diff --git a/ghostwriter/modules/linting_utils.py b/ghostwriter/modules/linting_utils.py index 21231ad9f..f226584f8 100644 --- a/ghostwriter/modules/linting_utils.py +++ b/ghostwriter/modules/linting_utils.py @@ -2,29 +2,33 @@ # Example JSON reporting data for loading into templates for rendering tests LINTER_CONTEXT = { - "report_date": "March 25, 2021", + "report_date": "Mar. 25, 2021", "project": { "id": 1, "name": "2021-03-01 Kabletown, Inc. Red Team (KABLE-01)", "type": "Red Team", - "start_date": "June 25, 2021", + "start_date": "Mar. 1, 2021", "start_month": "March", "start_day": 1, "start_year": 2021, - "end_date": "June 25, 2021", + "end_date": "Jun. 25, 2021", "end_month": "June", "end_day": 25, "end_year": 2021, "codename": "KABLE-01", + "timezone": "America/Los_Angeles", "note": "
This is an assessment for Kabletown but targets NBC assets. The goal is to answer specific questions prior to Kabletown absorbing NBC.
", "slack_channel": "#ghostwriter", "complete": False, + "start_time": "09:00:00", + "end_time": "17:00:00", }, "client": { "id": 1, "contacts": [ { "name": "Hank Hooper", + "timezone": "America/Los_Angeles", "job_title": "CEO", "email": "dad@kabletown.family", "phone": "(212) 664-4444", @@ -32,6 +36,7 @@ }, { "name": "John Francis Donaghy", + "timezone": "America/Los_Angeles", "job_title": "Vice President of East Coast Television", "email": "jack@nbc.com", "phone": "(212) 664-4444", @@ -48,16 +53,18 @@ "role": "Assessment Lead", "name": "Benny the Ghost", "email": "benny@ghostwriter.wiki", - "start_date": "March 1, 2021", - "end_date": "June 25, 2021", + "start_date": "Mar. 1, 2021", + "end_date": "Jun. 25, 2021", + "timezone": "America/Los_Angeles", "note": "Benny will lead the assessment for the full duration.
", }, { "role": "Assessment Oversight", "name": "Christopher Maddalena", "email": "cmaddalena@specterops.io", - "start_date": "March 1, 2021", - "end_date": "June 25, 2021", + "start_date": "Mar. 1, 2021", + "end_date": "Jun. 25, 2021", + "timezone": "America/Los_Angeles", "note": "Christopher will provide oversight and assistance (as needed).
", }, ], @@ -65,18 +72,18 @@ { "priority": "Primary", "status": "Active", - "deadline": "June 25, 2021", + "deadline": "Jun. 25, 2021", "percent_complete": 50.0, "tasks": [ { - "deadline": "June 25, 2021", + "deadline": "Jun. 25, 2021", "marked_complete": "", "task": "Extract information about Kenneth Parcell", "complete": False, }, { - "deadline": "June 4, 2021", - "marked_complete": "March 22, 2021", + "deadline": "Jun. 4, 2021", + "marked_complete": "Mar. 22, 2021", "task": "Locate information about Kenneth Parcell to begin the search (Page Program subnet)", "complete": True, }, @@ -91,11 +98,11 @@ { "priority": "Secondary", "status": "Active", - "deadline": "June 25, 2021", + "deadline": "Jun. 25, 2021", "percent_complete": 0.0, "tasks": [ { - "deadline": "March 16, 2021", + "deadline": "Mar. 16, 2021", "marked_complete": "", "task": "Locate systems and data repositories used by HR and contract teams", "complete": False, @@ -111,11 +118,11 @@ { "priority": "Primary", "status": "Active", - "deadline": "April 23, 2021", + "deadline": "Apr. 23, 2021", "percent_complete": 0.0, "tasks": [ { - "deadline": "March 24, 2021", + "deadline": "Mar. 24, 2021", "marked_complete": "", "task": "Run BloodHound!", "complete": False, @@ -172,8 +179,8 @@ { "activity": "Phishing", "domain": "getghostwriter.io", - "start_date": "March 1, 2021", - "end_date": "June 25, 2021", + "start_date": "Mar. 1, 2021", + "end_date": "Jun. 25, 2021", "dns": [ { "static_server": "172.67.132.12", @@ -187,8 +194,8 @@ { "activity": "Command and Control", "domain": "ghostwriter.wiki", - "start_date": "March 1, 2021", - "end_date": "June 25, 2021", + "start_date": "Mar. 1, 2021", + "end_date": "Jun. 25, 2021", "dns": [ { "static_server": "104.236.176.100", @@ -202,8 +209,8 @@ { "activity": "Command and Control", "domain": "specterops.io", - "start_date": "March 1, 2021", - "end_date": "June 25, 2021", + "start_date": "Mar. 1, 2021", + "end_date": "Jun. 25, 2021", "dns": [ { "static_server": "", @@ -222,8 +229,8 @@ "provider": "Digital Ocean", "activity": "Command and Control", "role": "Team Server / C2 Server", - "start_date": "March 1, 2021", - "end_date": "June 25, 2021", + "start_date": "Mar. 1, 2021", + "end_date": "Jun. 25, 2021", "dns": [ {"domain": "ghostwriter.wiki", "endpoint": "", "subdomain": "www"} ], @@ -235,8 +242,8 @@ "provider": "Microsoft Azure", "activity": "Command and Control", "role": "Team Server / C2 Server", - "start_date": "March 1, 2021", - "end_date": "June 25, 2021", + "start_date": "Mar. 1, 2021", + "end_date": "Jun. 25, 2021", "dns": [ { "domain": "getghostwriter.io", diff --git a/ghostwriter/modules/reportwriter.py b/ghostwriter/modules/reportwriter.py index 5832fa486..a5b727de3 100644 --- a/ghostwriter/modules/reportwriter.py +++ b/ghostwriter/modules/reportwriter.py @@ -11,6 +11,7 @@ import os import random import re +from datetime import datetime, timedelta # Django Imports from django.conf import settings @@ -121,6 +122,58 @@ def compromised(targets): return filtered_targets +def add_days(date, format_str, days): + """ + Add a number of business days to a date. + + **Parameters** + + ``date`` + Date string to add business days to + ``format_str`` + The format of the provided date + ``days`` + Number of business days to add to the date + """ + # Loop until all days added + date = datetime.strptime(date, format_str) + if days > 0: + while days > 0: + # Add one day to the date + date += timedelta(days=1) + # Check if the day is a business day + weekday = date.weekday() + if weekday >= 5: + # Return to the top (Sunday is 6) + continue + # Decrement the number of days to add + days -= 1 + else: + # Same as above but in reverse for negative days + while days < 0: + date -= timedelta(days=1) + weekday = date.weekday() + if weekday >= 5: + continue + days += 1 + return date.strftime(format_str) + + +def format_datetime(date, current_format, new_format): + """ + Change the format of a given date string. + + **Parameters** + + ``date`` + Date string to modify + ``format_str`` + The format of the provided date + """ + current = datetime.strptime(date, current_format) + return current.strftime(new_format) + + def prepare_jinja2_env(debug=False): """Prepare a Jinja2 environment with all custom filters.""" if debug: @@ -133,6 +186,8 @@ def prepare_jinja2_env(debug=False): env.filters["filter_type"] = filter_type env.filters["strip_html"] = strip_html env.filters["compromised"] = compromised + env.filters["add_days"] = add_days + env.filters["format_datetime"] = format_datetime return env diff --git a/ghostwriter/oplog/forms.py b/ghostwriter/oplog/forms.py index 4fd39c5c6..70f5f24a8 100644 --- a/ghostwriter/oplog/forms.py +++ b/ghostwriter/oplog/forms.py @@ -27,7 +27,7 @@ def __init__(self, project=None, *args, **kwargs): super().__init__(*args, **kwargs) self.project_instance = project # Limit the list to just projects not marked as complete - active_projects = Project.objects.filter(complete=False) + active_projects = Project.objects.filter(complete=False).order_by("-start_date") if active_projects: self.fields["project"].empty_label = "-- Select an Active Project --" else: diff --git a/ghostwriter/reporting/forms.py b/ghostwriter/reporting/forms.py index 34fa2e4c5..7f41c23d7 100644 --- a/ghostwriter/reporting/forms.py +++ b/ghostwriter/reporting/forms.py @@ -139,7 +139,7 @@ def __init__(self, project=None, *args, **kwargs): self.project_instance = project # Limit the list to just projects not marked as complete active_projects = Project.objects.filter(complete=False).order_by( - "start_date", "client", "project_type" + "-start_date", "client", "project_type" ) if active_projects: self.fields["project"].empty_label = "-- Select an Active Project --" diff --git a/ghostwriter/shepherd/tasks.py b/ghostwriter/shepherd/tasks.py index 705827a10..fe540e21c 100644 --- a/ghostwriter/shepherd/tasks.py +++ b/ghostwriter/shepherd/tasks.py @@ -38,7 +38,6 @@ from .models import ( Domain, - DomainHistory, DomainNote, DomainStatus, HealthStatus, @@ -678,7 +677,7 @@ def check_domains(domain=None): ) # Check if the domain is checked-out and send a message to that project channel - latest_checkout = DomainHistory.objects.filter(domain=domain).latest( + latest_checkout = History.objects.filter(domain=domain).latest( "end_date" ) if ( diff --git a/ghostwriter/shepherd/templates/shepherd/domain_list.html b/ghostwriter/shepherd/templates/shepherd/domain_list.html index e0459bd34..ce7624684 100644 --- a/ghostwriter/shepherd/templates/shepherd/domain_list.html +++ b/ghostwriter/shepherd/templates/shepherd/domain_list.html @@ -109,6 +109,9 @@ cssAsc: 'down', cssDesc: 'up', cssNone: 'none', + headers: { + 5: {sorter: 'digit'} + } } ); $('.tablesorter').trigger('update');