From 49b04b39f5dbeb0e51503a9a6419f88064ba427d Mon Sep 17 00:00:00 2001 From: Alexander Parrill Date: Tue, 12 Dec 2023 10:54:30 -0500 Subject: [PATCH 1/3] Add "Identifier" to oplog entry The intended use is for the Mythic integration to identify log entries that it has made, though other integrations or workflows may be able to make use of it. It is by default hidden in the oplog entry list. --- ghostwriter/oplog/forms.py | 10 +++- .../migrations/0012_auto_20231211_2154.py | 22 +++++++ ghostwriter/oplog/models.py | 10 ++++ ghostwriter/oplog/tests/test_views.py | 2 + ghostwriter/static/js/oplog.js | 57 ++++++++----------- 5 files changed, 65 insertions(+), 36 deletions(-) create mode 100644 ghostwriter/oplog/migrations/0012_auto_20231211_2154.py diff --git a/ghostwriter/oplog/forms.py b/ghostwriter/oplog/forms.py index d945e1664..21ced2994 100644 --- a/ghostwriter/oplog/forms.py +++ b/ghostwriter/oplog/forms.py @@ -134,9 +134,13 @@ def __init__(self, *args, **kwargs): self.helper.layout = Layout( Row( - Column(Field("start_date", step=1), css_class="form-group col-4 mb-0"), - Column(Field("end_date", step=1), css_class="form-group col-4 mb-0"), - Column("operator_name", css_class="form-group col-4 mb-0"), + Column(Field("start_date", step=1), css_class="form-group col-6 mb-0"), + Column(Field("end_date", step=1), css_class="form-group col-6 mb-0"), + css_class="form-row", + ), + Row( + Column("entry_identifier", css_class="form-group col-6 mb-0"), + Column("operator_name", css_class="form-group col-6 mb-0"), css_class="form-row", ), Row( diff --git a/ghostwriter/oplog/migrations/0012_auto_20231211_2154.py b/ghostwriter/oplog/migrations/0012_auto_20231211_2154.py new file mode 100644 index 000000000..59fb5a2e6 --- /dev/null +++ b/ghostwriter/oplog/migrations/0012_auto_20231211_2154.py @@ -0,0 +1,22 @@ +# Generated by Django 3.2.19 on 2023-12-11 21:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('oplog', '0011_auto_20230323_2248'), + ] + + operations = [ + migrations.AddField( + model_name='oplogentry', + name='entry_identifier', + field=models.CharField(blank=True, help_text='Integrations may use this to track log entries.', max_length=65535, null=True, verbose_name='Identifier'), + ), + migrations.AddIndex( + model_name='oplogentry', + index=models.Index(fields=['oplog_id', 'entry_identifier'], name='oplog_oplog_oplog_i_0e03f5_idx'), + ), + ] diff --git a/ghostwriter/oplog/models.py b/ghostwriter/oplog/models.py index d33f77880..93b92c91f 100644 --- a/ghostwriter/oplog/models.py +++ b/ghostwriter/oplog/models.py @@ -44,6 +44,13 @@ def __str__(self): class OplogEntry(models.Model): """Stores an individual log entry, related to :model:`oplog.Oplog`.""" + entry_identifier = models.CharField( + "Identifier", + null=True, + blank=True, + help_text="Integrations may use this to track log entries.", + max_length=65535, + ) start_date = models.DateTimeField( "Start Date", null=True, @@ -135,6 +142,9 @@ class Meta: ordering = ["-start_date", "-end_date", "oplog_id"] verbose_name = "Activity log entry" verbose_name_plural = "Activity log entries" + indexes = [ + models.Index(fields=["oplog_id", "entry_identifier"]), + ] def clean(self, *args, **kwargs): if isinstance(self.start_date, str): diff --git a/ghostwriter/oplog/tests/test_views.py b/ghostwriter/oplog/tests/test_views.py index f7baa5edd..fab05b980 100644 --- a/ghostwriter/oplog/tests/test_views.py +++ b/ghostwriter/oplog/tests/test_views.py @@ -157,6 +157,7 @@ def test_view_uses_correct_template(self): def test_post_data_and_permissions(self): filename = "oplog_import_test.csv" fieldnames = [ + "entry_identifier", "start_date", "end_date", "source_ip", @@ -207,6 +208,7 @@ def test_oplog_id_override(self): """Test that the ``oplog_id`` field is overridden when importing.""" filename = "oplog_import_test.csv" fieldnames = [ + "entry_identifier", "oplog_id", "start_date", "end_date", diff --git a/ghostwriter/static/js/oplog.js b/ghostwriter/static/js/oplog.js index e5bf9ad50..eb58040b3 100644 --- a/ghostwriter/static/js/oplog.js +++ b/ghostwriter/static/js/oplog.js @@ -6,8 +6,10 @@ let hiddenLogTblColumns = JSON.parse((localStorage.getItem('hiddenLogTblColumns' // Assemble the array of column information for the table let columnInfo = [] columnInfo = [ - ['startDateCheckBox', 'startDateColumn', 'Start Date', 'start_date'], - ['endDateCheckbox', 'endDateColumn', 'End Date', 'end_date'], + // [checkBoxID, columnClass, Pretty Name, name_in_json, toHtmlFunc (default `jsescape`), shownByDefault (default true)] + ['identifierCheckBox', 'identifierColumn', 'Identifier', 'entry_identifier', undefined, false], + ['startDateCheckBox', 'startDateColumn', 'Start Date', 'start_date', entry => jsEscape(entry).replace(/\.\d+/, "").replace("Z", "").replace("T", " ")], + ['endDateCheckbox', 'endDateColumn', 'End Date', 'end_date', entry => jsEscape(entry).replace(/\.\d+/, "").replace("Z", "").replace("T", " ")], ['sourceIPCheckbox', 'sourceIPColumn', 'Source', 'source_ip'], ['destIPCheckbox', 'destIPColumn', 'Destination', 'dest_ip'], ['toolNameCheckbox', 'toolNameColumn', 'Tool Name', 'tool'], @@ -17,25 +19,17 @@ columnInfo = [ ['outputCheckbox', 'outputColumn', 'Output', 'output'], ['commentsCheckbox', 'commentsColumn', 'Comments', 'comments'], ['operatorCheckbox', 'operatorColumn', 'Operator', 'operator_name'], - ['tagsCheckbox', 'tagsColumn', 'Tags', 'tags'], + ['tagsCheckbox', 'tagsColumn', 'Tags', 'tags', entry => stylizeTags(jsEscape(entry))], ['optionsCheckbox', 'optionsColumn', 'Options', ''], ] // Generate a table row based on a log entry function generateTableHeaders() { - return `${columnInfo[0][2]} - ${columnInfo[1][2]} - ${columnInfo[2][2]} - ${columnInfo[3][2]} - ${columnInfo[4][2]} - ${columnInfo[5][2]} - ${columnInfo[6][2]} - ${columnInfo[7][2]} - ${columnInfo[8][2]} - ${columnInfo[9][2]} - ${columnInfo[10][2]} - ${columnInfo[11][2]} - ${columnInfo[12][2]}` + let out = ""; + columnInfo.forEach(column => { + out += `${column[2]}` + }); + return out; } // Convert a table row to JSON and copy it to the clipboard @@ -84,25 +78,21 @@ function convertRowToJSON(row_id) { // Generate a table row based on a log entry function generateRow(entry) { - return ` - ${jsEscape(entry["start_date"]).replace(/\.\d+/, "").replace("Z", "").replace("T", " ")} - ${jsEscape(entry["end_date"]).replace(/\.\d+/, "").replace("Z", "").replace("T", " ")} - ${jsEscape(entry["source_ip"])} - ${jsEscape(entry["dest_ip"])} - ${jsEscape(entry["tool"])} - ${jsEscape(entry["user_context"])} -
${jsEscape(entry["command"])}
-
${jsEscape(entry["description"])}
-
${jsEscape(entry["output"])}
-
${jsEscape(entry["comments"])}
- ${jsEscape(entry["operator_name"])} - ${stylizeTags(jsEscape(entry["tags"]))} - + let out = ``; + columnInfo.forEach(column => { + if(column[0] == "optionsCheckbox") { + out += ` - - ` + ` + } else { + let value = entry[column[3]]; + let filter = column[4] ?? jsEscape; + out += `${filter(value)}`; + } + }); + return out + ""; } // Add a placeholder row that spans the entire table @@ -156,10 +146,11 @@ function coupleCheckboxColumn(checkboxId, columnClass) { // Build the column show/hide checkboxes function buildColumnsCheckboxes() { columnInfo.forEach(function (value, _, _) { + let checked = (value[5] === undefined || value[5]) ? "checked" : ""; let checkboxEntry = `
- +
From 38e7933d4a24639dfda252f7fb22935aefeba11c Mon Sep 17 00:00:00 2001 From: Christopher Maddalena Date: Wed, 13 Dec 2023 10:33:02 -0800 Subject: [PATCH 2/3] Added permissions to insert and update `entry_identifier` via GraphQL --- .../databases/default/tables/public_oplog_oplogentry.yaml | 6 ++++-- .../default/tables/public_reporting_reportfindinglink.yaml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/hasura-docker/metadata/databases/default/tables/public_oplog_oplogentry.yaml b/hasura-docker/metadata/databases/default/tables/public_oplog_oplogentry.yaml index 693025095..07b5fd0e7 100644 --- a/hasura-docker/metadata/databases/default/tables/public_oplog_oplogentry.yaml +++ b/hasura-docker/metadata/databases/default/tables/public_oplog_oplogentry.yaml @@ -70,13 +70,14 @@ insert_permissions: - description - dest_ip - end_date + - entry_identifier + - operator_name - oplog_id_id - output - source_ip - start_date - tool - user_context - - operator_name select_permissions: - role: manager permission: @@ -138,13 +139,14 @@ update_permissions: - description - dest_ip - end_date + - entry_identifier + - operator_name - oplog_id_id - output - source_ip - start_date - tool - user_context - - operator_name filter: log: project: diff --git a/hasura-docker/metadata/databases/default/tables/public_reporting_reportfindinglink.yaml b/hasura-docker/metadata/databases/default/tables/public_reporting_reportfindinglink.yaml index 993e65241..b1f6051db 100644 --- a/hasura-docker/metadata/databases/default/tables/public_reporting_reportfindinglink.yaml +++ b/hasura-docker/metadata/databases/default/tables/public_reporting_reportfindinglink.yaml @@ -297,9 +297,9 @@ event_triggers: value_from_env: HASURA_ACTION_SECRET - name: DeleteReportFinding definition: - enable_manual: false delete: columns: '*' + enable_manual: false retry_conf: interval_sec: 10 num_retries: 0 From 97faee63149fed17d5159bc3e7b3cf44826f5aa5 Mon Sep 17 00:00:00 2001 From: Christopher Maddalena Date: Thu, 14 Dec 2023 11:40:22 -0800 Subject: [PATCH 3/3] Fixed `manager` role permissions for the `entry_identifier` field --- .../default/tables/public_oplog_oplogentry.yaml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/hasura-docker/metadata/databases/default/tables/public_oplog_oplogentry.yaml b/hasura-docker/metadata/databases/default/tables/public_oplog_oplogentry.yaml index 07b5fd0e7..ace1b81cd 100644 --- a/hasura-docker/metadata/databases/default/tables/public_oplog_oplogentry.yaml +++ b/hasura-docker/metadata/databases/default/tables/public_oplog_oplogentry.yaml @@ -41,6 +41,7 @@ insert_permissions: - description - dest_ip - end_date + - entry_identifier - operator_name - oplog_id_id - output @@ -82,19 +83,20 @@ select_permissions: - role: manager permission: columns: - - id - - oplog_id_id - - operator_name - command - comments - description - dest_ip + - end_date + - entry_identifier + - id + - operator_name + - oplog_id_id - output - source_ip + - start_date - tool - user_context - - end_date - - start_date filter: {} - role: user permission: @@ -122,6 +124,7 @@ update_permissions: - description - dest_ip - end_date + - entry_identifier - operator_name - oplog_id_id - output