From 3a31b389e2f51d695233e293d2b078822984db3f Mon Sep 17 00:00:00 2001 From: Zachary Christensen Date: Tue, 6 Jun 2023 11:28:49 -0600 Subject: [PATCH] Initial creation Co-Authored-By: OutpostSecurity <72515718+OutpostSecurity@users.noreply.github.com> Co-Authored-By: Haylee Mills <12771156+7thdrxn@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/01-bug-report.yml | 53 ++ .github/ISSUE_TEMPLATE/02-feature-request.yml | 25 + .github/workflows/appinspect.yml | 17 + .github/workflows/release.yml | 12 + .gitignore | 8 + LICENSE | 42 +- README.md | 19 + src/threat_object_fun/README.txt | 4 + src/threat_object_fun/app.manifest | 57 ++ src/threat_object_fun/default/app.conf | 24 + .../default/data/ui/nav/default.xml | 8 + .../panels/content_threat_object_fields.xml | 46 ++ .../ui/views/risk_investigation_dashboard.xml | 560 ++++++++++++++++++ .../data/ui/views/threat_object__hunting.xml | 448 ++++++++++++++ .../ui/views/threat_object_content_dev.xml | 414 +++++++++++++ .../data/ui/views/threat_object_detail.xml | 77 +++ .../data/ui/views/threat_object_overview.xml | 119 ++++ .../ui/views/threat_object_overview_test.xml | 90 +++ .../ui/views/threat_object_prevalence.xml | 450 ++++++++++++++ .../data/ui/views/threat_object_soar.xml | 57 ++ src/threat_object_fun/default/macros.conf | 15 + .../default/workflow_actions.conf | 8 + src/threat_object_fun/metadata/default.meta | 35 ++ src/threat_object_fun/static/abuse.png | Bin 0 -> 2502 bytes .../static/adversarytactics.png | Bin 0 -> 2174 bytes src/threat_object_fun/static/appIcon.png | Bin 0 -> 2540 bytes src/threat_object_fun/static/appIcon300.png | Bin 0 -> 95 bytes src/threat_object_fun/static/appIcon67.png | Bin 0 -> 95 bytes src/threat_object_fun/static/appIconAlt.png | Bin 0 -> 1026 bytes .../static/appIconAlt_2x.png | Bin 0 -> 2231 bytes src/threat_object_fun/static/appIcon_2x.png | Bin 0 -> 7055 bytes .../static/bestpractices.png | Bin 0 -> 2218 bytes .../static/cloudsecurity.png | Bin 0 -> 2397 bytes src/threat_object_fun/static/compliance.png | Bin 0 -> 1841 bytes .../static/insiderthreats.png | Bin 0 -> 2396 bytes src/threat_object_fun/static/malware.png | Bin 0 -> 1984 bytes .../static/securitymonitoring.png | Bin 0 -> 2171 bytes src/threat_object_fun/static/unknown.png | Bin 0 -> 1892 bytes .../static/vulnerability.png | Bin 0 -> 2105 bytes 39 files changed, 2567 insertions(+), 21 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/01-bug-report.yml create mode 100644 .github/ISSUE_TEMPLATE/02-feature-request.yml create mode 100644 .github/workflows/appinspect.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 README.md create mode 100644 src/threat_object_fun/README.txt create mode 100644 src/threat_object_fun/app.manifest create mode 100644 src/threat_object_fun/default/app.conf create mode 100644 src/threat_object_fun/default/data/ui/nav/default.xml create mode 100644 src/threat_object_fun/default/data/ui/panels/content_threat_object_fields.xml create mode 100644 src/threat_object_fun/default/data/ui/views/risk_investigation_dashboard.xml create mode 100644 src/threat_object_fun/default/data/ui/views/threat_object__hunting.xml create mode 100644 src/threat_object_fun/default/data/ui/views/threat_object_content_dev.xml create mode 100644 src/threat_object_fun/default/data/ui/views/threat_object_detail.xml create mode 100644 src/threat_object_fun/default/data/ui/views/threat_object_overview.xml create mode 100644 src/threat_object_fun/default/data/ui/views/threat_object_overview_test.xml create mode 100644 src/threat_object_fun/default/data/ui/views/threat_object_prevalence.xml create mode 100644 src/threat_object_fun/default/data/ui/views/threat_object_soar.xml create mode 100644 src/threat_object_fun/default/macros.conf create mode 100644 src/threat_object_fun/default/workflow_actions.conf create mode 100644 src/threat_object_fun/metadata/default.meta create mode 100644 src/threat_object_fun/static/abuse.png create mode 100644 src/threat_object_fun/static/adversarytactics.png create mode 100644 src/threat_object_fun/static/appIcon.png create mode 100644 src/threat_object_fun/static/appIcon300.png create mode 100644 src/threat_object_fun/static/appIcon67.png create mode 100644 src/threat_object_fun/static/appIconAlt.png create mode 100644 src/threat_object_fun/static/appIconAlt_2x.png create mode 100644 src/threat_object_fun/static/appIcon_2x.png create mode 100644 src/threat_object_fun/static/bestpractices.png create mode 100644 src/threat_object_fun/static/cloudsecurity.png create mode 100644 src/threat_object_fun/static/compliance.png create mode 100644 src/threat_object_fun/static/insiderthreats.png create mode 100644 src/threat_object_fun/static/malware.png create mode 100644 src/threat_object_fun/static/securitymonitoring.png create mode 100644 src/threat_object_fun/static/unknown.png create mode 100644 src/threat_object_fun/static/vulnerability.png diff --git a/.github/ISSUE_TEMPLATE/01-bug-report.yml b/.github/ISSUE_TEMPLATE/01-bug-report.yml new file mode 100644 index 0000000..cb24bbb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/01-bug-report.yml @@ -0,0 +1,53 @@ +name: Report a bug +description: Something is not working? Report a bug +labels: + - bug +body: + - type: textarea + id: description + attributes: + label: Bug description + description: >- + Please give a detailed description of the issue. Be as specific as + possible. If you have found a workaround or a fix for the problem, + please let us know. Include screenshots (if applicable). + validations: + required: true + + # - type: textarea + # id: related-links + # attributes: + # label: Related links + # description: >- + # Please list all links to the sections of + # [the documentation](#placeholder) that + # are relevant to the bug in order to show that you have consulted and + # thoroughly read it. Additionally, list links to possibly related open + # and closed [issues](https://github.com/rba-community/threat_object_fun/issues). + # value: |- + # - [Example Issue](https://github.com/rba-community/threat_object_fun/issues) + # - + # validations: + # required: true + + - type: input + id: ta-version + attributes: + label: threat_object_fun Version + description: >- + Which version of this app (threat_object_fun) are you using? + placeholder: |- + 1.0.0 + validations: + required: true + + - type: input + id: splunk-version + attributes: + label: Splunk Version + description: >- + Which version of Splunk are you using? + placeholder: |- + 9.0.1 + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/02-feature-request.yml b/.github/ISSUE_TEMPLATE/02-feature-request.yml new file mode 100644 index 0000000..d7e609b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/02-feature-request.yml @@ -0,0 +1,25 @@ +name: Feature Request +description: Want to submit an idea? Propose a change or feature request +labels: + - feature request +body: + - type: textarea + id: description + attributes: + label: Description + description: >- + Please provide a detailed description of your idea in 2-3 sentences so + we can fully understand what change, feature, or the + improvement you are proposing. + validations: + required: true + + - type: textarea + id: related-links + attributes: + label: Related links + description: >- + (optional) Please list all links to open and closed [issues](https://github.com/rba-community/threat_object_fun/issues) that are relevant to your idea. + value: |- + - [Feature Request](https://github.com/rba-community/threat_object_fun/issues/) + - diff --git a/.github/workflows/appinspect.yml b/.github/workflows/appinspect.yml new file mode 100644 index 0000000..bda8bd4 --- /dev/null +++ b/.github/workflows/appinspect.yml @@ -0,0 +1,17 @@ +name: Splunk Appinspect +on: + pull_request: + branches: + - main + - master + paths: + - "src/**" + types: [opened, ready_for_review] + workflow_dispatch: + +jobs: + call-packaging-workflow: + uses: ZachChristensen28/splunk-github-wfa/.github/workflows/appinspect.yml@main + secrets: + API_USER: ${{ secrets.API_USER }} + API_PASS: ${{ secrets.API_PASS }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..6391098 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,12 @@ +name: release +on: + push: + branches: + - master + - main + paths: + - 'src/**' + +jobs: + call-packaging-workflow: + uses: ZachChristensen28/splunk-github-wfa/.github/workflows/package-app.yml@main diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6065e65 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.DS_STORE +**/local +local.meta +__pycache__/ +.vscode +venv +.idea +Pipfile** diff --git a/LICENSE b/LICENSE index 57d821c..2c1e60e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2023 The RBA Community - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2023 Outpost Security, LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3636bcd --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +![GitHub](https://img.shields.io/github/license/rba-community/threat_object_fun) +![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/rba-community/threat_object_fun) +[![Splunkbase App](https://img.shields.io/badge/Splunkbase-threat__object__fun-blue)](https://splunkbase.splunk.com/app/6917) +[![Splunk ES Compatibility](https://img.shields.io/badge/Splunk%20ES%20Compatibility->=6.6.0-success)](https://splunkbase.splunk.com/app/263) +![Splunk Cloud Compatibility](https://img.shields.io/badge/Splunk%20Cloud%20Ready-Victoria%20|%20Classic-informational?logo=splunk) + +This app helps illustrate setting and leveraging threat objects with [Risk-Based Alerting (RBA)](https://www.splunk.com/en_us/form/the-essential-guide-to-risk-based-alerting.html). + +## About + +Info | Description +------|---------- +threat_object_fun | 1.0.0 - [Splunkbase](https://splunkbase.splunk.com/app/6917) \| [GitHub](https://github.com/rba-community/threat_object_fun/releases) +App has a web UI | Yes, this app contains dashboards. +Authors | Haylee Mills, Stuart McIntosh + +## Issues or Feature Requests + +Please open an issue or feature request on [Github](https://github.com/rba-community/threat_object_fun/issues). diff --git a/src/threat_object_fun/README.txt b/src/threat_object_fun/README.txt new file mode 100644 index 0000000..14bedc2 --- /dev/null +++ b/src/threat_object_fun/README.txt @@ -0,0 +1,4 @@ +threat_object_fun + +Copyright (C) 2023 Outpost Security, LLC. All rights reserved. + diff --git a/src/threat_object_fun/app.manifest b/src/threat_object_fun/app.manifest new file mode 100644 index 0000000..1bb2f80 --- /dev/null +++ b/src/threat_object_fun/app.manifest @@ -0,0 +1,57 @@ +{ + "schemaVersion": "2.0.0", + "info": { + "title": "Threat Object Fun", + "id": { + "group": null, + "name": "threat_object_fun", + "version": "1.0.0" + }, + "author": [ + { + "name": "Haylee Mills, Stuart McIntosh", + "email": null, + "company": "Outpost Security" + } + ], + "releaseDate": null, + "description": "An illustrative app for working with Threat Objects.", + "classification": { + "intendedAudience": null, + "categories": [], + "developmentStatus": null + }, + "commonInformationModels": null, + "license": { + "name": null, + "text": null, + "uri": null + }, + "privacyPolicy": { + "name": null, + "text": null, + "uri": null + }, + "releaseNotes": { + "name": null, + "text": null, + "uri": null + } + }, + "dependencies": { + "SplunkEnterpriseSecuritySuite": { + "version": ">=6.6.0", + "optional": false + } + }, + "tasks": null, + "inputGroups": null, + "incompatibleApps": null, + "platformRequirements": null, + "supportedDeployments": [ + "_standalone", + "_distributed" + ], + "targetWorkloads": ["_search_heads"] +} + diff --git a/src/threat_object_fun/default/app.conf b/src/threat_object_fun/default/app.conf new file mode 100644 index 0000000..853ba38 --- /dev/null +++ b/src/threat_object_fun/default/app.conf @@ -0,0 +1,24 @@ +# +# Splunk app configuration file +# + +[id] +name = threat_object_fun +version = 1.0.0 + +[install] +is_configured = 0 + +[ui] +is_visible = 1 +label = Threat Object Fun + +[launcher] +author = Haylee Mills, Stuart McIntosh, Outpost Security +description = An illustrative app for working with Threat Objects. +version = 1.0.0 + +[package] +id = threat_object_fun +check_for_updates = 1 + diff --git a/src/threat_object_fun/default/data/ui/nav/default.xml b/src/threat_object_fun/default/data/ui/nav/default.xml new file mode 100644 index 0000000..20229fd --- /dev/null +++ b/src/threat_object_fun/default/data/ui/nav/default.xml @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/src/threat_object_fun/default/data/ui/panels/content_threat_object_fields.xml b/src/threat_object_fun/default/data/ui/panels/content_threat_object_fields.xml new file mode 100644 index 0000000..381e32a --- /dev/null +++ b/src/threat_object_fun/default/data/ui/panels/content_threat_object_fields.xml @@ -0,0 +1,46 @@ + + Suggested Threat Object Types + +

These are suggested threat object types based on threat intel fields and potential SOAR fields.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
certificate_common_namedomainprocessregistry_value_name
certificate_organizationemailprocess_nameregistry_value_text
certificate_serialemail_subjectparent_processregistry_value_text
certificate_unitfile_hashparent_process_nameservice
commandfile_nameprocess_hashurl
http_user_agentregistry_path
+
+ +
\ No newline at end of file diff --git a/src/threat_object_fun/default/data/ui/views/risk_investigation_dashboard.xml b/src/threat_object_fun/default/data/ui/views/risk_investigation_dashboard.xml new file mode 100644 index 0000000..bf23bc1 --- /dev/null +++ b/src/threat_object_fun/default/data/ui/views/risk_investigation_dashboard.xml @@ -0,0 +1,560 @@ + +
+ + + false + true + + true + false + + + + + + + + + * + + + | tstats summariesonly=t count values(All_Risk.risk_message) as risk_message values(All_Risk.risk_score) as risk_score values(All_Risk.savedsearch_description) as description values(All_Risk.annotations._all) as annotation values(source) as source values(All_Risk.src) as src values(All_Risk.user) as user values(All_Risk.threat_object) as threat_object from datamodel=Risk.All_Risk where All_Risk.risk_object=$field_rv$ groupby _time,All_Risk.risk_score,All_Risk.risk_message span=1s | table * | dedup _time risk_message + $timepicker.earliest$ + $timepicker.latest$ + + + + | search NOT risk_score=0 + + + + | tstats summariesonly=t count as event_count from datamodel=Risk.All_Risk where All_Risk.risk_object=$field_rv$ groupby All_Risk.risk_object + -30d + now + + $result.event_count$ + + + + index=risk (NOT source="/opt/*" risk_object="$field_rv$") +| stats count values(source) as source dc(risk_message) as risk_messages by threat_object +| eventstats dc(threat_object) as dc_threats + + $timepicker.earliest$ + $timepicker.latest$ + + $result.dc_threats$ + + +
+ + + User + + + true + + + + true + + + + System + + + true + + + + true + + + + + + + + + + + -7d@h + now + + + +
+ + + Aggregate Risk Score + + + +| eval risk_score = round(risk_score,0) , risk_message = risk_score." - ".risk_message +| streamstats sum(risk_score) as score_original values(source) as sources values(risk_message) as risk_messages by risk_object +| dedup risk_message risk_score +| stats sum(risk_score) as risk_score + + + + + + + + + + + + +| makeresults | eval count = "$event_count$" | eval count = if(isnum(count),count,"0") + + + + + + + + + + + + +| makeresults | eval count = "$notable_count$" | eval count = if(isnum(count),count,"0") + + + + + + + + + + + + + + + Risk Object Info + + + | inputlookup identity_lookup_expanded | search identity="$field_rv$" | table first last identity bunit startDate endDate watchlist_name | eval startDate=strftime(startDate,"%Y-%m-%d") , endDate=strftime(endDate,"%Y-%m-%d") + -24h@h + now + + + + +
+ + + | inputlookup asset_lookup_by_str | search nt_host="$field_rv$" | table wks_ip wks_usr wks_dom category city + -24h@h + now + + + + +
+
+
+ + + Notables for $field_rv$ in past 30 days + + + +`get_notable_index` risk_object=$field_rv$ +| eval indexer_guid=replace('_bkt',".*~(.+)","\\1"), event_hash=md5(('_time' . '_raw')), event_id=((((indexer_guid . "@@") . index) . "@@") . event_hash), rule_id=event_id +| eval latest=orig_time+1800 , earliest=orig_time-1800 +| search event_id="*" +| fields - "host_*" +| tags outputfield=tag +| eval tag=mvdedup(mvappend(tag,NULL,orig_tag)) +| dedup rule_id +| lookup update=true notable_xref_lookup event_id OUTPUTNEW xref_name as notable_xref_name,xref_id as notable_xref_id +| eval notable_xref=mvzip(notable_xref_name,notable_xref_id,":") +| eval temp_time=(time() + 86400) +| lookup update=true event_time_field=temp_time incident_review_lookup rule_id OUTPUT owner as new_owner, urgency as new_urgency, status as new_status, disposition as new_disposition +| lookup update=true event_time_field=temp_time incident_review_comment_lookup rule_id OUTPUT time as review_time,user as reviewer,comment +| eval owner=if(isnotnull(new_owner),new_owner,owner), status=case(isnotnull(new_status),new_status,isnotnull(status),status,true(),default_status), urgency=if(isnotnull(new_urgency),new_urgency,urgency), disposition=if(isnotnull(new_disposition),new_disposition,default_disposition) +| fields - temp_time, new_owner, new_status, new_urgency, new_disposition +| eval temp_status=if(isnull(status),-1,status) +| lookup update=true reviewstatuses_lookup _key as temp_status OUTPUT status,label as status_label,description as status_description,default as status_default,end as status_end +| eval status=if(isnull(status_label),0,status), status_label=if(isnull(status_label),"Unassigned",status_label), status_description=if(isnull(status_description),"unknown",status_description), status_default=case(match(status_default,"1|[Tt]|[Tt][Rr][Uu][Ee]"),"true",match(status_default,"0|[Ff]|[Ff][Aa][Ll][Ss][Ee]"),"false",true(),status_default), status_end=case(match(status_end,"1|[Tt]|[Tt][Rr][Uu][Ee]"),"true",match(status_end,"0|[Ff]|[Ff][Aa][Ll][Ss][Ee]"),"false",true(),status_end), status_group=case((status_default == "true"),"New",(status_end == "true"),"Closed",(status == 0),"New",true(),"Open") +| fields - temp_status +| eval temp_disposition=if(isnull(disposition),-3,disposition) +| lookup update=true disposition_lookup _key as temp_disposition OUTPUT status as disposition,label as disposition_label,description as disposition_description,default as disposition_default +| eval disposition=if(isnull(disposition),"disposition:0",disposition), disposition_label=if(isnull(disposition_label),"Unassigned",disposition_label), disposition_description=if(isnull(disposition_description),"An error is preventing the event from having a valid disposition.",disposition_description), disposition_default=case(match(disposition_default,"1|[Tt]|[Tt][Rr][Uu][Ee]"),"true",match(disposition_default,"0|[Ff]|[Ff][Aa][Ll][Ss][Ee]"),"false",true(),disposition_default) +| fields - temp_disposition +| table _time, orig_time, search_name, orig_source, status_label, status_end, comment, owner, reviewer, risk_object, risk_object_type, risk_messages, src, user, dest, rule_id, event_hash, earliest, latest +| eventstats count as notable_count count(eval(status_label="Incident")) as incident_count | eval incident_count = if(isnull(incident_count),"0",incident_count) | rename status_label as status +| eval ir_link = "https://i-0f475f545da6fbdc2.splunk.show/en-US/app/SplunkEnterpriseSecuritySuite/incident_review?earliest=".earliest."&latest=".latest."&status=*&urgency=*&search=event_hash%3D".event_hash + + -30d + now + + $result.notable_count$ + $result.incident_count$ + + + + + $row.ir_link|n$ + + + + + + _time owner status comment + + [#a7c4f2] + + + +
+
+
+ + + Event Breakdown + + + | stats count as Events sum(risk_score) as risk_sum dc(risk_message) as "Distinct Events" values(description) as Description values(annotation) as Annotation by source | rename source as Rule | eval risk_sum = round(risk_sum,0) | rename risk_sum as "Risk Sum" | sort - "Risk Sum" + + "Events" "Risk Sum" "Rule" "Description" "Annotation" + + $row.Rule$ + + + + + + + [#a7c4f2] + +
+
+ + + + + | rest splunk_server=local count=0 /services/saved/searches + | search title="$risk_rule_drilldown$" | rename dispatch.earliest_time as early_time + | table title qualifiedSearch early_time + + + $result.qualifiedSearch$ + $result.early_time$ + + + + [#a7c4f2] + + + + search?q=$qualifiedSearch$&earliest=$earlySearch$&latest=$timepicker.latest$ + + + + + +
+
+
+ + + Timeline of Events + + + | stats count as count by _time,risk_score,risk_message | timechart span=30min limit=0 values(risk_score) as risk_score by risk_message + + + + $start$ + $end$ + + + + + + + + + + + + + + + + Risk Events + + | makeresults + | eval count="0" | eval count= if(isint($addriskmsg_count$),"$addriskmsg_count$",0) + | fields count | table count | sort - count + + + + + + + + + + + + + + + + Threat Objects + + | makeresults + | eval count="0" | eval count= if(isint($dc_threats$),"$dc_threats$",0) + | fields count | table count | sort - count + + + + + + + + + + + + + + + + + Risk Messages for risk_object=$field_rv$ (click to drilldown) + + All Events (Default) + Use Selection + no-selection + + + true + + + + + true + + + + + + + + * + + + + + + + + + | eval risk_score = round(risk_score) +| eval risk_message = risk_score." - ".risk_message +| table _time source risk_message risk_score threat_object threat_short +| sort + _time +| eventstats count(risk_message) as riskmsg_count +| search $search_filter$ | eventstats count(risk_message) as addriskmsg_count + + + $result.addriskmsg_count$ + + + + + [#a7c4f2] + + ["_time","source","risk_message","threat_object"] + + + $click.value2$ + replace(replace($threat_token$,"\\\\","\\\\\\"),"\"","\\\"") + + + search?q=index=proxy category="FileHost" NOT dest IN ("*.icloud.com","*.live.com","d.docs.live.net","docs.live.net","api.onedrive.com","*.box.com") $field_rv$ earliest=$timepicker.earliest$ | stats values(src_user_bunit) as src_user_bunit count sum(bytes) as bytes by dest,src_user + + + + + +
+
+ + + + + | where _time > $selection.earliest$ AND _time < $selection.latest$ + + + $result.addriskmsg_count$ + + + + + [#a7c4f2] + + ["_time","source","risk_message","threat_object"] + + $click.value2$ + replace(replace($threat_token$,"\\\\","\\\\\\"),"\"","\\\"") + +
+
+ + Threat Objects + + + + + + count risk_messages source threat_object + + $row.threat_object$ + replace(replace($threat_token$,"\\\\","\\\\\\"),"\"","\\\"") + + +
+
+ + + Number of Events + + | makeresults | eval num_objects = if(isint($num_objects$),"$num_objects$",0) | table num_objects + + + + + + + + + + + + + + + + + + + + Risk Rule Sources + + | makeresults | eval source_count = if(isint($source_count$),"$source_count$",0) | table source_count + + + + + + + + + + + + + + + + + + + Risk Objects + + | makeresults +| eval risk_objects = if(isint($ro_count$),"$ro_count$",0) +| table risk_objects + $earliest$ + $latest$ + + + + + + + + + + + + + + + + + + + Past 30 Days for $threat_token$ + + | tstats summariesonly=t count values(All_Risk.risk_message) as risk_message values(All_Risk.risk_score) as risk_score values(source) as sources values(All_Risk.risk_object_type) as risk_object_type from datamodel=Risk.All_Risk where All_Risk.threat_object="$threat_token$" groupby All_Risk.risk_object _time span=30d | rename All_Risk.risk_object as risk_object | table * | eval risk_score = mvindex(risk_score,0) , risk_score=round(risk_score,0) , risk_message = mvindex(risk_message,0) , risk_message = risk_score." - ".risk_message | eventstats dc(risk_object) as ro_count dc(sources) as source_count sum(count) as num_objects | rename risk_message AS sample_message + -30d + + 1 + + $result.ro_count$ + $result.source_count$ + $result.num_objects$ + + + + + + + + + + + [#a7c4f2] + + ["risk_object","count","sample_message"] + + + /app/SplunkEnterpriseSecuritySuite/risk_investigation_dashboard?form.field_rv=$click.value2$&form.timepicker.earliest=-30d&form.timepicker.latest=now + + + + + +
+
+
+
\ No newline at end of file diff --git a/src/threat_object_fun/default/data/ui/views/threat_object__hunting.xml b/src/threat_object_fun/default/data/ui/views/threat_object__hunting.xml new file mode 100644 index 0000000..337e42c --- /dev/null +++ b/src/threat_object_fun/default/data/ui/views/threat_object__hunting.xml @@ -0,0 +1,448 @@ +
+ + + + + + + + + | tstats summariesonly=true count dc(All_Risk.risk_object) as dc_r_obj dc(All_Risk.threat_object) as dc_t_obj dc(All_Risk.src) as dc_src dc(All_Risk.dest) as dc_dest dc(All_Risk.user) as dc_users dc(All_Risk.user_bunit) as dc_bunit sum(All_Risk.calculated_risk_score) as risk_sum values(All_Risk.calculated_risk_score) as scores values(All_Risk.risk_object) as risk_object values(All_Risk.src) as src values(All_Risk.dest) as dest values(All_Risk.user) as user values(All_Risk.user_bunit) as bunit from datamodel=Risk.All_Risk where All_Risk.threat_object IN ("$threat_token$") by All_Risk.threat_object,All_Risk.threat_object_type,source | `drop_dm_object_name("All_Risk")` + + $time_picker.earliest$ + $time_picker.latest$ + + + +
+ + + + replace(replace(replace($threat_object$,"\\\\","\\\\\\"),"\"","\\\""),"\\|","\\\|") + replace($threat_token$,"&&","\",\"") + + * + + + + + -7d@d + now + + +
+ + + + Search for multiple threat objects at the same time by joining them with "&&" in the input field. + + + + + + Past 30 Days + + Number of Events + + | makeresults | eval num_objects = if(isint($num_objects$),"$num_objects$",0) | table num_objects + + + + + + + + + + + + + + + + + true + + + + Risk Rule Sources + + | makeresults | eval source_count = if(isint($source_count$),"$source_count$",0) | table source_count + + + + + + + + + + + + + + + + + + + Risk Objects + + | makeresults +| eval risk_objects = if(isint($ro_count$),"$ro_count$",0) +| table risk_objects + $earliest$ + $latest$ + + + + + + + + + + + + + + + Related Threat Objects + + | makeresults | eval related_count = if(isint($related_count$),"$related_count$",0) | table related_count + + + + + + + + + + + + + + + + + + + Risk Messages in Past 30 Days + + + | tstats summariesonly=t count values(All_Risk.risk_message) as risk_message sum(All_Risk.calculated_risk_score) as risk_score values(source) as sources dc(All_Risk.threat_object) as dc_t_obj values(All_Risk.threat_object_type) as t_types values(All_Risk.threat_object) as threat_object values(All_Risk.risk_object_type) as risk_object_type from datamodel=Risk.All_Risk where All_Risk.threat_object IN ("$threat_token$") groupby All_Risk.risk_object All_Risk.calculated_risk_score source _time span=30d | `drop_dm_object_name("All_Risk")` | table * | dedup risk_message | eval risk_message="-----=== ".source." ===-----||"."===== THREAT OBJECTS ====||".mvjoin(threat_object,"||")."||===== RISK MESSAGES =====||".mvjoin(risk_message,"||")."|| ||" | rex mode=sed field=risk_message "s/\|\|/\n/g" | stats sum(count) as events sum(dc_t_obj) as dc_t_obj values(t_types) as t_types sum(risk_score) as risk_score values(sources) as sources values(risk_message) as risk_message by risk_object | eventstats dc(risk_object) as ro_count dc(sources) as source_count sum(events) as num_objects + + -30d + + 1 + + $result.ro_count$ + $result.source_count$ + $result.num_objects$ + + + + + + + + + + + [#a7c4f2] + + ["risk_object","count","dc_t_obj","t_types","risk_message"] + + + /app/threat_object_fun/risk_investigation_dashboard?form.field_rv=$click.value2$&form.timepicker.earliest=-30d&form.timepicker.latest=now + + + + + +
+
+
+ + + + + + | tstats summariesonly=true count sum(All_Risk.calculated_risk_score) as risk_sum values(All_Risk.calculated_risk_score) as scores values(All_Risk.threat_object_type) as threat_object_type from datamodel=Risk.All_Risk where All_Risk.$search_values$ IN ("$values_search$") by All_Risk.$search_values$,All_Risk.risk_object,source,All_Risk.threat_object | `drop_dm_object_name("All_Risk")` | eval threat_object_type=mvjoin(threat_object_type,"+") , threat_object_full=threat_object , threat_object=if(len(threat_object)<90, threat_object, substr(threat_object,1,90)."...") , threat_object=threat_object_type.": ".threat_object | stats values(threat_object) as threat_object values(threat_object_full) as threat_object_full sum(count) as count sum(risk_sum) as risk_sum by $search_values$,risk_object,source | eval threat_object="--= ".source." =--||".mvjoin(threat_object,"||") | rex mode=sed field=threat_object "s/\|\|/\n/g" | stats values(threat_object) as threat_object sum(count) as count sum(risk_sum) as risk_sum values(threat_object_full) as threat_object_full by $search_values$,risk_object | eval threat_object_full=mvjoin(threat_object_full,"&&") + + + $search_values$,risk_object,threat_object,count,risk_sum + + + /app/threat_object_fun/risk_investigation_dashboard?form.field_rv=$click.value2$&form.timepicker.earliest=-7d&form.timepicker.latest=now + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object__hunting?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + + + + + [#a7c4f2] + + + [#a7e4f2] + +
+
+ + + + + | tstats summariesonly=true count sum(All_Risk.calculated_risk_score) as risk_sum values(All_Risk.calculated_risk_score) as scores values(All_Risk.threat_object_type) as threat_object_type from datamodel=Risk.All_Risk where All_Risk.risk_object IN ("$values_search$") by All_Risk.risk_object,source,All_Risk.threat_object | `drop_dm_object_name("All_Risk")` | eval threat_object_type=mvjoin(threat_object_type,"+") , threat_object_full=threat_object , threat_object=if(len(threat_object)<90, threat_object, substr(threat_object,1,90)."...") , threat_object=threat_object_type.": ".threat_object | stats values(threat_object) as threat_object values(threat_object_full) as threat_object_full sum(count) as count sum(risk_sum) as risk_sum by risk_object,source | eval threat_object="--= ".source." =--||".mvjoin(threat_object,"||") | rex mode=sed field=threat_object "s/\|\|/\n/g" | stats values(threat_object) as threat_object sum(count) as count sum(risk_sum) as risk_sum values(threat_object_full) as threat_object_full by risk_object | eval threat_object_full=mvjoin(threat_object_full,"&&") + + + risk_object,threat_object,count,risk_sum + + + /app/threat_object_fun/risk_investigation_dashboard?form.field_rv=$click.value2$&form.timepicker.earliest=-7d&form.timepicker.latest=now + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object__hunting?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + + + + + [#a7c4f2] + + + [#a7c4f2] + +
+
+
+ + + + Prevalence by Source + + | search threat_object IN ("$threat_token$") | sort 1000 + count | eval threat_object_full=threat_object | eval type=threat_object_type | eval threat_object=if(len(threat_object)<50, threat_object, substr(threat_object,1,50)."...") + + threat_object type source count dc_r_obj dc_t_obj dc_src dc_dest dc_users dc_bunit risk_sum scores + + + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + + + risk_object + $row.risk_object$ + replace(replace($risk_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($risk_values$,",","\",\"") + + + + src + $row.src$ + replace(replace($src_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($src_values$,",","\",\"") + + + + dest + $row.dest$ + replace(replace($dest_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($dest_values$,",","\",\"") + + + + user + $row.user$ + replace(replace($user_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($user_values$,",","\",\"") + + + + bunit + $row.bunit$ + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object__hunting?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object__hunting?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + + + +
+
+
+ + + + Prevalence by Source - related objects + + | search NOT threat_object IN ("$threat_token$") | sort 1000 + count | eval threat_object_full=threat_object | eval type=threat_object_type | eval threat_object=if(len(threat_object)<50, threat_object, substr(threat_object,1,50)."...") | eventstats dc(threat_object_full) as dc_related_objects + + $result.dc_related_objects$ + + + threat_object type source count dc_r_obj dc_t_obj dc_src dc_dest dc_users dc_bunit risk_sum scores + + + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + + + risk_object + $row.risk_object$ + replace(replace($risk_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($risk_values$,",","\",\"") + + + + src + $row.src$ + replace(replace($src_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($src_values$,",","\",\"") + + + + dest + $row.dest$ + replace(replace($dest_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($dest_values$,",","\",\"") + + + + user + $row.user$ + replace(replace($user_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($user_values$,",","\",\"") + + + + bunit + $row.bunit$ + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object__hunting?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object__hunting?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + + + +
+
+
+ + + + + + | rest splunk_server=local count=0 /services/saved/searches + | search title="$risk_drilldown$" | rename dispatch.earliest_time as early_time qualifiedSearch as search_spl + | table description search_spl early_time + | eval search_spl = if(match(search_spl,"^(|\s)(tstats|from).*"),"|".search_spl,search_spl) + + + $result.search_spl$ + $result.early_time$ + + + + [#a7c4f2] + + + + search?q=$search_spl$&earliest=$early_time$&latest=$time_picker.latest$ + + + + + +
+
+
+ + + + Score Contribution + + | tstats summariesonly=false sum(All_Risk.calculated_risk_score) as risk_score,dc(All_Risk.risk_object) as risk_objects,count from datamodel=Risk.All_Risk where All_Risk.threat_object IN("$threat_token$") All_Risk.risk_object_type="*" (All_Risk.risk_object="*" OR risk_object="*") by source | sort 1000 - count,risk_score + $time_picker.earliest$ + $time_picker.latest$ + + + + + + + + + [#a7c4f2] + + + + $click.value$ + + + + + +
+
+
+
\ No newline at end of file diff --git a/src/threat_object_fun/default/data/ui/views/threat_object_content_dev.xml b/src/threat_object_fun/default/data/ui/views/threat_object_content_dev.xml new file mode 100644 index 0000000..34a8f6f --- /dev/null +++ b/src/threat_object_fun/default/data/ui/views/threat_object_content_dev.xml @@ -0,0 +1,414 @@ +
+ + This dashboard can be used to discover noise via threat objects or discover content which could use additional threat object definitions. + + + + + +
+ + + + -24h@h + now + + +
+ + + + + | makeresults | eval title = "tune" | table title + + + + + + + + + true + + + + + + | makeresults | eval title = "develop" | table title + + + + + + + + + true + + + + + + + + + + These contribute the most risk overall. This may be from a handful of risk_objects or threat_objects contributing an inordinate amount of risk and throwing off your thresholds. Rules which ingest hundreds of signatures should generate plenty of risk, whereas one-off detections for a specific thing should be carefully tuned. Consider adjusting logic to account for the noisiest behavior or applying a variable risk_score with | eval + to bring more signal from noise. + + + Risk Rules + + | tstats summariesonly=false sum(All_Risk.calculated_risk_score) as risk_score dc(All_Risk.risk_object) as risk_objects dc(All_Risk.threat_object) as threat_objects count from datamodel=Risk.All_Risk where * All_Risk.risk_object_type="*" (All_Risk.risk_object="*" OR risk_object="*") by source | sort 1000 - count risk_score + $time_picker.earliest$ + $time_picker.latest$ + + + [#a7c4f2] + + + + $click.value$ + + + + + +
+
+ + + These fire most commonly in every risk notable and may contribute more risk than necessary. Consider lowering score for the noisiest threat objects, finding useful fields which indicate less risk and + | eval a variable risk_score, or converting to a contextual 0 risk score rule. If you are utilizing contextual rules, consider modifying your Risk Incident Rules which use counts on metadata (like MITRE Tactics or Distinct Sources) to weight these differently. + + + Risk Rule Frequency + + `notable` | search eventtype=risk_notables | eventstats count as sum | stats count(eval(status_label="New")) as rule_count values(sum) as sum by orig_source | eval notable_percent = rule_count / sum | sort - notable_percent | eval notable_percent=round(notable_percent*100) | rename orig_source as source + $time_picker.earliest$ + $time_picker.latest$ + + + + + + + [#a7c4f2] + + + + $click.value$ + +
+
+ + + + + $result.search_spl$ + $result.early_time$ + + | rest splunk_server=local count=0 /services/saved/searches + | search title="$risk_drilldown$" | rename dispatch.earliest_time as early_time qualifiedSearch as search_spl + | table search_spl early_time + $time_picker.earliest$ + $time_picker.latest$ + + +
+
+
+ + + + + | tstats summariesonly=true count sum(All_Risk.calculated_risk_score) as risk_sum values(All_Risk.calculated_risk_score) as scores values(All_Risk.threat_object_type) as threat_object_type from datamodel=Risk.All_Risk where All_Risk.$search_values$ IN ("$values_search$") by All_Risk.$search_values$,All_Risk.risk_object,source,All_Risk.threat_object | `drop_dm_object_name("All_Risk")` | eval threat_object_type=mvjoin(threat_object_type,"+") , threat_object_full=threat_object , threat_object=if(len(threat_object)<90, threat_object, substr(threat_object,1,90)."...") , threat_object=threat_object_type.": ".threat_object | stats values(threat_object) as threat_object values(threat_object_full) as threat_object_full sum(count) as count sum(risk_sum) as risk_sum by $search_values$,risk_object,source | eval threat_object="--= ".source." =--||".mvjoin(threat_object,"||") | rex mode=sed field=threat_object "s/\|\|/\n/g" | stats values(threat_object) as threat_object sum(count) as count sum(risk_sum) as risk_sum values(threat_object_full) as threat_object_full by $search_values$,risk_object | eval threat_object_full=mvjoin(threat_object_full,"&&") + $time_picker.earliest$ + $time_picker.latest$ + + + + [#a7c4f2] + + + [#a7e4f2] + + $search_values$,risk_object,threat_object,count,risk_sum + + + /app/threat_object_fun/risk_investigation_dashboard?form.field_rv=$click.value2$&form.timepicker.earliest=-7d&form.timepicker.latest=now + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object__hunting?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + + + +
+
+ + + + | tstats summariesonly=true count sum(All_Risk.calculated_risk_score) as risk_sum values(All_Risk.calculated_risk_score) as scores values(All_Risk.threat_object_type) as threat_object_type from datamodel=Risk.All_Risk where All_Risk.risk_object IN ("$values_search$") by All_Risk.risk_object,source,All_Risk.threat_object | `drop_dm_object_name("All_Risk")` | eval threat_object_type=mvjoin(threat_object_type,"+") , threat_object_full=threat_object , threat_object=if(len(threat_object)<90, threat_object, substr(threat_object,1,90)."...") , threat_object=threat_object_type.": ".threat_object | stats values(threat_object) as threat_object values(threat_object_full) as threat_object_full sum(count) as count sum(risk_sum) as risk_sum by risk_object,source | eval threat_object="--= ".source." =--||".mvjoin(threat_object,"||") | rex mode=sed field=threat_object "s/\|\|/\n/g" | stats values(threat_object) as threat_object sum(count) as count sum(risk_sum) as risk_sum values(threat_object_full) as threat_object_full by risk_object | eval threat_object_full=mvjoin(threat_object_full,"&&") + $time_picker.earliest$ + $time_picker.latest$ + + + + [#a7c4f2] + + + [#a7c4f2] + + ["risk_object","threat_object","count","risk_sum"] + + + /app/threat_object_fun/risk_investigation_dashboard?form.field_rv=$click.value2$&form.timepicker.earliest=-7d&form.timepicker.latest=now + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object__hunting?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + + + +
+
+
+ + + + $risk_drilldown$ + + + | tstats summariesonly=true count dc(All_Risk.risk_object) as dc_r_obj dc(All_Risk.threat_object) as dc_t_obj dc(All_Risk.src) as dc_src dc(All_Risk.dest) as dc_dest dc(All_Risk.user) as dc_users dc(All_Risk.user_bunit) as dc_bunit sum(All_Risk.calculated_risk_score) as risk_sum values(All_Risk.calculated_risk_score) as scores values(All_Risk.risk_object) as risk_object values(All_Risk.src) as src values(All_Risk.dest) as dest values(All_Risk.user) as user values(All_Risk.user_bunit) as bunit from datamodel=Risk.All_Risk where source="$risk_drilldown$" by All_Risk.threat_object,All_Risk.threat_object_type | `drop_dm_object_name("All_Risk")` | sort 1000 - count | eval threat_object_full=threat_object | eval type=threat_object_type | eval threat_object=if(len(threat_object)<50, threat_object, substr(threat_object,1,50)."...") + $time_picker.earliest$ + $time_picker.latest$ + + threat_object type count dc_r_obj dc_t_obj dc_src dc_dest dc_users dc_bunit risk_sum scores + + + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + + + risk_object + $row.risk_object$ + replace(replace($risk_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($risk_values$,",","\",\"") + + + + src + $row.src$ + replace(replace($src_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($src_values$,",","\",\"") + + + + dest + $row.dest$ + replace(replace($dest_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($dest_values$,",","\",\"") + + + + user + $row.user$ + replace(replace($user_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($user_values$,",","\",\"") + + + + bunit + $row.bunit$ + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object__hunting?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object__hunting?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + + + +
+
+
+ + + Potential Threat Objects - From Risk Index + + + index=risk (certificate_common_name=* OR + certificate_organization=* OR + certificate_serial=* OR + certificate_unit=* OR + domain=* OR + email=* OR + email_subject=* OR + file_hash=* OR + file_name=* OR + http_user_agent=* OR + process=* OR + process_hash=* OR + process_name=* OR + parent_process_name=* OR + parent_process=* OR + registry_path=* OR + registry_value_name=* OR + registry_value_text=* OR + service=* OR + url=* OR + command=*) +| stats + count(eval(like(certificate_common_name,"%"))) as count_certificate_common_name + count(eval(like(certificate_organization,"%"))) as count_certificate_organization + count(eval(like(certificate_serial,"%"))) as count_certificate_serial + count(eval(like(certificate_unit,"%"))) as count_certificate_unit + count(eval(like(domain,"%"))) as count_domain + count(eval(like(email,"%"))) as count_email + count(eval(like(email_subject,"%"))) as count_email_subject + count(eval(like(file_hash,"%"))) as count_file_hash + count(eval(like(file_name,"%"))) as count_file_name + count(eval(like(http_user_agent,"%"))) as count_http_user_agent + count(eval(like(process,"%"))) as count_process + count(eval(like(process_hash,"%"))) as count_process_hash + count(eval(like(process_name,"%"))) as count_process_name + count(eval(like(parent_process_name,"%"))) as count_parent_process_name + count(eval(like(parent_process,"%"))) as count_parent_process + count(eval(like(registry_path,"%"))) as count_registry_path + count(eval(like(registry_value_name,"%"))) as count_registry_value_name + count(eval(like(registry_value_text,"%"))) as count_registry_value_text + count(eval(like(service,"%"))) as count_service + count(eval(like(url,"%"))) as count_url + count(eval(like(command,"%"))) as count_command, + values(threat_object_type) as threat_object_type, + count + by source +| eval observed_threat_object_types=mvappend( + if(count_certificate_common_name>0, "certificate_common_name=".count_certificate_common_name, ""), + if(count_certificate_organization>0, "certificate_organization=".count_certificate_organization, ""), + if(count_certificate_serial>0, "certificate_serial=".count_certificate_serial, ""), + if(count_certificate_unit>0, "certificate_unit=".count_certificate_unit, ""), + if(count_domain>0, "domain=".count_domain, ""), + if(count_email>0, "email=".count_email, ""), + if(count_email_subject>0, "email_subject=".count_email_subject, ""), + if(count_file_hash>0, "file_hash=".count_file_hash, ""), + if(count_file_name>0, "file_name=".count_file_name, ""), + if(count_http_user_agent>0, "http_user_agent=".count_http_user_agent, ""), + if(count_process>0, "process=".count_process, ""), + if(count_process_hash>0, "process_hash=".count_process_hash, ""), + if(count_process_name>0, "process_name=".count_process_name, ""), + if(count_parent_process_name>0, "parent_process_name=".count_parent_process_name, ""), + if(count_parent_process>0, "parent_process=".count_parent_process, ""), + if(count_registry_path>0, "registry_path=".count_registry_path, ""), + if(count_registry_value_name>0, "registry_value_name=".count_registry_value_name, ""), + if(count_registry_value_text>0, "registry_value_text=".count_registry_value_text, ""), + if(count_service>0, "service=".count_service, ""), + if(count_url>0, "url=".count_url, ""), + if(count_command>0, "command=".count_command, ""), + "") +| stats values(count) as event_count, values(observed_threat_object_types) as observed_threat_object_types, values(threat_object_type) as existing_threat_object_types by source +| sort - count + $time_picker.earliest$ + $time_picker.latest$ + + + +
+
+ +
+ + + Enabled Risk Generation Rules with Threat Objects + + + | rest splunk_server=local count=0 /services/saved/searches +| where match('action.correlationsearch.enabled', "1|[Tt]|[Tt][Rr][Uu][Ee]") AND NOT disabled=1 +| table title, disabled, alert.track, action.risk, cron_schedule, description, eai:acl.app, action.risk.param._risk +| search action.risk.param._risk="*threat_object*" +| eval _temp=split(replace(replace('action.risk.param._risk',"\[",""),"\]",""), "{") +| eval _temp2=mvfilter(_temp!="") +| eval _temp2=mvindex(_temp2, mvfind(_temp2,"threat_")) +| eval _temp3=split(_temp2,",") +| replace "*}" with "*" in _temp3 +| eval threat_objects=_temp3 +| fields - action.risk.param._risk, alert.track, action.risk + -15m + now + + + [#a7c4f2] + + + + $row.threat_object_full$ + /app/SplunkEnterpriseSecuritySuite/correlation_search_edit?search=$row.title$ + + + + + + +
+
+
+ + + Enabled Risk Generation Rules with *NO* Threat Objects + + + | rest splunk_server=local count=0 /services/saved/searches +| where match('action.correlationsearch.enabled', "1|[Tt]|[Tt][Rr][Uu][Ee]") AND NOT disabled=1 AND 'action.risk'=1 +| table title, alert.track, action.risk, cron_schedule, description, eai:acl.app, action.risk.param._risk +| search action.risk.param._risk!="*threat_object*" +| fields - action.risk.param._risk, alert.track, action.risk + -15m + now + + + + [#a7c4f2] + + + + $row.threat_object_full$ + /app/SplunkEnterpriseSecuritySuite/correlation_search_edit?search=$row.title$ + + + + + +
+
+
+
\ No newline at end of file diff --git a/src/threat_object_fun/default/data/ui/views/threat_object_detail.xml b/src/threat_object_fun/default/data/ui/views/threat_object_detail.xml new file mode 100644 index 0000000..954deda --- /dev/null +++ b/src/threat_object_fun/default/data/ui/views/threat_object_detail.xml @@ -0,0 +1,77 @@ +
+ +
+ + + + + + + -7d@h + now + + +
+ + + Occurrence Count by Day - Last 90 Days + + + | tstats `summariesonly` count + from datamodel=Risk.All_Risk + where (All_Risk.threat_object_type!="unknown" All_Risk.threat_object_type!="" All_Risk.threat_object=$input_threat_object|s$) + by All_Risk.threat_object, _time +| `drop_dm_object_name("All_Risk")` +| search threat_object=$input_threat_object|s$ +| timechart span=1d sum(count) as count BY threat_object + -90d@d + now + + + + + + + + + + + + Threat Object Details + + + | tstats `summariesonly` count, values(source) as detections + from datamodel=Risk.All_Risk + where (All_Risk.threat_object_type!="unknown" All_Risk.threat_object_type!="" All_Risk.threat_object=$input_threat_object|s$) + by All_Risk.threat_object, All_Risk.threat_object_type +| `drop_dm_object_name("All_Risk")` +| search threat_object=$input_threat_object|s$ + $input_timerange.earliest$ + $input_timerange.latest$ + + + +
+
+ + Risk Objects + + + | tstats `summariesonly` count, values(source) as detections + from datamodel=Risk.All_Risk + where (All_Risk.threat_object_type!="unknown" All_Risk.threat_object_type!="" All_Risk.threat_object=$input_threat_object|s$) + by All_Risk.threat_object, All_Risk.threat_object_type, All_Risk.risk_object, All_Risk.risk_object_type +| `drop_dm_object_name("All_Risk")` +| search threat_object=$input_threat_object|s$ +| fields - threat_object, threat_object_type +| dedup risk_object, risk_object_type, detections +| sort - count + $input_timerange.earliest$ + $input_timerange.latest$ + + + +
+
+
+
\ No newline at end of file diff --git a/src/threat_object_fun/default/data/ui/views/threat_object_overview.xml b/src/threat_object_fun/default/data/ui/views/threat_object_overview.xml new file mode 100644 index 0000000..8860bb0 --- /dev/null +++ b/src/threat_object_fun/default/data/ui/views/threat_object_overview.xml @@ -0,0 +1,119 @@ +
+ +
+ + + + -7d@h + now + + +
+ + + Threat Object Types Found + + + | tstats `summariesonly` count + from datamodel=Risk.All_Risk + where (All_Risk.threat_object_type!="unknown" All_Risk.threat_object_type!="") + by All_Risk.threat_object_type +| `drop_dm_object_name("All_Risk")` + $input_timerange.earliest$ + $input_timerange.latest$ + + + + + + + Threat Object Types Found - Over Time + + + | tstats `summariesonly` count + from datamodel=Risk.All_Risk + where (All_Risk.threat_object_type!="unknown" All_Risk.threat_object_type!="") + by _time All_Risk.threat_object_type +| `drop_dm_object_name("All_Risk")` +| chart bins=75 sum(count) as count over _time by threat_object_type + $input_timerange.earliest$ + $input_timerange.latest$ + + + + + + + + + + + + Threat Objects - Top 10 + + + | tstats `summariesonly` count as total, + dc(All_Risk.risk_object) as distinct_risk_objects, + values(source) as detections + from datamodel=Risk.All_Risk + where (All_Risk.threat_object_type!="unknown" All_Risk.threat_object_type!="") + by All_Risk.threat_object +| `drop_dm_object_name("All_Risk")` +| sort 10 - total +| eval threat_object=if(len(threat_object)<50, threat_object, substr(threat_object,1,50)."...") + $input_timerange.earliest$ + $input_timerange.latest$ + + +
+
+ + Threat Objects - Rarest 10 + + + | tstats `summariesonly` count as total, + dc(All_Risk.risk_object) as distinct_risk_objects, + values(source) as detections + from datamodel=Risk.All_Risk + where (All_Risk.threat_object_type!="unknown" All_Risk.threat_object_type!="") + by All_Risk.threat_object +| `drop_dm_object_name("All_Risk")` +| sort 10 total +| eval threat_object=if(len(threat_object)<50, threat_object, substr(threat_object,1,50)."...") + $input_timerange.earliest$ + $input_timerange.latest$ + + +
+
+
+ + + Non-File Threat Objects Related To File Threat Objects + + + | tstats `summariesonly` count, values(source) as detections, values(All_Risk.threat_object_type) as threat_object_type, dc(All_Risk.threat_object_type) as threat_object_type_count + from datamodel=Risk.All_Risk + where (All_Risk.threat_object_type!="unknown" All_Risk.threat_object_type!="" All_Risk.threat_object_type!=file_name) ( + [| tstats `summariesonly` count, values(source) as detections + from datamodel=Risk.All_Risk + where (All_Risk.threat_object_type!="unknown" All_Risk.threat_object_type!="" All_Risk.threat_object_type=file_name) + by All_Risk.threat_object, All_Risk.threat_object_type + | `drop_dm_object_name("All_Risk")` + | fields threat_object + | eval threat_object="*".mvindex(split(threat_object,"\\"), mvcount(split(threat_object,"\\"))-1)."*" + | rename threat_object AS "All_Risk.threat_object"]) + by All_Risk.threat_object +| `drop_dm_object_name("All_Risk")` +| sort - threat_object_type_count + $input_timerange.earliest$ + $input_timerange.latest$ + + + + /app/threat_object_fun/threat_object_detail?form.input_threat_object=$row.threat_object$ + +
+
+
+
\ No newline at end of file diff --git a/src/threat_object_fun/default/data/ui/views/threat_object_overview_test.xml b/src/threat_object_fun/default/data/ui/views/threat_object_overview_test.xml new file mode 100644 index 0000000..41e4a5d --- /dev/null +++ b/src/threat_object_fun/default/data/ui/views/threat_object_overview_test.xml @@ -0,0 +1,90 @@ +
+ +
+ + + + -7d@h + now + + +
+ + + Threat Object Types Found + + + | tstats `summariesonly` count + from datamodel=Risk.All_Risk + where (All_Risk.threat_object_type!="unknown" All_Risk.threat_object_type!="") + by All_Risk.threat_object_type +| `drop_dm_object_name("All_Risk")` + $input_timerange.earliest$ + $input_timerange.latest$ + + + + + + + Threat Object Types Found - Over Time + + + | tstats `summariesonly` count + from datamodel=Risk.All_Risk + where (All_Risk.threat_object_type!="unknown" All_Risk.threat_object_type!="") + by _time All_Risk.threat_object_type +| `drop_dm_object_name("All_Risk")` +| chart bins=75 sum(count) as count over _time by threat_object_type + $input_timerange.earliest$ + $input_timerange.latest$ + + + + + + + + + + Threat Objects - Top 10 + + + | tstats `summariesonly` count as total, + dc(All_Risk.risk_object) as distinct_risk_objects, + values(source) as detections + from datamodel=Risk.All_Risk + where (All_Risk.threat_object_type!="unknown" All_Risk.threat_object_type!="") + by All_Risk.threat_object +| `drop_dm_object_name("All_Risk")` +| sort 10 - total +| eval threat_object=if(len(threat_object)<50, threat_object, substr(threat_object,1,50)."...") + $input_timerange.earliest$ + $input_timerange.latest$ + + +
+
+
+ + + Threat Objects - Rarest 10 + + + | tstats `summariesonly` count as total, + dc(All_Risk.risk_object) as distinct_risk_objects, + values(source) as detections + from datamodel=Risk.All_Risk + where (All_Risk.threat_object_type!="unknown" All_Risk.threat_object_type!="") + by All_Risk.threat_object +| `drop_dm_object_name("All_Risk")` +| sort 10 total +| eval threat_object=if(len(threat_object)<50, threat_object, substr(threat_object,1,50)."...") + $input_timerange.earliest$ + $input_timerange.latest$ + + +
+
+
+
\ No newline at end of file diff --git a/src/threat_object_fun/default/data/ui/views/threat_object_prevalence.xml b/src/threat_object_fun/default/data/ui/views/threat_object_prevalence.xml new file mode 100644 index 0000000..c107a76 --- /dev/null +++ b/src/threat_object_fun/default/data/ui/views/threat_object_prevalence.xml @@ -0,0 +1,450 @@ +
+ + + + + + + + + | tstats summariesonly=true count dc(All_Risk.risk_object) as dc_r_obj dc(All_Risk.threat_object) as dc_t_obj dc(All_Risk.src) as dc_src dc(All_Risk.dest) as dc_dest dc(All_Risk.user) as dc_users dc(All_Risk.user_bunit) as dc_bunit sum(All_Risk.calculated_risk_score) as risk_sum values(All_Risk.calculated_risk_score) as scores values(All_Risk.risk_object) as risk_object values(All_Risk.src) as src values(All_Risk.dest) as dest values(All_Risk.user) as user values(All_Risk.user_bunit) as bunit from datamodel=Risk.All_Risk where All_Risk.threat_object IN ("$threat_token$") by All_Risk.threat_object,All_Risk.threat_object_type,source | `drop_dm_object_name("All_Risk")` + + $time_picker.earliest$ + $time_picker.latest$ + + + +
+ + + + replace(replace(replace($threat_object$,"\\\\","\\\\\\"),"\"","\\\""),"\\|","\\\|") + replace($threat_token$,"&&","\",\"") + + * + * + + + + + -7d@d + now + + +
+ + + + + Search for multiple threat objects at the same time by joining them with "&&" in the input field. + + + + + + Past 30 Days + + Number of Events + + | makeresults | eval num_objects = if(isint($num_objects$),"$num_objects$",0) | table num_objects + + + + + + + + + + + + + + + + + true + + + + Risk Rule Sources + + | makeresults | eval source_count = if(isint($source_count$),"$source_count$",0) | table source_count + + + + + + + + + + + + + + + + + + + Risk Objects + + | makeresults +| eval risk_objects = if(isint($ro_count$),"$ro_count$",0) +| table risk_objects + $earliest$ + $latest$ + + + + + + + + + + + + + + + Related Threat Objects + + | makeresults | eval related_count = if(isint($related_count$),"$related_count$",0) | table related_count + + + + + + + + + + + + + + + + + + + Risk Messages in Past 30 Days + + + | tstats summariesonly=t count values(All_Risk.risk_message) as risk_message sum(All_Risk.calculated_risk_score) as risk_score values(source) as sources dc(All_Risk.threat_object) as dc_t_obj values(All_Risk.threat_object_type) as t_types values(All_Risk.threat_object) as threat_object values(All_Risk.risk_object_type) as risk_object_type from datamodel=Risk.All_Risk where All_Risk.threat_object IN ("$threat_token$") groupby All_Risk.risk_object All_Risk.calculated_risk_score source _time span=30d | `drop_dm_object_name("All_Risk")` | table * | dedup risk_message | eval risk_message="-----=== ".source." ===-----||"."===== THREAT OBJECTS ====||".mvjoin(threat_object,"||")."||===== RISK MESSAGES =====||".mvjoin(risk_message,"||")."|| ||" | rex mode=sed field=risk_message "s/\|\|/\n/g" | stats sum(count) as events sum(dc_t_obj) as dc_t_obj values(t_types) as t_types sum(risk_score) as risk_score values(sources) as sources values(risk_message) as risk_message by risk_object | eventstats dc(risk_object) as ro_count dc(sources) as source_count sum(events) as num_objects + + -30d + + 1 + + $result.ro_count$ + $result.source_count$ + $result.num_objects$ + + + + + + + + + + + [#a7c4f2] + + ["risk_object","count","dc_t_obj","t_types","risk_message"] + + + /app/threat_object_fun/risk_investigation_dashboard?form.field_rv=$click.value2$&form.timepicker.earliest=-30d&form.timepicker.latest=now + + + + + +
+
+
+ + + + + + | tstats summariesonly=true count sum(All_Risk.calculated_risk_score) as risk_sum values(All_Risk.calculated_risk_score) as scores values(All_Risk.threat_object_type) as threat_object_type from datamodel=Risk.All_Risk where All_Risk.$search_values$ IN ("$values_search$") by All_Risk.$search_values$,All_Risk.risk_object,source,All_Risk.threat_object | `drop_dm_object_name("All_Risk")` | eval threat_object_type=mvjoin(threat_object_type,"+") , threat_object_full=threat_object , threat_object=if(len(threat_object)<90, threat_object, substr(threat_object,1,90)."...") , threat_object=threat_object_type.": ".threat_object | stats values(threat_object) as threat_object values(threat_object_full) as threat_object_full sum(count) as count sum(risk_sum) as risk_sum by $search_values$,risk_object,source | eval threat_object="--= ".source." =--||".mvjoin(threat_object,"||") | rex mode=sed field=threat_object "s/\|\|/\n/g" | stats values(threat_object) as threat_object sum(count) as count sum(risk_sum) as risk_sum values(threat_object_full) as threat_object_full by $search_values$,risk_object | eval threat_object_full=mvjoin(threat_object_full,"&&") + + + $search_values$,risk_object,threat_object,count,risk_sum + + + /app/threat_object_fun/risk_investigation_dashboard?form.field_rv=$click.value2$&form.timepicker.earliest=-7d&form.timepicker.latest=now + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object_prevalence?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + + + + + [#a7c4f2] + + + [#a7e4f2] + +
+
+ + + + + | tstats summariesonly=true count sum(All_Risk.calculated_risk_score) as risk_sum values(All_Risk.calculated_risk_score) as scores values(All_Risk.threat_object_type) as threat_object_type from datamodel=Risk.All_Risk where All_Risk.risk_object IN ("$values_search$") by All_Risk.risk_object,source,All_Risk.threat_object | `drop_dm_object_name("All_Risk")` | eval threat_object_type=mvjoin(threat_object_type,"+") , threat_object_full=threat_object , threat_object=if(len(threat_object)<90, threat_object, substr(threat_object,1,90)."...") , threat_object=threat_object_type.": ".threat_object | stats values(threat_object) as threat_object values(threat_object_full) as threat_object_full sum(count) as count sum(risk_sum) as risk_sum by risk_object,source | eval threat_object="--= ".source." =--||".mvjoin(threat_object,"||") | rex mode=sed field=threat_object "s/\|\|/\n/g" | stats values(threat_object) as threat_object sum(count) as count sum(risk_sum) as risk_sum values(threat_object_full) as threat_object_full by risk_object | eval threat_object_full=mvjoin(threat_object_full,"&&") + + + risk_object,threat_object,count,risk_sum + + + /app/threat_object_fun/risk_investigation_dashboard?form.field_rv=$click.value2$&form.timepicker.earliest=-7d&form.timepicker.latest=now + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object_prevalence?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + + + + + [#a7c4f2] + + + [#a7c4f2] + +
+
+
+ + + + Prevalence by Source + + | search threat_object IN ("$threat_token$") | sort 1000 + count | eval threat_object_full=threat_object | eval type=threat_object_type | eval threat_object=if(len(threat_object)<50, threat_object, substr(threat_object,1,50)."...") + + threat_object type source count dc_r_obj dc_t_obj dc_src dc_dest dc_users dc_bunit risk_sum scores + + + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + + + risk_object + $row.risk_object$ + replace(replace($risk_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($risk_values$,",","\",\"") + + + + src + $row.src$ + replace(replace($src_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($src_values$,",","\",\"") + + + + dest + $row.dest$ + replace(replace($dest_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($dest_values$,",","\",\"") + + + + user + $row.user$ + replace(replace($user_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($user_values$,",","\",\"") + + + + bunit + $row.bunit$ + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object_prevalence?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object_prevalence?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + + + +
+
+
+ + + + Prevalence by Source - related objects + + | search NOT threat_object IN ("$threat_token$") | sort 1000 + count | eval threat_object_full=threat_object | eval type=threat_object_type | eval threat_object=if(len(threat_object)<50, threat_object, substr(threat_object,1,50)."...") | eventstats dc(threat_object_full) as dc_related_objects + + $result.dc_related_objects$ + + + threat_object type source count dc_r_obj dc_t_obj dc_src dc_dest dc_users dc_bunit risk_sum scores + + + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + [#a7c4f2] + + + + + risk_object + $row.risk_object$ + replace(replace($risk_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($risk_values$,",","\",\"") + + + + src + $row.src$ + replace(replace($src_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($src_values$,",","\",\"") + + + + dest + $row.dest$ + replace(replace($dest_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($dest_values$,",","\",\"") + + + + user + $row.user$ + replace(replace($user_values$,"\\\\","\\\\\\"),"\"","\\\"") + replace($user_values$,",","\",\"") + + + + bunit + $row.bunit$ + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object_prevalence?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + $row.threat_object_full$ + /app/threat_object_fun/threat_object_prevalence?form.threat_object=$threat_object_full$&form.time_picker.earliest=-7d&form.time_picker.latest=now + + + + + +
+
+
+ + + + + + | rest splunk_server=local count=0 /services/saved/searches + | search title="$risk_drilldown$" | rename dispatch.earliest_time as early_time qualifiedSearch as search_spl + | table description search_spl early_time + | eval search_spl = if(match(search_spl,"^(|\s)(tstats|from).*"),"|".search_spl,search_spl) + + + $result.search_spl$ + $result.early_time$ + + + + [#a7c4f2] + + + + search?q=$search_spl$&earliest=$early_time$&latest=$time_picker.latest$ + + + + + +
+
+
+ + + + Score Contribution + + | tstats summariesonly=false sum(All_Risk.calculated_risk_score) as risk_score,dc(All_Risk.risk_object) as risk_objects,count from datamodel=Risk.All_Risk where All_Risk.threat_object IN("$threat_token$") All_Risk.risk_object_type="*" (All_Risk.risk_object="*" OR risk_object="*") by source | sort 1000 - count,risk_score + $time_picker.earliest$ + $time_picker.latest$ + + + + + + + + + [#a7c4f2] + + + + $click.value$ + + + + + +
+
+
+
\ No newline at end of file diff --git a/src/threat_object_fun/default/data/ui/views/threat_object_soar.xml b/src/threat_object_fun/default/data/ui/views/threat_object_soar.xml new file mode 100644 index 0000000..24bb648 --- /dev/null +++ b/src/threat_object_fun/default/data/ui/views/threat_object_soar.xml @@ -0,0 +1,57 @@ +
+ +
+ + + + + + threat_object_type + threat_object_type + + index=risk risk_object="$input_risk_object$" +| eval threat_object_and_type=mvzip(threat_object_type, threat_object, "=") +| table source, risk_object, threat_object_and_type, threat_object_type, threat_object +| fields threat_object_type +| mvexpand threat_object_type +| dedup threat_object_type +| sort threat_object_type + -90d@d + now + + All + * + + + + + -24h@h + now + + +
+ + + Indicators of Behavior (IOBs) + + + index=risk risk_object="$input_risk_object$" +| eval threat_object_and_type=mvzip(threat_object_type, threat_object, "=") +| table source, risk_object, threat_object_and_type, threat_object_type, threat_object +| mvexpand threat_object_and_type +```| stats count, values(source) as detections, values(threat_object_and_type) as threat_object_and_type by risk_object``` +| fields threat_object_and_type +| where threat_object_and_type!="" +| dedup threat_object_and_type +| sort threat_object_and_type +| search threat_object_and_type="$input_threat_object_type$*" +| rename threat_object_and_type AS IOBs + $input_timeframe.earliest$ + $input_timeframe.latest$ + + + +
+
+
+
\ No newline at end of file diff --git a/src/threat_object_fun/default/macros.conf b/src/threat_object_fun/default/macros.conf new file mode 100644 index 0000000..040eb78 --- /dev/null +++ b/src/threat_object_fun/default/macros.conf @@ -0,0 +1,15 @@ +[line_breaker(1)] +args = line_text +definition = eval $line_text$=if(len($line_text$) < 100, $line_text$, replace($line_text$, "(.{100})(.*)", "\1\\n\2"))\ +| eval $line_text$=if(len($line_text$) < 202, $line_text$, replace($line_text$, "(.{202})(.*)", "\1\\n\2"))\ +| eval $line_text$=if(len($line_text$) < 304, $line_text$, replace($line_text$, "(.{304})(.*)", "\1\\n\2"))\ +| eval $line_text$=if(len($line_text$) < 406, $line_text$, replace($line_text$, "(.{406})(.*)", "\1\\n\2"))\ +| eval $line_text$=if(len($line_text$) < 508, $line_text$, replace($line_text$, "(.{508})(.*)", "\1\\n\2"))\ +| eval $line_text$=if(len($line_text$) < 610, $line_text$, replace($line_text$, "(.{610})(.*)", "\1\\n\2"))\ +| eval $line_text$=if(len($line_text$) < 712, $line_text$, replace($line_text$, "(.{712})(.*)", "\1\\n\2"))\ +| eval $line_text$=if(len($line_text$) < 814, $line_text$, replace($line_text$, "(.{814})(.*)", "\1\\n\2"))\ +| eval $line_text$=if(len($line_text$) < 916, $line_text$, replace($line_text$, "(.{916})(.*)", "\1\\n\2"))\ +| eval $line_text$=if(len($line_text$) < 1018, $line_text$, replace($line_text$, "(.{1018})(.*)", "\1\\n\2"))\ +| eval $line_text$=if(len($line_text$) < 1120, $line_text$, replace($line_text$, "(.{1120})(.*)", "\1\\n... truncated ...")) \ +| eval $line_text$=if(len($line_text$) >= 100, split($line_text$,"\n"),$line_text$) +iseval = 0 diff --git a/src/threat_object_fun/default/workflow_actions.conf b/src/threat_object_fun/default/workflow_actions.conf new file mode 100644 index 0000000..834b912 --- /dev/null +++ b/src/threat_object_fun/default/workflow_actions.conf @@ -0,0 +1,8 @@ +[to_wfa_soar] +display_location = field_menu +fields = risk_object +label = Threat Objects - SOAR +link.method = get +link.target = blank +link.uri = /app/threat_object_fun/threat_object_soar?form.input_risk_object=$risk_object$ +type = link diff --git a/src/threat_object_fun/metadata/default.meta b/src/threat_object_fun/metadata/default.meta new file mode 100644 index 0000000..d6566f3 --- /dev/null +++ b/src/threat_object_fun/metadata/default.meta @@ -0,0 +1,35 @@ + +# Application-level permissions + +[] +access = read : [ * ], write : [ sc_admin, admin, power ] + +### EVENT TYPES + +[eventtypes] +export = system + + +### PROPS + +[props] +export = system + + +### TRANSFORMS + +[transforms] +export = system + + +### LOOKUPS + +[lookups] +export = system + + +### VIEWSTATES: even normal users should be able to create shared viewstates + +[viewstates] +access = read : [ * ], write : [ * ] +export = system diff --git a/src/threat_object_fun/static/abuse.png b/src/threat_object_fun/static/abuse.png new file mode 100644 index 0000000000000000000000000000000000000000..4a97bf68fd9947d9c25d1cb6d3745a9ce954ec38 GIT binary patch literal 2502 zcmaJ@dpK148lGHo$&7?t(r#Ll*vy?_W|)e(7`em@r7L4*(KO~_W|eWNgltksRAW+h zQIcFcMJY<6DWzvz}+I-{tw<_j|wZd;eIOL4iJSV_Rbw z3OY#gnN-0`mI`#0R-*XcCT+uTN}dcyz~ZM%nh6XD`2V3|@sDT) z!~y@-`#*^lA@MR0#{m`6t#ZD0a8an~R5B`E4)P$WJVYvundxHCW+^09Y?jK9bozAH z$VkTk9$zS#zWntYDj11~bkx6#(CXw6-1SZ+ri^-%= z@N_zhLUv;^nKM|1l)qIBN}w66;BTz!PqEX65X-cg8K7La4HU5CQZe#d;Z)(zwGe*F z_Z=(vxfbG2u{f<5-1K<=YuqzeS`STcf0$Q$_+fugqV>F7Yi_Rh(k>WmwyQ70D@6J5 z&4zoi1MIm4jt0%FYCtE;5Dmb5BE}!CD#pU-ur)W1joDLl=z0fH`0VC~hJlB!cD%WK z^|At0BHX8Uo)qfz&rK(Uw9Bt{^mXNp6v-;4CY>!7ZJ)FjP8AKfG<|v2_BF(90+V8v zk&{Wrwweu8+a%gm4fGm!)|#5mwU+Bf=(L?W1QWNu>s-<@nVziLlS4_hf4q3sMXMF| z(eSy+4dP^sTgAFddYU-By-@W#qg{kqB=Z%e4*G0ZmjQqNllW}7b-@M1T)RJ?+0?wS zR#!G;H?C>vX-tC2JbTA=)avNm!|aK|(_;i5;IOO6q}UXJn6qRmYZo7$H>H2IM(1V~ z?2d(P+w=DQdzaDmqZ1^%A7hejo4kpS;$qq={6i)zy+3E&y0kRA2){+t$xT>S+w(DN z+(Xs1Z(&`$(qCuX9_S2p4EMWt5^HUhpdWNRZ^Y@OxO;c=d3{FtoFZ5ByaR2pi;Ci0 zZYLRKwUw(2#S=`8W6&-2I_;%<)*q3swLuQ9UPW@)xX0IB?{EWsQ64HW{OYFoua^p6 z+NtCh0Q-eKt~(560J>{^8{*R%gyS8YrQGplo+45*oZ(z*o3YLdE*mWBeO9@QbR;{C zjRM9`1;cZ7xYWqV&a=9*NQ3+;s^Fa8bIvx{{kOr3Lb#(QMr3iO#>DTI?t1&My2AH^ z?&1=c&6`>lp8>n)lPMZ&O0ScbYUP6F68q6c1uAt*@loScRyJ^~Bey@Mwb8ldzBTUw zjbPvG<;j`dC;K%s=$8wIcjoo`&q<0hQAgb#T~u92Y*=!}GiH(`VDfB38eu%zo&=^*{IV-nb`S5mFuKuCbR}-tEmAHZN#u^)zpR+x9=* z>GHz1UA;3nm1Z>fRfE)7)K7N6s!(4LnPH1#%X`urCeoNjC}sPoIN$W5z`D_6;1Z`z zvsPGPM+E*zb{w_$xN+prAHKhtEU#t`8XvZbLA|Ia0?C>u#Or)^(K*Ztr_&2ulGln5 zpDNSzo3^bC2L4qxN_Z21IW)Nw<~0@O;kUF}go*7i!wjHyNc0yp5P>Cb>pwFn(wtY$ zA^LY%X};%^dS1Lf;1N^E&&>E3)^dtj*s(e^^%n&v6js-vzLw%KxnVGWV~Ada=*DMB z4yrXc;w8GHu|MvqGYh?KZQ28w<;TWP>5XPp`trrp*n#zA?7E{P#;@A)87+RbY5r!S zjdNAk?ivQ^g;(F;*dA!-Sk&A|FSR)bR^LT)O(LM+>=W;+*^2vP5ql$pbPTrB?;GA( z-BmVddu6fl!xw5)rKvGmoj0#KDiF&qV7;t8nl^fG#|ew4goUdSRxc6tetWr1@JuQu zD}}Rja>=cza>`R1@0u%3mhm6QE|m>MGy8t28y(VkCzTG4WZlm=y*LsaT>9_dIs*Dc zZjbQNr~LBU8Tlm54U6AB?_mQe&olP3dSU1IWnXodZb+UWTBL3VzZQ>Nw(3@phs+*q zSEAo51gcj)p*!<_ccbx2oSJ5R(A>_;3bU{n$8;CfIBbpS!C)Xy{27FSf1y*u$%s9| z1->K~S)85!bMx-(imC9odCq;G;`wRUNR#cFi2nJ=dw_aNc&1$~qn6JTt}iI1knx5r z#iNb+o6+V<7Y5p@$U4-?fPRvk|Ev?y<0A7tq%$e!`Lopng;!oLM0OrK zkqOlHi5`~u`Ci|`SHxzv|080ep4Oe7P#$~NbqKMYYV-jCFX%y(rxb8)KiKak9ZsmS zx?LvsuP<;{p>;}ZR%nd6)x+kTe#evYL_Ol=*WLLQl`4l35faY!@bA4=d%Rz!nrIT? zhJuquA44jAc%6f;AJ?GY&O6a2)idX*rI+g5iiJwHv7j=2UIu+2H+;(k`57rr+*~+Z zGpp<->wSA-m9vlKii7uLryfFgkMFljhjM`YClkZGgT}85t&|shQMW+-?WuM=ZFcXj0J$hfAn_Y$GWdK$H literal 0 HcmV?d00001 diff --git a/src/threat_object_fun/static/adversarytactics.png b/src/threat_object_fun/static/adversarytactics.png new file mode 100644 index 0000000000000000000000000000000000000000..83cf8793e81753463932e382c1d6d174751ee2d2 GIT binary patch literal 2174 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 literal 0 HcmV?d00001 diff --git a/src/threat_object_fun/static/appIconAlt_2x.png b/src/threat_object_fun/static/appIconAlt_2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f10805e4bea3daec4008296de3f5b8254c335154 GIT binary patch literal 2231 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 FV1oUH72f~= literal 0 HcmV?d00001 diff --git a/src/threat_object_fun/static/appIcon_2x.png b/src/threat_object_fun/static/appIcon_2x.png new file mode 100644 index 0000000000000000000000000000000000000000..748af39a6b1013f6d7d3a82241fb8326e60e8348 GIT binary patch literal 7055 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 k`A5k1HGdbqE(1CB@pKmX9WgVp|1=b> z1C9tN11e%EQ&|*{Z9rv{GK$M6tzfB$Bcn)l>?Bs~{4vfu=e>LH?|k3)TkkpVXmFtK z280y?27_(j__27J)ld5xtk-;ZFShz>7E2X7TonSvt5O9D5XKNeaUj5v3KBpbC=l&W z9tPcEuyqa+ez+=}8$c66Qk+1G!KtNk4I2h?_f*RT!o8phhyxQOGCF#xvl|UaM09i* znM>fxnV?wWm!<$i(gOLyw7o(%5!%xOa97hb0#Z;V0MybXnUbcaqd(}@-+~I~1_Mk;0Rm(k1uG=F5CEzhjz}T6kcmzJi9n>{31mEhf+Y}X1Xmh~2z-3d z8gB|wJdMZl`RGe?qNBwsm7Iphr>3UjQk`*-A^}fyb92KJNO%$nt3hCu`(-MD8Y@%U zttqfTrBES}t0a&N&?*YzpcEAyt%>xv6r}P`vNGkzGHD8iR}18LB95R%NE63B!ghebzgbZ`=hh(=_QSw0jO7jH6|N+hyfy%}t_ zn;U`2^l@{gu-WW2E(;Q-NI{uujVt<{Oa3fZI}lR2#xo04NcMpu9|a@@J|s?)d_ES^ zXZ1dEMW2tw`LkTSCK$Z7z5mtjHIrtBwA)X^t2ulce^92Gd4*=U-y+SeU@*7^hsEHl zXP#9*POkMr4Vh!$!MdTFE&$<-mdx8hE5zhxm{5m0@%0MlqSqx|4!jsqpH-KAZ~ooz zqH#8R1uMQ^X^RxZuKx4&;;&bu<*Y35m*sLi755&g`1N=T7vp(th}$-C*`V)aRq*tI zi1aC%y-#|1irpD|^FJ7vz1$G%-q(QfvW^I=Hk%`4SdQGfZ5XOZ{L)Kln0PnQ3+60n zDWipw$%Z3Dy(2cyY8eD}jgJX`$^kGO%o%Vm*jHxhw7qSk!AA81^m)hDbG?nnyOc*R z-HnFXWKf=u#~(5(Hb=)eqsk-7CX0QN4&!V_IYrg@^$nD*^G4Sj;f-}V3F;jAUyvy_ z-_;RImikl5_f+c1x3eCdMLwBdsDDT#MobSR4f2iqtC^*T3jVYTSkolD8=0G;q}Yrz z!9eD~kvl=Fe?~3V4C8=?$3@#1v-7NYr@9jUE@Bg+@8b z*#RNZvx?=X4Z@?hbu(r_+|S6mhmn?sg?YZ4$IlZ^T0UbQT(sy#Wi0g4D~d3B2dkIj z&J15mG7g-674XaG3(qatoU4>nIk4mho9fu|6;I zD;~=jwtfF1YP_bgmNAEINsMU&x;IR(D|BXzTeRsE^%bFR9LyV)SJjLXO+X#Hv)-KC zuDEXKO~*{y)6tjm>e)F{asg%wuc9DpPx5_-sJYr>-%=W`Jm}okVVY4)?aBeK_^NJM z#eOpm!g?rMp7!cn2KkgaS;;5h;?5>PijZyJX+KnnW8^-r-#vGlk^h)FiEwR#l6QXL ze{>_Oa?tUA$G_No78$lH2E58?0h9mrG+yd(D7cOB(HJ7<;*Rj60o^j}ABo9%zY~5aM z?=ost_I=Lb3k%K0qsxCgbB`9VQ_K{h!mJJn*PXbM8-#dN5>qN1>A1U{+7Qoc?ziRU zMn+}uvYx;x_SAXd_XZi3X75hFUi{J_E8hYq+EjFzmY*CxQ6FcKn)9&fM9q(L4efg` z>!i((GhLQpJ7)844zD;7J9~|*Y%5&-fh!4!zyoijq@!agd)idPtErEUne?7C@~9`s z-=FARj^Fh@(=f0YH0Im(m(C%@{)W-F^y-PHjBfLFLaM0jGlTvwN)!AW;`-h6O`cpx z@VljGejbyqt4Hr&ot>Et@SD2mbGWbF9TVCn@R+J_oK19bfRT>%NDqcCku!dT2r~_AqtcWmZ=05a=%S^xk5 literal 0 HcmV?d00001 diff --git a/src/threat_object_fun/static/cloudsecurity.png b/src/threat_object_fun/static/cloudsecurity.png new file mode 100644 index 0000000000000000000000000000000000000000..50e83b5c94d01746c8db83e2d06c95fa4fda1eea GIT binary patch literal 2397 zcmaJ@dpwl+8XuQ5NR8aDy=L4h<|2a`#$_&y%ZN#GJ2K6@m^AknL%B?>m_0??rV^Tz zOBa_=L>;uLlxkZ=o7SSVQrOh0Lv3fKO?&=0o%i#3-{0l)e8124d7kedZ&6rifS!)I z4h#m<3#3z-%9XBq;abY?=INFIdJ=2VX*zl8~QxiORj|8iNErg+M7J zx#!Y0WMgaI|hr#VBMUtI3m`A=z;@2KS*UZ zF(;A8r22o(r96?4$q*zYVle6H>FD$gXn{BhgCh_K7_1A%#l=|};VjAELoBH?UxHd< zpn?*%m@9<10zRN(WNj0qLL{V8>0c%AgkNa+lFw~YHVh+W2{AY{R#nncAcOJ$LwUR} z(GrLW{;l_a5=$a7gdm0qN(8B5wsLTZC{-#Uks=0JkU$(E5bRj$Vpy^O5=fE-LV!Y1 zb*^fpe z5U>=AKf%L|Mx!lZsRDK?59C8jSkB*A%2%-}L-2&k%v4a!O#?apVgV2MR5+3QbuEOi z@_oi~zOKdZt5}Ru3`RBH{~GtwmC{41?HBVZ4`1vL@|B(!E6r`cW=|Ciw(M3Q)h|N& z=w;k5qH#LHI@}_cjL!X$nEfDJaomqb_0SE$>{Ua@e+Rgh! zLRh7%xyS#i4Zm3b=Bn}L>rEl*Z`M&qTYiW;edg6aciy(z8nm+Y;HGe`Kgo)x^_FK# znTKK{)Z!*>JBG}LdrM-cLmd7MTr*s6Y|L5I?hX#8lzEPKhsV!EKHX-KXHxU+{6w!w zYs_3tA1|jn>o9qdMBnyd=KGiO`&I*w9TUS0=g;|=HkSv9 z4sq9L8|_6bJE7Go^6qNLo6)-%DW`)P<*0UNnPIqddr%ZFYPd-E_|NmZ zHa02DP*+CE3Gn91;DlJjg#JBt`IGI`DpxauX@yNL?x01b4!Gh@^)6u@Y@zm9A0>Rm zF+@-M&Va4H5u<~@CN8=ockWT;7RtvGFvLl_yIH4Or?1{Qbp81e>w(6N3zQbiEhzmo z>)dwmLUk7ZiE!_HeX#KU6;0zix4e^zkAR!T3C1&?r?T_lDdK!f-5?v7!1M5E%jCNr zxUp}H+6(5jl<4FCLi;wfCl)xTQvb9uQLJ-Y)q1o^t$%fgZNc}GDXfRrfSbU%o!7%( zS?V&2hR@g~M2?yu{js6S83wHFA%O79b$J|?)CNx?_I^Jf~cKGSm zsYfBp8Y^Wdk1h`xI!EdY(z}|QQM+Sc%-Cl7>0ggz~k8=8eLEE4e=EB?F zCpcNH-)h+nraF|hHCjY(bbIh_2I+~0>jc`*E*>kJ228xzW8nMw(FCLcOmt)FggT@2 z?anh9=2h|h=8iP1Y%S4dv41?jF3SE$AOD+*_*mAus*ht6O zS8gC2I_O!t(!N>Wr?Z--9|pcb-@0_`W+o!uzvUkX!cV*1RtqF45E|t&%8R1)YClEZ zoi|Me^zbBF?y1nJhsXc$GCb%x7xBV6vv(O?zQ^B@XG!Y}m^Yu0(RhmZZ+vQ2+M6Wj z=EM4{p9S8MzFk;H9@wHky1fYHJ+<8{;_~U}=mT0U*G=G|{TW&B7swTBbJ1{H&qhu> zoSwFI>VdC3f6;*yf)Ml2m$Rc3+gxXEKiN$QkawOVH~d5xbaG@fj<;t&&cDqVy88qx z>&Q+h3Vb@W5yJK8T>S$j*z5F?l4Jk-Ry8e{==^t+5_yoe>W3$g7D{a(C+z+Yeg@13 literal 0 HcmV?d00001 diff --git a/src/threat_object_fun/static/compliance.png b/src/threat_object_fun/static/compliance.png new file mode 100644 index 0000000000000000000000000000000000000000..479c1f20c42ead25b0d13e54f436641590a9bd15 GIT binary patch literal 1841 zcmaJ?eKb^Q9KM6oFwxQ1w%E37SW7bZ4vqO>GGk^iG18dOmTJsgV`%1%nJc3-B(?ew zvI>=q)E1JE)yAe(p-8pTi8_+7rBb_Xr`@gHy;IcwvG$&G@B6;L^E}V*^F4P*SZJUP z$({rNfQ>MSFUHp((`z{m|E_pi7l>!ZM`N*MsTKjaax?}3g(|565hGH0N@54% z3jpS>N=XzJB?@85P!&aL!cg=o4bBDtUq8J@Doa2xFa}X5)ok+kx$|UDDQA--X(Cvp z;URI#pp9B2d}F9YwlP7*l#~6IfWCSbE}%j%DX3SiSL;}MHu;?{3*Vc}5E*<2!4lZy z_d!L8!ayFXML-(G+e1cO41;tgh3XA2rcoDxo-maT!88c=_JFA@n8EU-f)fuJ_okJ{ zvc&v=319e$O^(Ab4GV&jlandQUKCWTfT&C+6M{VI1-O7#J)!^FtP zc>hyaCrQyDkQmXSNm?1+xL7BXD-DaMMWh(2m7wVQ$ts4$p%|)*Lp30eXQ~g-mKUW}NGGQJsfXVO{ z2n3T{J}OI6A!=-rEC0x4OvyD3gi3>Z<|A6=21Fj9MOEOt#97LzW1&r{H^G%p9gFvr zTnG;aGPU<#?VdE@Gi2I+7+(DFVf+y_KJ!|9xHa~l9K-L-VIiL@(f2($crULHwrxYY z=W-TWo&eSouM;GI;ffRNmTpY%ydW!izCwf9CIb>pC^3|HW2Be<<35#Rg37Mm>+|l- zpI-I*`^*CWy=|=er`>A_em2kB5}$QbOMdFg86U0g`}vHetbJLyVfX8q_Y-#=deQiN zsNMKQGcl7?5eJN%GJY^nlkLOs%@=EuulANJgUGcJ* z_Sq975B3amB+gAHWo@-9jfv?Ih@4Rt}Z74gN7SlaVjPBDK2X0&>j)O5Wh zJ)oPdty}lDKFi(B*}O-`_$s%FxK-!nJWd$AYta#zUf0NDteZZ!?WtSlFSE~~o2r)* znu?ukgswR@e(mYU8-i{3E-p%~Xbk)A7)urto60adcX122EJG3P?rxb-IZ#Z0L%xfx ztBo1Gew&}$;!@jpGKBlRO%}J}jpLfA#LSu#*~Wg}!$Cy=V6|j?m1<5aU7lb?$Qw;> zwKG1dcG(qg*fD;Z?HkVRlbF@6W~(?0kGq~KMY?CPNkPGGU)7dnzY2i%pBF~X+U zh46~60-{Z8B9UCO`C)pqS?1cuNy7&n2`}Mc)WWJe&6+u8JYGtCRcXb&Qu`cIGBZ2ksT9FF#>w0rAIRoq_0=bYLT zoVN|SoI3BBU)labhmqjy<{@2I%l^z;fg5^-2DgH$sC!G`(vwwDh{eLkWx%yJmm|X; z6OI&KEb97o6=qvJc{SI3g?g3FCKQD7tNqty`~#@= B%4z@r literal 0 HcmV?d00001 diff --git a/src/threat_object_fun/static/insiderthreats.png b/src/threat_object_fun/static/insiderthreats.png new file mode 100644 index 0000000000000000000000000000000000000000..75f0bb2ca271f102d0c2f4210f9eff9dbb2469f4 GIT binary patch literal 2396 zcmaJ@cUTko77c;Wq=;0JGA5|h6hZv0IpkgS}i!?<5Ec{^baz!?6%kobtgzTNQE}fN`sVv)e&xI8+;i_ee@tFTu&=hJsU{2t z)AskHGUThD;#F6be?zBF`O2525RC<`6U0Cgwg`lIM+>%qfIp8N3o<}hn@`Q3U4Cdx36|y-AAOvgyW4U~H;1($fQQlal2GJP=|7QeGloOqRMMKk<^~d&M;d3498H65NrW zMX~5107W1I0Ro!nz`;3T0cR2#N5nc2aQ1*B7Uzt?5-?bz0~SZdx{w`lz?TOp&nAkF zAv36}zvPmi+>vn*BqU=n5{U#Y!J`GDSPYItB4MzO7)M73d4z*Fg%7c%4tz0cfq@E& zIU=qQ;tKeHf|0#NkPNva|z5qB#Xy;>yT0iOydbHAa5y4soO zjFoF35QyK_@);ZbeJzgP)q;_W!6?T2KjU7wl6y$8{c2wM;j8^YzTER7xw)$v({f-i zM2|n!n<@QcD&l_9L*impf{iT9dqOj4y^x70wLS5w!k1JIm)ZiT`z62A0@4T~JO zb}Id`8iVb3U`kbm-r?18L-$sMq@$v8qr%ML>kxxX_?c%0fJTsdQHsI)iWN?i6Xw9; znFimDoSO|v;YiDf4nmF{%r~l7t#{w%%(0@}gq07-paX&1quO7Yc}w%~=uXvO&h88g znK;Y$9o)xoW8#}d|2@S;-0XnYXz07B^a?~}mJ?b+hS_opp!9K_(b@KjJnbYkqrkt@ zZJbQtxxF)R(Ht(Ew0F&1_?@z<2-#?%{UjitxARVqLI<|rItV)*m~sUlp3tAKR6|I7Uv|>> zh4*S8`A$mFapyKP!9(abrGKb&PpgoN|bxg0r_@zfjLD!WFkM zW;>D!pOx5kI_FQ-c-O8pvENBoz~ zbel7b!)0|k^O0~MG?@Itec&LuSaR)Wn^_+o^lRBHJ?b#baWcM4scgt~KzG1>%tNJ( za&YC=tX8Y+dJn@9+eWZ1!BckZ{27F z$IRn2-GHGyUg#6!p+%E3RW;`<_l@Aw1BUczGiO_QwmF>v243j9;SH=7W9_cq!0}ol zb_9;0T+H^mQCHV!q$!LqS!*?I+t!#`;p_k_A(RC>Sjwb@Wm5uH9)8+o^zrh!X70*A zLnQ{0hnH*SpXzV;#r(q5lWAn4&0GJ}VH>y*^}LA~Yqu&0-ZwmghOR}_;}gepOxuni zZ=3e`9iqGbx_3vI4go#%pQh2{h1R!hJCc%Lgk8PCq3KKx$DZ*WS!!1iX2u)bIL&Qim6W0zJVD{j>v(4}R{y&3b8}Vi zUEvJj>h1$a^N0n+FR=06|B;;JI0zSvtQ5S(?4orVJIp~bYRG3gW`Y3pB7AQ I_KC{)2YTbi0RR91 literal 0 HcmV?d00001 diff --git a/src/threat_object_fun/static/malware.png b/src/threat_object_fun/static/malware.png new file mode 100644 index 0000000000000000000000000000000000000000..c6a1fa69d07d374dc6d6ef8f29f3550402ab7ba5 GIT binary patch literal 1984 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 literal 0 HcmV?d00001 diff --git a/src/threat_object_fun/static/unknown.png b/src/threat_object_fun/static/unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..32ad60c22abd4c12d79a11adafabcd82cfedcf1b GIT binary patch literal 1892 zcmaJ?c~BEq9Nr)(q8utkY!#P8G+;?~(EDkYW)xHtt*!qRaoVnTsf4VH$2ay^oPCZdSOo?VYd z1Hdqeba5)@)46lBrZk!qL;fl*u<%!ZgO_*0Mp!BKRGMTgjt5X^%(JO&I7K4ik1Nt4b? z6iEhs5hp%bi{nNfoo=;SY1YqZm??t}bGckP#Go@6kpv>rY&YPDEz)473@M0Ev)ZIH z;yTO#x)qT$%!2dDM5OL==o}LyUBo2Dwuj0xA^$57q16qRn_B`Yzu0 z3Y%4SBT7$1&6vfcCK{Jcal10|geDZhF_Q|zvWBXt)M7Yh)?!9bD0Eki15y=;T4!(@ z!{4wJ3ZC3x#u0-Wm5cafLWic)X?P+@6gvtMi3Kbc8-~RkL9AHJ?=3Vfp{%FL#>ZeA5_o`ZF0wn!8#B<@%z30NZ%QyPYKfZ^{d9B@@Z=WCaB@P{);3_lstn$f$7QSNymhrxk^UdCTv z-t?p>=dTKdy>Cj=O-j#(%wgk@qQ~`}eiyh>LsqJRR~qqh=Ip1t#_0_GvFV`)Z=Uy1 zjwm>^qq|OV2B=&7dcm}bycNX_vw|JxgDT}gX>nJPcDXBjMrdbFAGBoO&OYX1=EW)X zhi=AGz@7fn%hcdh&D^hKxvS$?SIrl<+DopJgO=Y7d@%FGFMmhBO zN9?#S{Ju1aUDeTW;S5eWrg9eMgt_PiEf&csQpIUO-RWO0(BtL@&P~h{j5n5(PMwTvWKPU-2uOZw zYotv;q4#CqmG)a3gXe5BSQe?6!MjF{rRH#c+60_h$1Gca<GJ^N%^ zTSm+ChYjZ+RBg!G{o-P=y~uH<>T8JyT+~%e8o4oWovftk8C@ObAw`m+7UKgwJa%C@OIJPXW6qz+SW zQst=R%Fr!eSXvf%RwwWAq*CGnsx+Ak?*vL39&=hL8-&?D%YLiaSJM6Z06KYMNd4ha zN+}pVtF`o4w)eE<2HpJxu#G`031q&3P@uEpFLhn^LouZ{XhYap46Os!*gJKD$r&7c1Fn@-X-^cPcBXn Jl?hUF{{i<|*!^fQX_50fDNE z4?uYel#0p`g<7$25QGI4j z3=6QfTyF^gfOSwHH{7rW8ebg7@cn$QF~G1mqdXBBp^QaSBpMj-lPRSz7^INI!Qrq( zc0hd(_62}7o8*xqR3r#xK}rQ#VvHf{6e$_8*fnhTL}u)2UySl zLh&J5i-yC$>;0d^+Q9m`l1YczyHWys8hHS%Ow#@8qn;Jd!0ciW*Dq2x zI=g4!)F{>AEISH#4tO?IXXM)inq$9QH1jZD*aRM3e6X(7a>A2w(X`1@#R4~QgNKjz ziisnsw(b9n^?mxl`tZK`*U9cZdIl7FWcg5jv*X*@k6Xj8kMqWFD|!o{HXQ$pmv1!9 zMNigvm;5L`c;-oPM&VxHo#MNMbosWo2h96}k-oE5Yje__@BUPa37N?@jVJ4aTQImb zu36%B${Y#WzdH1Nu3C3FbkRdpP@ddUfAZd|@;2)JGKXlB%uMEN z2e;X|8_5?>e-(LL{jkd_hU!)joLwiArl}dlwN)2ek8bI6`d74*NoILjhyT=rb7cz^ z%gwHw?Q_uQBws(peIe(YOYILAineBx!n0ed&cGWjv|A}9UgbT2J9D42#${#=!o!?6 z*CNcui>uTQ9bMvqJlER;yD+reI~#r!e`=Z{E+czHcUJda2*|eYYcD@ve)YvPz)o0^C@cGt?-N2!+r_Ks>pcI_U9YDz21|K8x)A@dt;lZ|)2u`0x8 z$B?!?t~lMt!~PAEzHPE}iM8{W(5n8du9$S*pySj&Y>ozlMo0r+@NN0t9^ZksdjJ7$ zdBd?&zuJEE+P213V6j|=$nFty?s&M7iy{>BLrD*uM1z(VM||~cC;K3rBf*6=!}#p_ zu}9-PMtA1)F9##7@+52VlOClmBi04xl|Vdp{#*0DYjZea@jlC)THLMLuB`bBMTx~V zhzxqX&K|6cIyU<}{Y^r7QJ%-GY5s75`AC+{pDN27 z%t~*>akeaG_Qm-$Se6Jwu3oAUwTBPhAX8>0ReFl`iNwit-mC0AC8kpvMn}P^vL;~K z=12>Z`t@hlq%6;WFP_+6)v6_2aVqnkwjDliRcQ5}C zt9aJb()S0#$xPLeC_LeKyj4mXbu0J@w zkYiKV-R5607Z=&%bhd~e;b=Xf?=0xl6LG=$<9R)z+R1O3jw2Cu(pQ}o3pyIn4j?!KacHFZqD%7SbuBB`rSci@6+T~+ufsZVbX>} zV;9Yn#wMD+5T?N30P$XnU4Hz!|Lg~?&HC&YuWpmQXnj2|)#uf+8}saw*->Naf?iih zs28x+2XE!7$I*lAldi&>>xj