Skip to content

Commit

Permalink
Merge pull request #257 from GhostManager/release/v3.1.0
Browse files Browse the repository at this point in the history
Release/v3.1.0
  • Loading branch information
chrismaddalena authored Oct 15, 2022
2 parents 5011542 + e94be75 commit c056955
Show file tree
Hide file tree
Showing 105 changed files with 2,755 additions and 598 deletions.
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
"commandcenter",
"csrftoken",
"dateutil",
"deconfliction",
"deconflictions",
"Diffie",
"DMARC",
"domainserverconnection",
Expand Down Expand Up @@ -91,6 +93,8 @@
"specterops",
"spreadsheetml",
"staticfiles",
"subdocument",
"subdocuments",
"tablesorter",
"tablib",
"transientserver",
Expand All @@ -99,6 +103,8 @@
"Uvicorn",
"viewsets",
"virustotal",
"whitecard",
"whitecards",
"whois",
"wordprocessingml",
"xforce"
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.1.0] - 14 October 2022

### Fixed

* Fixed a bug that could cause content or styling to be lost inside nested text formatting

### Added

* New deconfliction event tracking feature now available under the "Deconflictions" tab on project dashboards
* New whitecard tracking feature now available under the "White Cards" tab on project dashboards

### Changed

* Findings added to a report via a blank template (i.e., not added from the library) will now appear with a flag icon for easy identification
* All fields that use the WYSIWYG editor now have a `RichText` counterpart available in report templates (Closes [#241](https://github.com/GhostManager/Ghostwriter/issues/241))
* Improved sample "tutorial" template to cover more advanced usage of filters, variables, and more

## [3.0.7] - 10 October 2022

### Fixed
Expand Down
Binary file modified DOCS/sample_reports/template.docx
Binary file not shown.
4 changes: 2 additions & 2 deletions VERSION
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
v3.0.7
10 October 2022
v3.1.0
14 October 2022
4 changes: 2 additions & 2 deletions config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
# 3rd Party Libraries
import environ

__version__ = "3.0.7"
__version__ = "3.1.0"
VERSION = __version__
RELEASE_DATE = "10 October 2022"
RELEASE_DATE = "14 October 2022"

ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent.parent
APPS_DIR = ROOT_DIR / "ghostwriter"
Expand Down
Binary file modified ghostwriter-cli-linux
Binary file not shown.
Binary file modified ghostwriter-cli-macos
Binary file not shown.
Binary file modified ghostwriter-cli.exe
Binary file not shown.
1 change: 0 additions & 1 deletion ghostwriter/api/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ def form_data(

def test_valid_data(self):
form = self.form_data(name="Test Entry", expiry_date=datetime.now() + timedelta(days=1))
print(form.errors)
self.assertTrue(form.is_valid())

def test_empty_name(self):
Expand Down
53 changes: 52 additions & 1 deletion ghostwriter/factories.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Standard Libraries
import random
from datetime import date, timedelta
from datetime import date, timedelta, timezone

# Django Imports
from django.contrib.auth import get_user_model
Expand Down Expand Up @@ -679,6 +679,38 @@ class Meta:
sleep_time = 20


class DeconflictionStatusFactory(factory.django.DjangoModelFactory):
class Meta:
model = "rolodex.DeconflictionStatus"

status = factory.Sequence(lambda n: "Status %s" % n)
weight = factory.Sequence(lambda n: n)


class DeconflictionFactory(factory.django.DjangoModelFactory):
class Meta:
model = "rolodex.Deconfliction"

report_timestamp = Faker("date_time", tzinfo=pytz.UTC)
alert_timestamp = Faker("date_time", tzinfo=pytz.UTC)
response_timestamp = Faker("date_time", tzinfo=pytz.UTC)
title = Faker("sentence")
description = Faker("paragraph")
alert_source = Faker("word")
status = factory.SubFactory(DeconflictionStatusFactory)
project = factory.SubFactory(ProjectFactory)


class WhiteCardFactory(factory.django.DjangoModelFactory):
class Meta:
model = "rolodex.WhiteCard"

issued = Faker("date_time", tzinfo=pytz.UTC)
title = Faker("user_name")
description = Faker("paragraph")
project = factory.SubFactory(ProjectFactory)


def GenerateMockProject(
num_of_contacts=3,
num_of_assignments=3,
Expand All @@ -689,6 +721,8 @@ def GenerateMockProject(
num_of_subtasks=5,
num_of_domains=5,
num_of_servers=5,
num_of_deconflictions=3,
num_of_whitecards=3,
):
# Generate a random client and project
client = ClientFactory(name="SpecterOps, Inc.")
Expand Down Expand Up @@ -759,6 +793,23 @@ def GenerateMockProject(
servers = ServerHistoryFactory.create_batch(num_of_servers, project=project)
cloud = TransientServerFactory.create_batch(num_of_servers, project=project)

# Generate deconflictions
deconfliction_status = []
deconfliction_status.append(DeconflictionStatusFactory(status="Undetermined", weight=0))
deconfliction_status.append(DeconflictionStatusFactory(status="Confirmed", weight=1))
deconfliction_status.append(DeconflictionStatusFactory(status="Unrelated", weight=2))
DeconflictionFactory.create_batch(
num_of_deconflictions,
project=project,
status=random.choice(deconfliction_status),
)

# Generate white cards
WhiteCardFactory.create_batch(
num_of_whitecards,
project=project,
)

for index, domain in enumerate(domains):
if index % 2 == 0:
DomainServerConnectionFactory(
Expand Down
46 changes: 46 additions & 0 deletions ghostwriter/modules/custom_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@
from ghostwriter.rolodex.models import (
Client,
ClientContact,
Deconfliction,
Project,
ProjectAssignment,
ProjectNote,
ProjectObjective,
ProjectScope,
ProjectSubTask,
ProjectTarget,
WhiteCard,
)
from ghostwriter.shepherd.models import (
AuxServerAddress,
Expand Down Expand Up @@ -640,6 +642,24 @@ class Meta:
depth = 1


class DeconflictionSerializer(CustomModelSerializer):
"""Serialize :model:`rolodex:Deconfliction` entries."""

status = StringRelatedField()

class Meta:
model = Deconfliction
fields = "__all__"


class WhiteCardSerializer(CustomModelSerializer):
"""Serialize :model:`rolodex:WhiteCard` entries."""

class Meta:
model = WhiteCard
fields = "__all__"


class ReportDataSerializer(CustomModelSerializer):
"""Serialize :model:`rolodex:Project` and all related entries."""

Expand All @@ -663,6 +683,12 @@ class ReportDataSerializer(CustomModelSerializer):
scope = ProjectScopeSerializer(
source="project.projectscope_set", many=True, exclude=["id", "project"]
)
deconflictions = DeconflictionSerializer(
source="project.deconfliction_set", many=True, exclude=["id", "project"]
)
whitecards = WhiteCardSerializer(
source="project.whitecard_set", many=True, exclude=["id", "project"]
)
infrastructure = ProjectInfrastructureSerializer(source="project")
findings = FindingLinkSerializer(
source="reportfindinglink_set",
Expand Down Expand Up @@ -729,15 +755,35 @@ def to_representation(self, instance):
total_scope_lines += scope["total"]

finding_order = 0
critical_findings = 0
high_findings = 0
medium_findings = 0
low_findings = 0
info_findings = 0
for finding in rep["findings"]:
finding["ordering"] = finding_order
if finding["severity"].lower() == "critical":
critical_findings += 1
elif finding["severity"].lower() == "high":
high_findings += 1
elif finding["severity"].lower() == "medium":
medium_findings += 1
elif finding["severity"].lower() == "low":
low_findings += 1
elif finding["severity"].lower() == "informational":
info_findings += 1
finding_order += 1

# Add a ``totals`` key to track the values
rep["totals"] = {}
rep["totals"]["objectives"] = total_objectives
rep["totals"]["objectives_completed"] = completed_objectives
rep["totals"]["findings"] = total_findings
rep["totals"]["findings_critical"] = critical_findings
rep["totals"]["findings_high"] = high_findings
rep["totals"]["findings_medium"] = medium_findings
rep["totals"]["findings_low"] = low_findings
rep["totals"]["findings_info"] = info_findings
rep["totals"]["scope"] = total_scope_lines
rep["totals"]["team"] = total_team
rep["totals"]["targets"] = total_targets
Expand Down
42 changes: 41 additions & 1 deletion ghostwriter/modules/linting_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"codename": "KABLE-01",
"timezone": "America/Los_Angeles",
"note": "<p>This is an assessment for Kabletown but targets NBC assets. The goal is to answer specific questions prior to Kabletown absorbing NBC.</p>",
"note_rt": "",
"slack_channel": "#ghostwriter",
"complete": False,
"start_time": "09:00:00",
Expand All @@ -33,6 +34,7 @@
"email": "[email protected]",
"phone": "(212) 664-4444",
"note": '<p>A self-described "family man," Vietnam veteran, and head of Kabletown. He always seems happy on the surface (laughing incessantly), while directing thinly-veiled insults and threats to subordinates. Handle with care.</p>',
"note_rt": "",
},
{
"name": "John Francis Donaghy",
Expand All @@ -41,12 +43,16 @@
"email": "[email protected]",
"phone": "(212) 664-4444",
"note": '<p>Prefers to go by "Jack."</p>',
"note_rt": "",
},
],
"name": "Kabletown, Inc.",
"short_name": "KTOWN",
"codename": "Totally Not Comcast",
"note": "<p>Philadelphia-based cable company Kabletown, a fictionalized depiction of the acquisition of NBC Universal by Comcast.</p>",
"note_rt": "",
"address": "30 Rockefeller Plaza New York City, New York 10112",
"address_rt": "",
},
"team": [
{
Expand All @@ -58,6 +64,7 @@
"timezone": "America/Los_Angeles",
"phone": "(212) 664-4444",
"note": "<p>Benny will lead the assessment for the full duration.</p>",
"note_rt": "",
},
{
"role": "Assessment Oversight",
Expand All @@ -68,6 +75,7 @@
"timezone": "America/Los_Angeles",
"phone": "(212) 664-4444",
"note": "<p>Christopher will provide oversight and assistance (as needed).</p>",
"note_rt": "",
},
],
"objectives": [
Expand Down Expand Up @@ -176,6 +184,27 @@
"requires_caution": True,
},
],
"deconflictions": [
{
"status": "Unrelated",
"created_at": "2022-10-06T19:41:20.889055Z",
"report_timestamp": "2022-10-06T19:41:20.889055Z",
"alert_timestamp": "2022-10-06T19:41:20.889055Z",
"response_timestamp": "2022-10-06T19:41:20.889055Z",
"title": "A Brief Descriptive Title",
"description": "<p>This would be a description of the alert, response, and any related assessment activity.</p>",
"description_rt": "",
"alert_source": "EDR",
},
],
"whitecards": [
{
"issued": "2022-10-13T19:18:26Z",
"title": "Test Card",
"description": "Test description",
"description_rt": "",
}
],
"infrastructure": {
"domains": [
{
Expand All @@ -192,6 +221,7 @@
}
],
"note": "<p>Domain for the first phishing campaign</p>",
"note_rt": "",
},
{
"activity": "Command and Control",
Expand All @@ -207,6 +237,7 @@
}
],
"note": "<p>Domain for long-haul C2 comms</p>",
"note_rt": "",
},
{
"activity": "Command and Control",
Expand All @@ -222,6 +253,7 @@
}
],
"note": "<p>Domain for the short-haul C2 comms (phishing)</p>",
"note_rt": "",
},
],
"servers": [
Expand All @@ -237,6 +269,7 @@
{"domain": "ghostwriter.wiki", "endpoint": "", "subdomain": "www"}
],
"note": "<p>Long-haul C2 server</p>",
"note_rt": "",
},
{
"name": "CC-02",
Expand All @@ -254,6 +287,7 @@
}
],
"note": "<p>Short-haul C2 server for phishing</p>",
"note_rt": "",
},
],
"cloud": [
Expand All @@ -265,6 +299,7 @@
"ip_address": "30.49.38.30",
"name": "SMTP01",
"note": "<p>SMTP server for phishing emails; running Gophish</p>",
"note_rt": "",
}
],
},
Expand Down Expand Up @@ -339,7 +374,12 @@
"totals": {
"objectives": 3,
"objectives_completed": 0,
"findings": 7,
"findings": 1,
"findings_critical": 1,
"findings_high": 0,
"findings_medium": 0,
"findings_low": 0,
"findings_info": 0,
"scope": 6,
"team": 2,
"targets": 1,
Expand Down
Loading

0 comments on commit c056955

Please sign in to comment.