├── requirements.txt ├── README.md ├── sigma_manager.py ├── Combinear.qss ├── mappings.py └── ThreatHound.py /requirements.txt: -------------------------------------------------------------------------------- 1 | colorama==0.4.6 2 | evtx==0.8.3 3 | netaddr==0.9.0 4 | numpy==1.26.2 5 | pandas==2.1.3 6 | PyQt5==5.15.10 7 | PyQt5-Qt5==5.15.2 8 | PyQt5-sip==12.13.0 9 | python-dateutil==2.8.2 10 | pytz==2023.3.post1 11 | PyYAML==6.0.1 12 | six==1.16.0 13 | tzdata==2023.3 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Threathound--logo](https://user-images.githubusercontent.com/54814433/209755888-4677f99a-760d-47ea-8764-6994670805a7.png) 2 | 3 | # ThreatHound 4 | 5 | ThreatHound is an advanced cybersecurity tool designed to facilitate efficient threat detection and analysis, windows events logs. it offers a user-friendly interface for managing and analyzing security data. Key features include log analysis, Sigma rule integration, and real-time threat detection. 6 | 7 | # Key Features: 8 | - Automation for Threat hunting, Compromise Assessment, and Incident Response for the Windows Event Logs 9 | - Downloading and updating the Sigma rules daily from the source 10 | - More then 50 detection rules included 11 | - support for more then 2300 detection rules for Sigma 12 | - Support for new sigma rules dynamically and adding it to the detection rulest 13 | - Easily add any detection rules you prefer 14 | - you can add new event log source type in mapping.py easily 15 | - Sigma Rule Management: Seamlessly manage and process Sigma rules. 16 | ## V2 Features: 17 | - Faster!!. 18 | - Saving of all the outputs in cvs format with full details. 19 | - searching functionality. 20 | - Log Analysis: Analyze logs using custom mappings and filters. 21 | - User Interface: Intuitive GUI for easy interaction and visualization. 22 | - Command Interface: you can use command only. 23 | - Data Visualization: Graphical representation of data for better insights. 24 | - Real-Time Analysis: Process and analyze data in real-time. 25 | - Customization: Easily customizable to suit different cybersecurity needs. 26 | - Compatibility: Cross-platform compatibility with support for different data formats. 27 | 28 | ## Specialized Features for DFIR Professionals: 29 | 30 | - **Forensic Data Analysis**: Equipped with capabilities to analyze forensic artifacts, aiding in digital investigations. 31 | - **Incident Response Toolkit**: Provides essential tools for rapid response to security incidents, helping DFIR teams to quickly assess and react to threats. 32 | - **Timeline Analysis**: Supports constructing and analyzing timelines of events, crucial for understanding the sequence of activities during an incident. 33 | - **Artifact Correlation**: Facilitates correlation of various digital artifacts, aiding in the identification of malicious activities and breach points. 34 | - **Log Consolidation and Analysis**: Aggregates and analyzes logs from various sources, providing a comprehensive view of security-related events. 35 | - **Integrations with Forensic Tools**: Offers integration capabilities with popular forensic tools, enhancing its utility in a DFIR context. 36 | 37 | ## Ideal Use Cases: 38 | 39 | - **Security Monitoring**: For organizations looking to bolster their security monitoring capabilities, ThreatHound provides real-time analysis and alerts. 40 | 41 | - **Incident Investigation**: In the event of a security incident, the tool's deep analysis features enable rapid understanding and response. 42 | 43 | - **Compliance and Reporting**: With its comprehensive data handling, ThreatHound assists in maintaining compliance standards and generates detailed reports for auditing purposes. 44 | 45 | - **Educational and Training Purposes**: Its user-friendly interface and comprehensive feature set make ThreatHound an excellent tool for educational environments focusing on cybersecurity training. 46 | 47 | # I’ve built the following: 48 | - A dedicated backend to support Sigma rules for python 49 | - A dedicated backend for parsing evtx for python 50 | - A dedicated backend for match between csv and the Sigma rules 51 | - A dedicated backend to match between evtx and the Sigma rules 52 | 53 | # To-do: 54 | - [X] ~~Support for Sigma rules dedicated for DNS query~~ 55 | - [X] ~~Modifying the speed of algorithm dedicated for the detection and making it faster~~ 56 | - [X] ~~Adding csv output that supports SIEMS~~ 57 | - [X] ~~More features~~ 58 | 59 | # installiton: 60 | ```sh 61 | $ git clone https://github.com/MazX0p/ThreatHound.git 62 | $ cd ThreatHound 63 | $ pip3 install - r requirements.txt 64 | $ pyhton3 ThreatHound.py 65 | ``` 66 | * Note: glob doesn't support get path of the directory if it has spaces on folder names, please ensure the path of the tool is without spaces (folders names) 67 | 68 | 69 | 70 | # Demo: 71 | 72 | ![tool](https://github.com/MazX0p/ThreatHound/assets/54814433/550e0655-806a-4d7f-80d7-fa87284ac362) 73 | 74 | 75 | # Screenshots: 76 | 77 | # GUI: 78 | 79 | ![image](https://github.com/MazX0p/ThreatHound/assets/54814433/fbf8cf46-ce10-46f2-9af4-ea239b0bb5b3) 80 | 81 | ![image](https://github.com/MazX0p/ThreatHound/assets/54814433/009f9f31-2781-461c-8952-cc69cc7653b9) 82 | 83 | ![image](https://github.com/MazX0p/ThreatHound/assets/54814433/5a0e1155-8663-45f8-a37f-6b2c9085c000) 84 | 85 | ![image](https://github.com/MazX0p/ThreatHound/assets/54814433/fec9922c-b00c-4dd1-910c-7d25e06f63e9) 86 | 87 | ![image](https://github.com/MazX0p/ThreatHound/assets/54814433/7ee7183b-c4d9-4a42-86d6-885c5857ad3b) 88 | 89 | # COMMAND LINE: 90 | 91 | ![image](https://github.com/MazX0p/ThreatHound/assets/54814433/b30a70fc-4e9c-4a27-a556-25976f072714) 92 | 93 | ![image](https://github.com/MazX0p/ThreatHound/assets/54814433/11f71030-e1be-4a0d-bf6f-731e4b68b774) 94 | 95 | -------------------------------------------------------------------------------- /sigma_manager.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import yaml 4 | import glob 5 | from mappings import sigma_to_evtx_mapping, is_queryable 6 | import platform 7 | import shutil 8 | 9 | #from sigma.rule import SigmaYAMLLoader, SigmaRule 10 | 11 | def get_os_type(): 12 | system = platform.system() 13 | if system == "Windows": 14 | return "Windows" 15 | elif system == "Linux": 16 | return "Linux" 17 | else: 18 | return "Unknown" 19 | 20 | os_type = get_os_type() 21 | CurrentPath = os.getcwd() 22 | 23 | if os_type == "Windows": 24 | SigmaPath = f"{CurrentPath}\\sigma" 25 | RulesDirectory = f"{CurrentPath}\\windows" 26 | else: 27 | SigmaPath = f"{CurrentPath}/sigma" 28 | RulesDirectory = f"{CurrentPath}/windows" 29 | 30 | RulesExist = os.path.exists(RulesDirectory) 31 | RuleFilesList = [] 32 | Rules = [] 33 | RuleObject_list = [] 34 | IsSigmaLoad = False 35 | IsSigmaLoading = False 36 | 37 | ######################### 38 | #######rules array####### 39 | ######################### 40 | 41 | #['C:\\Windows\\System32\\', 'C:\\Windows\\SysWOW64\\'] 42 | system_utility = [] 43 | action_reverse_shell = [] 44 | 45 | def remove_directory(directory_path): 46 | try: 47 | shutil.rmtree(directory_path) 48 | print(f"Directory '{directory_path}' removed successfully.") 49 | except FileNotFoundError: 50 | print(f"Directory '{directory_path}' not found.") 51 | except PermissionError: 52 | print(f"Permission error: Unable to remove directory '{directory_path}'.") 53 | 54 | 55 | def directory_exists(path): 56 | return os.path.exists(path) and os.path.isdir(path) 57 | 58 | # Download Rules From Github Repo 59 | #For me: the code is Linux focused 60 | def downloadRepo(): 61 | github_repository_url = 'https://github.com/SigmaHQ/sigma.git' 62 | os.system(f'git clone {github_repository_url}') 63 | if os_type == "Windows": 64 | if not directory_exists(RulesDirectory): 65 | os.makedirs(RulesDirectory) 66 | 67 | os.system(f'xcopy "{SigmaPath}\\rules\\windows" "{RulesDirectory}" /e /y') 68 | remove_directory(f'{SigmaPath}') 69 | else: 70 | os.system(f'cp -r "{SigmaPath}/rules/windows" "{CurrentPath}"') 71 | remove_directory(f'{SigmaPath}') 72 | 73 | # Check Rules if Updated or Not 74 | def CheckUpdate(): 75 | # Check if Rules is Exist or Not 76 | if RulesExist == False: 77 | downloadRepo() 78 | else: 79 | # Check Rule Update 80 | DAY = 86400 # seconds -- POSIX day 81 | if (time.time() - os.path.getctime(RulesDirectory)) > DAY: 82 | remove_directory(f'{RulesDirectory}') 83 | downloadRepo() 84 | else: 85 | print("Rules are Updated") 86 | 87 | # Get all Rules From File Windows: Updates the Global variable 88 | def GetRuleFilesList(path): 89 | print("[-] load rule (" + path + ")") 90 | 91 | IsSigmaLoad = False 92 | IsSigmaLoading = True 93 | print ("[-] loading sigma") 94 | for name in glob.glob(f'{path}/*.yml'): 95 | if name not in RuleFilesList: 96 | RuleFilesList.append(name) 97 | for name in glob.glob(f'{path}/*/*.yml'): 98 | if name not in RuleFilesList: 99 | RuleFilesList.append(name) 100 | for name in glob.glob(f'{path}/*/*/*.yml'): 101 | if name not in RuleFilesList: 102 | RuleFilesList.append(name) 103 | 104 | for RuleName in RuleFilesList: 105 | try: 106 | with open(RuleName, 'r') as Rulefile: 107 | RuleObject = yaml.safe_load(Rulefile) 108 | RuleObject_list.append(RuleObject) 109 | except Exception as ERROR: 110 | # print(f"Skipping the rule rule: {RuleName}") 111 | # print(ERROR) 112 | pass # Silently skip the rules with obsolete conditions 113 | 114 | if len(RuleFilesList) > 0: 115 | print ("[-] load sigma successfully") 116 | IsSigmaLoad = True 117 | else: 118 | print ("[-] load sigma fail") 119 | 120 | IsSigmaLoading = False 121 | 122 | def GetIsSigmaLoad(): 123 | return IsSigmaLoad 124 | 125 | def SigmaRulesParse(Rule): 126 | print("test") 127 | 128 | def MatchRules(Event): 129 | matched_rules = list() 130 | loader = True 131 | event_count = 1 132 | 133 | for RuleObject in RuleObject_list: 134 | #print("Scanning the logs: [\]\r", end=" ") 135 | 136 | """ 137 | if loader: 138 | print(f"Checked event against rule: {event_count}, Scanning the logs: [/] \r", end=" ") 139 | loader = False 140 | else: 141 | print(f"Checked event against rule: {event_count}, Scanning the logs: [\] \r", end=" ") 142 | loader = True 143 | """ 144 | 145 | try: 146 | if len(Event["EventID"]) > 0: 147 | if is_queryable(RuleObject["logsource"], Event["EventID"]): 148 | detection_fields = RuleObject["detection"].keys() 149 | overall_match = dict() # dict that contains matches against each selections 150 | 151 | for detection_field in detection_fields: 152 | if "condition" == detection_field: # condition 153 | condition_list = RuleObject["detection"][detection_field].split() 154 | 155 | condition_list_len = len(condition_list) 156 | # convert raw fields to their boolean outcome 157 | for condition_item in range(0, condition_list_len): 158 | if condition_list[condition_item] in overall_match.keys(): 159 | condition_list[condition_item] = overall_match[condition_list[condition_item]] 160 | 161 | # convert x of filed* to their boolean outcome 162 | for condition_item in range(0,condition_list_len): 163 | if condition_list[condition_item] in ["1","2","3","4","5","6","7","8","9","10"]: 164 | required_length = int(condition_list[condition_item]) 165 | selection_name = condition_list[condition_item+2].replace("*","") 166 | result = list() 167 | 168 | for key in overall_match.keys(): 169 | if key.startswith(selection_name) and overall_match[key]: 170 | result.append(overall_match[key]) 171 | 172 | if required_length == len(result): 173 | condition_list[condition_item+2] = True 174 | else: 175 | condition_list[condition_item+2] = False 176 | 177 | condition_list.pop(condition_item) 178 | condition_list.pop(condition_item) 179 | 180 | if condition_item >= len(condition_list)-1: 181 | break 182 | 183 | if condition_list[condition_item] == "all": 184 | selection_name = condition_list[condition_item+2].replace("*","") 185 | 186 | result = True 187 | for key in overall_match.keys(): 188 | if key.startswith(selection_name) and overall_match[key] == False: 189 | result = False 190 | 191 | condition_list[condition_item+2] = result 192 | 193 | condition_list.pop(condition_item) 194 | condition_list.pop(condition_item) 195 | 196 | if condition_item >= len(condition_list)-1: 197 | break 198 | 199 | evaluation_string = "" 200 | for condition in condition_list: 201 | if isinstance(condition,bool): 202 | if condition: 203 | evaluation_string+="True " 204 | if not condition: 205 | evaluation_string+="False " 206 | elif condition == "and" or condition == "&": 207 | evaluation_string+="and " 208 | elif condition == "or" or condition == "|": 209 | evaluation_string+="or " 210 | elif condition == "not": 211 | evaluation_string+="not " 212 | elif condition == "(": 213 | evaluation_string+="(" 214 | elif condition == ")": 215 | evaluation_string+=")" 216 | 217 | if eval(evaluation_string): 218 | matched_rules.append(RuleObject) 219 | else: 220 | pass 221 | 222 | else: # selection and filter content 223 | if isinstance(RuleObject["detection"][detection_field], dict): 224 | selection_fields = RuleObject["detection"][detection_field].keys() 225 | elif isinstance(RuleObject["detection"][detection_field], list): 226 | # this exception needs to be handled in future a it does not allow running SIGMA rule 227 | overall_match[detection_field] = False 228 | break 229 | 230 | selection_field_match_list = list() 231 | 232 | for selection_field in selection_fields: 233 | selection_object_match_list = list() # list that contains matches against each objects in a selection_field which will be ORed 234 | fieldname = selection_field.split("|")[0] 235 | 236 | if fieldname not in Event: 237 | # this exception needs to be handled in future a it does not allow running SIGMA rule 238 | #print(fieldname+" field not parsed, skipping from the rule") 239 | selection_object_match_list.append(1) 240 | break 241 | 242 | if "#" in selection_field: #ignore the commented lines in the SIGMA rule 243 | continue 244 | 245 | if "startswith" in selection_field: # startswith routine 246 | if len(Event[fieldname]) == 0: 247 | selection_object_match_list.append(0) 248 | else: 249 | if isinstance(RuleObject["detection"][detection_field][selection_field], list): 250 | for value in RuleObject["detection"][detection_field][selection_field]: 251 | if Event[fieldname].startswith(value): 252 | selection_object_match_list.append(1) 253 | else: 254 | selection_object_match_list.append(0) 255 | else: 256 | if Event[fieldname].startswith(RuleObject["detection"][detection_field][selection_field]): 257 | selection_object_match_list.append(1) 258 | else: 259 | selection_object_match_list.append(0) 260 | 261 | if 1 in selection_object_match_list: 262 | selection_field_match_list.append(1) 263 | else: 264 | selection_field_match_list.append(0) 265 | 266 | elif "endswith" in selection_field: # endsswith routine 267 | if len(Event[fieldname]) == 0: 268 | selection_object_match_list.append(0) 269 | else: 270 | if isinstance(RuleObject["detection"][detection_field][selection_field], list): 271 | for value in RuleObject["detection"][detection_field][selection_field]: 272 | if Event[fieldname].endswith(value): 273 | selection_object_match_list.append(1) 274 | else: 275 | selection_object_match_list.append(0) 276 | else: 277 | if Event[fieldname].endswith(RuleObject["detection"][detection_field][selection_field]): 278 | selection_object_match_list.append(1) 279 | else: 280 | selection_object_match_list.append(0) 281 | 282 | if 1 in selection_object_match_list: 283 | selection_field_match_list.append(1) 284 | else: 285 | selection_field_match_list.append(0) 286 | 287 | elif "contains|all" in selection_field: # contians routine 288 | if len(Event[fieldname]) == 0: 289 | selection_object_match_list.append(0) 290 | else: 291 | if isinstance(RuleObject["detection"][detection_field][selection_field], list): 292 | for value in RuleObject["detection"][detection_field][selection_field]: 293 | if value in Event[fieldname]: 294 | selection_object_match_list.append(1) 295 | else: 296 | selection_object_match_list.append(0) 297 | else: 298 | if RuleObject["detection"][detection_field][selection_field] in Event[fieldname]: 299 | selection_object_match_list.append(1) 300 | else: 301 | selection_object_match_list.append(0) 302 | 303 | if 0 in selection_object_match_list: 304 | selection_field_match_list.append(0) 305 | else: 306 | selection_field_match_list.append(1) 307 | 308 | elif "contains" in selection_field: # contians routine 309 | if len(Event[fieldname]) == 0: 310 | selection_object_match_list.append(0) 311 | else: 312 | if isinstance(RuleObject["detection"][detection_field][selection_field], list): 313 | for value in RuleObject["detection"][detection_field][selection_field]: 314 | if value in Event[fieldname]: 315 | selection_object_match_list.append(1) 316 | else: 317 | selection_object_match_list.append(0) 318 | else: 319 | if RuleObject["detection"][detection_field][selection_field] in Event[fieldname]: 320 | selection_object_match_list.append(1) 321 | else: 322 | selection_object_match_list.append(0) 323 | 324 | if 1 in selection_object_match_list: 325 | selection_field_match_list.append(1) 326 | else: 327 | selection_field_match_list.append(0) 328 | 329 | else: # exact match routine 330 | if len(Event[fieldname]) == 0: 331 | selection_object_match_list.append(0) 332 | else: 333 | if isinstance(RuleObject["detection"][detection_field][selection_field], list): 334 | for value in RuleObject["detection"][detection_field][selection_field]: 335 | if Event[fieldname] == value: 336 | selection_object_match_list.append(1) 337 | else: 338 | selection_object_match_list.append(0) 339 | else: 340 | if Event[fieldname] == RuleObject["detection"][detection_field][selection_field]: 341 | selection_object_match_list.append(1) 342 | else: 343 | selection_object_match_list.append(0) 344 | 345 | if 1 in selection_object_match_list: 346 | selection_field_match_list.append(1) 347 | else: 348 | selection_field_match_list.append(0) 349 | 350 | if 0 in selection_field_match_list: 351 | overall_match[detection_field] = False 352 | else: 353 | overall_match[detection_field] = True 354 | 355 | else: 356 | pass 357 | except Exception as ERROR: 358 | # print(f"Skipping the rule rule: {RuleName}") 359 | # print(ERROR) 360 | pass # Silently skip the rules with obsolete conditions 361 | event_count+=1 362 | return matched_rules 363 | -------------------------------------------------------------------------------- /Combinear.qss: -------------------------------------------------------------------------------- 1 | /*Copyright (c) DevSec Studio. All rights reserved. 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | /*-----QWidget-----*/ 24 | QWidget 25 | { 26 | background-color: #3a3a3a; 27 | color: #fff; 28 | selection-background-color: #b78620; 29 | selection-color: #000; 30 | 31 | } 32 | 33 | 34 | /*-----QLabel-----*/ 35 | QLabel 36 | { 37 | background-color: transparent; 38 | color: #fff; 39 | 40 | } 41 | 42 | 43 | /*-----QMenuBar-----*/ 44 | QMenuBar 45 | { 46 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(57, 57, 57, 255),stop:1 rgba(50, 50, 50, 255)); 47 | border: 1px solid #000; 48 | color: #fff; 49 | 50 | } 51 | 52 | 53 | QMenuBar::item 54 | { 55 | background-color: transparent; 56 | 57 | } 58 | 59 | 60 | QMenuBar::item:selected 61 | { 62 | background-color: rgba(183, 134, 32, 20%); 63 | border: 1px solid #b78620; 64 | color: #fff; 65 | 66 | } 67 | 68 | 69 | QMenuBar::item:pressed 70 | { 71 | background-color: rgb(183, 134, 32); 72 | border: 1px solid #b78620; 73 | color: #fff; 74 | 75 | } 76 | 77 | 78 | /*-----QMenu-----*/ 79 | QMenu 80 | { 81 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(57, 57, 57, 255),stop:1 rgba(50, 50, 50, 255)); 82 | border: 1px solid #222; 83 | padding: 4px; 84 | color: #fff; 85 | 86 | } 87 | 88 | 89 | QMenu::item 90 | { 91 | background-color: transparent; 92 | padding: 2px 20px 2px 20px; 93 | 94 | } 95 | 96 | 97 | QMenu::separator 98 | { 99 | background-color: rgb(183, 134, 32); 100 | height: 1px; 101 | 102 | } 103 | 104 | 105 | QMenu::item:disabled 106 | { 107 | color: #555; 108 | background-color: transparent; 109 | padding: 2px 20px 2px 20px; 110 | 111 | } 112 | 113 | 114 | QMenu::item:selected 115 | { 116 | background-color: rgba(183, 134, 32, 20%); 117 | border: 1px solid #b78620; 118 | color: #fff; 119 | 120 | } 121 | 122 | 123 | /*-----QToolBar-----*/ 124 | QToolBar 125 | { 126 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(69, 69, 69, 255),stop:1 rgba(58, 58, 58, 255)); 127 | border-top: none; 128 | border-bottom: 1px solid #4f4f4f; 129 | border-left: 1px solid #4f4f4f; 130 | border-right: 1px solid #4f4f4f; 131 | 132 | } 133 | 134 | 135 | QToolBar::separator 136 | { 137 | background-color: #2e2e2e; 138 | width: 1px; 139 | 140 | } 141 | 142 | 143 | /*-----QToolButton-----*/ 144 | QToolButton 145 | { 146 | background-color: transparent; 147 | color: #fff; 148 | padding: 5px; 149 | padding-left: 8px; 150 | padding-right: 8px; 151 | margin-left: 1px; 152 | } 153 | 154 | 155 | QToolButton:hover 156 | { 157 | background-color: rgba(183, 134, 32, 20%); 158 | border: 1px solid #b78620; 159 | color: #fff; 160 | 161 | } 162 | 163 | 164 | QToolButton:pressed 165 | { 166 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(57, 57, 57, 255),stop:1 rgba(50, 50, 50, 255)); 167 | border: 1px solid #b78620; 168 | 169 | } 170 | 171 | 172 | QToolButton:checked 173 | { 174 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(57, 57, 57, 255),stop:1 rgba(50, 50, 50, 255)); 175 | border: 1px solid #222; 176 | } 177 | 178 | 179 | /*-----QPushButton-----*/ 180 | QPushButton 181 | { 182 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(84, 84, 84, 255),stop:1 rgba(59, 59, 59, 255)); 183 | color: #ffffff; 184 | min-width: 80px; 185 | border-style: solid; 186 | border-width: 1px; 187 | border-radius: 3px; 188 | border-color: #051a39; 189 | padding: 5px; 190 | 191 | } 192 | 193 | 194 | QPushButton::flat 195 | { 196 | background-color: transparent; 197 | border: none; 198 | color: #fff; 199 | 200 | } 201 | 202 | 203 | QPushButton::disabled 204 | { 205 | background-color: #404040; 206 | color: #656565; 207 | border-color: #051a39; 208 | 209 | } 210 | 211 | 212 | QPushButton::hover 213 | { 214 | background-color: rgba(183, 134, 32, 20%); 215 | border: 1px solid #b78620; 216 | 217 | } 218 | 219 | 220 | QPushButton::pressed 221 | { 222 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(74, 74, 74, 255),stop:1 rgba(49, 49, 49, 255)); 223 | border: 1px solid #b78620; 224 | 225 | } 226 | 227 | 228 | QPushButton::checked 229 | { 230 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(74, 74, 74, 255),stop:1 rgba(49, 49, 49, 255)); 231 | border: 1px solid #222; 232 | 233 | } 234 | 235 | 236 | /*-----QLineEdit-----*/ 237 | QLineEdit 238 | { 239 | background-color: #131313; 240 | color : #eee; 241 | border: 1px solid #343434; 242 | border-radius: 2px; 243 | padding: 3px; 244 | padding-left: 5px; 245 | 246 | } 247 | 248 | 249 | /*-----QPlainTExtEdit-----*/ 250 | QPlainTextEdit 251 | { 252 | background-color: #131313; 253 | color : #eee; 254 | border: 1px solid #343434; 255 | border-radius: 2px; 256 | padding: 3px; 257 | padding-left: 5px; 258 | 259 | } 260 | 261 | 262 | /*-----QTabBar-----*/ 263 | QTabBar::tab 264 | { 265 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(84, 84, 84, 255),stop:1 rgba(59, 59, 59, 255)); 266 | color: #ffffff; 267 | border-style: solid; 268 | border-width: 1px; 269 | border-color: #666; 270 | border-bottom: none; 271 | padding: 5px; 272 | padding-left: 15px; 273 | padding-right: 15px; 274 | 275 | } 276 | 277 | 278 | QTabWidget::pane 279 | { 280 | background-color: red; 281 | border: 1px solid #666; 282 | top: 1px; 283 | 284 | } 285 | 286 | 287 | QTabBar::tab:last 288 | { 289 | margin-right: 0; 290 | 291 | } 292 | 293 | 294 | QTabBar::tab:first:!selected 295 | { 296 | background-color: #0c0c0d; 297 | margin-left: 0px; 298 | 299 | } 300 | 301 | 302 | QTabBar::tab:!selected 303 | { 304 | color: #b1b1b1; 305 | border-bottom-style: solid; 306 | background-color: #0c0c0d; 307 | 308 | } 309 | 310 | 311 | QTabBar::tab:selected 312 | { 313 | margin-bottom: 0px; 314 | 315 | } 316 | 317 | 318 | QTabBar::tab:!selected:hover 319 | { 320 | border-top-color: #b78620; 321 | 322 | } 323 | 324 | 325 | /*-----QComboBox-----*/ 326 | QComboBox 327 | { 328 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(84, 84, 84, 255),stop:1 rgba(59, 59, 59, 255)); 329 | border: 1px solid #000; 330 | padding-left: 6px; 331 | color: #ffffff; 332 | height: 20px; 333 | 334 | } 335 | 336 | 337 | QComboBox::disabled 338 | { 339 | background-color: #404040; 340 | color: #656565; 341 | border-color: #051a39; 342 | 343 | } 344 | 345 | 346 | QComboBox:on 347 | { 348 | background-color: #b78620; 349 | color: #000; 350 | 351 | } 352 | 353 | 354 | QComboBox QAbstractItemView 355 | { 356 | background-color: #383838; 357 | color: #ffffff; 358 | border: 1px solid black; 359 | selection-background-color: #b78620; 360 | outline: 0; 361 | 362 | } 363 | 364 | 365 | QComboBox::drop-down 366 | { 367 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(57, 57, 57, 255),stop:1 rgba(50, 50, 50, 255)); 368 | subcontrol-origin: padding; 369 | subcontrol-position: top right; 370 | width: 15px; 371 | border-left-width: 1px; 372 | border-left-color: black; 373 | border-left-style: solid; 374 | 375 | } 376 | 377 | 378 | QComboBox::down-arrow 379 | { 380 | image: url(://arrow-down.png); 381 | width: 8px; 382 | height: 8px; 383 | } 384 | 385 | 386 | /*-----QSpinBox & QDateTimeEdit-----*/ 387 | QSpinBox, 388 | QDateTimeEdit 389 | { 390 | background-color: #131313; 391 | color : #eee; 392 | border: 1px solid #343434; 393 | padding: 3px; 394 | padding-left: 5px; 395 | border-radius : 2px; 396 | 397 | } 398 | 399 | 400 | QSpinBox::up-button, 401 | QDateTimeEdit::up-button 402 | { 403 | border-top-right-radius:2px; 404 | background-color: #777777; 405 | width: 16px; 406 | border-width: 1px; 407 | 408 | } 409 | 410 | 411 | QSpinBox::up-button:hover, 412 | QDateTimeEdit::up-button:hover 413 | { 414 | background-color: #585858; 415 | 416 | } 417 | 418 | 419 | QSpinBox::up-button:pressed, 420 | QDateTimeEdit::up-button:pressed 421 | { 422 | background-color: #252525; 423 | width: 16px; 424 | border-width: 1px; 425 | 426 | } 427 | 428 | 429 | QSpinBox::up-arrow, 430 | QDateTimeEdit::up-arrow 431 | { 432 | image: url(://arrow-up.png); 433 | width: 7px; 434 | height: 7px; 435 | 436 | } 437 | 438 | 439 | QSpinBox::down-button, 440 | QDateTimeEdit::down-button 441 | { 442 | border-bottom-right-radius:2px; 443 | background-color: #777777; 444 | width: 16px; 445 | border-width: 1px; 446 | 447 | } 448 | 449 | 450 | QSpinBox::down-button:hover, 451 | QDateTimeEdit::down-button:hover 452 | { 453 | background-color: #585858; 454 | 455 | } 456 | 457 | 458 | QSpinBox::down-button:pressed, 459 | QDateTimeEdit::down-button:pressed 460 | { 461 | background-color: #252525; 462 | width: 16px; 463 | border-width: 1px; 464 | 465 | } 466 | 467 | 468 | QSpinBox::down-arrow, 469 | QDateTimeEdit::down-arrow 470 | { 471 | image: url(://arrow-down.png); 472 | width: 7px; 473 | height: 7px; 474 | 475 | } 476 | 477 | 478 | /*-----QGroupBox-----*/ 479 | QGroupBox 480 | { 481 | border: 1px solid; 482 | border-color: #666666; 483 | border-radius: 5px; 484 | margin-top: 20px; 485 | 486 | } 487 | 488 | 489 | QGroupBox::title 490 | { 491 | background-color: transparent; 492 | color: #eee; 493 | subcontrol-origin: margin; 494 | padding: 5px; 495 | border-top-left-radius: 3px; 496 | border-top-right-radius: 3px; 497 | 498 | } 499 | 500 | 501 | /*-----QHeaderView-----*/ 502 | QHeaderView::section 503 | { 504 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(60, 60, 60, 255),stop:1 rgba(50, 50, 50, 255)); 505 | border: 1px solid #000; 506 | color: #fff; 507 | text-align: left; 508 | padding: 4px; 509 | 510 | } 511 | 512 | 513 | QHeaderView::section:disabled 514 | { 515 | background-color: #525251; 516 | color: #656565; 517 | 518 | } 519 | 520 | 521 | QHeaderView::section:checked 522 | { 523 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(60, 60, 60, 255),stop:1 rgba(50, 50, 50, 255)); 524 | color: #fff; 525 | 526 | } 527 | 528 | 529 | QHeaderView::section::vertical::first, 530 | QHeaderView::section::vertical::only-one 531 | { 532 | border-top: 1px solid #353635; 533 | 534 | } 535 | 536 | 537 | QHeaderView::section::vertical 538 | { 539 | border-top: 1px solid #353635; 540 | 541 | } 542 | 543 | 544 | QHeaderView::section::horizontal::first, 545 | QHeaderView::section::horizontal::only-one 546 | { 547 | border-left: 1px solid #353635; 548 | 549 | } 550 | 551 | 552 | QHeaderView::section::horizontal 553 | { 554 | border-left: 1px solid #353635; 555 | 556 | } 557 | 558 | 559 | QTableCornerButton::section 560 | { 561 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(60, 60, 60, 255),stop:1 rgba(50, 50, 50, 255)); 562 | border: 1px solid #000; 563 | color: #fff; 564 | 565 | } 566 | 567 | 568 | /*-----QTreeWidget-----*/ 569 | QTreeView 570 | { 571 | show-decoration-selected: 1; 572 | alternate-background-color: #3a3a3a; 573 | selection-color: #fff; 574 | background-color: #2d2d2d; 575 | border: 1px solid gray; 576 | padding-top : 5px; 577 | color: #fff; 578 | font: 8pt; 579 | 580 | } 581 | 582 | 583 | QTreeView::item:selected 584 | { 585 | color:#fff; 586 | background-color: #b78620; 587 | border-radius: 0px; 588 | 589 | } 590 | 591 | 592 | QTreeView::item:!selected:hover 593 | { 594 | background-color: #262626; 595 | border: none; 596 | color: white; 597 | 598 | } 599 | 600 | 601 | QTreeView::branch:has-children:!has-siblings:closed, 602 | QTreeView::branch:closed:has-children:has-siblings 603 | { 604 | image: url(://tree-closed.png); 605 | 606 | } 607 | 608 | 609 | QTreeView::branch:open:has-children:!has-siblings, 610 | QTreeView::branch:open:has-children:has-siblings 611 | { 612 | image: url(://tree-open.png); 613 | 614 | } 615 | 616 | 617 | /*-----QListView-----*/ 618 | QListView 619 | { 620 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(83, 83, 83, 255),stop:0.293269 rgba(81, 81, 81, 255),stop:0.634615 rgba(79, 79, 79, 255),stop:1 rgba(83, 83, 83, 255)); 621 | border : none; 622 | color: white; 623 | show-decoration-selected: 1; 624 | outline: 0; 625 | border: 1px solid gray; 626 | 627 | } 628 | 629 | 630 | QListView::disabled 631 | { 632 | background-color: #656565; 633 | color: #1b1b1b; 634 | border: 1px solid #656565; 635 | 636 | } 637 | 638 | 639 | QListView::item 640 | { 641 | background-color: #2d2d2d; 642 | padding: 1px; 643 | 644 | } 645 | 646 | 647 | QListView::item:alternate 648 | { 649 | background-color: #3a3a3a; 650 | 651 | } 652 | 653 | 654 | QListView::item:selected 655 | { 656 | background-color: #b78620; 657 | border: 1px solid #b78620; 658 | color: #fff; 659 | 660 | } 661 | 662 | 663 | QListView::item:selected:!active 664 | { 665 | background-color: #b78620; 666 | border: 1px solid #b78620; 667 | color: #fff; 668 | 669 | } 670 | 671 | 672 | QListView::item:selected:active 673 | { 674 | background-color: #b78620; 675 | border: 1px solid #b78620; 676 | color: #fff; 677 | 678 | } 679 | 680 | 681 | QListView::item:hover { 682 | background-color: #262626; 683 | border: none; 684 | color: white; 685 | 686 | } 687 | 688 | 689 | /*-----QCheckBox-----*/ 690 | QCheckBox 691 | { 692 | background-color: transparent; 693 | color: lightgray; 694 | border: none; 695 | 696 | } 697 | 698 | 699 | QCheckBox::indicator 700 | { 701 | background-color: #323232; 702 | border: 1px solid darkgray; 703 | width: 12px; 704 | height: 12px; 705 | 706 | } 707 | 708 | 709 | QCheckBox::indicator:checked 710 | { 711 | image:url("./ressources/check.png"); 712 | background-color: #b78620; 713 | border: 1px solid #3a546e; 714 | 715 | } 716 | 717 | 718 | QCheckBox::indicator:unchecked:hover 719 | { 720 | border: 1px solid #b78620; 721 | 722 | } 723 | 724 | 725 | QCheckBox::disabled 726 | { 727 | color: #656565; 728 | 729 | } 730 | 731 | 732 | QCheckBox::indicator:disabled 733 | { 734 | background-color: #656565; 735 | color: #656565; 736 | border: 1px solid #656565; 737 | 738 | } 739 | 740 | 741 | /*-----QRadioButton-----*/ 742 | QRadioButton 743 | { 744 | color: lightgray; 745 | background-color: transparent; 746 | 747 | } 748 | 749 | 750 | QRadioButton::indicator::unchecked:hover 751 | { 752 | background-color: lightgray; 753 | border: 2px solid #b78620; 754 | border-radius: 6px; 755 | } 756 | 757 | 758 | QRadioButton::indicator::checked 759 | { 760 | border: 2px solid #b78620; 761 | border-radius: 6px; 762 | background-color: rgba(183,134,32,20%); 763 | width: 9px; 764 | height: 9px; 765 | 766 | } 767 | 768 | 769 | /*-----QSlider-----*/ 770 | QSlider::groove:horizontal 771 | { 772 | background-color: transparent; 773 | height: 3px; 774 | 775 | } 776 | 777 | 778 | QSlider::sub-page:horizontal 779 | { 780 | background-color: #b78620; 781 | 782 | } 783 | 784 | 785 | QSlider::add-page:horizontal 786 | { 787 | background-color: #131313; 788 | 789 | } 790 | 791 | 792 | QSlider::handle:horizontal 793 | { 794 | background-color: #b78620; 795 | width: 14px; 796 | margin-top: -6px; 797 | margin-bottom: -6px; 798 | border-radius: 6px; 799 | 800 | } 801 | 802 | 803 | QSlider::handle:horizontal:hover 804 | { 805 | background-color: #d89e25; 806 | border-radius: 6px; 807 | 808 | } 809 | 810 | 811 | QSlider::sub-page:horizontal:disabled 812 | { 813 | background-color: #bbb; 814 | border-color: #999; 815 | 816 | } 817 | 818 | 819 | QSlider::add-page:horizontal:disabled 820 | { 821 | background-color: #eee; 822 | border-color: #999; 823 | 824 | } 825 | 826 | 827 | QSlider::handle:horizontal:disabled 828 | { 829 | background-color: #eee; 830 | border: 1px solid #aaa; 831 | border-radius: 3px; 832 | 833 | } 834 | 835 | 836 | /*-----QScrollBar-----*/ 837 | QScrollBar:horizontal 838 | { 839 | border: 1px solid #222222; 840 | background-color: #3d3d3d; 841 | height: 15px; 842 | margin: 0px 16px 0 16px; 843 | 844 | } 845 | 846 | 847 | QScrollBar::handle:horizontal 848 | { 849 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(97, 97, 97, 255),stop:1 rgba(90, 90, 90, 255)); 850 | border: 1px solid #2d2d2d; 851 | min-height: 20px; 852 | 853 | } 854 | 855 | 856 | QScrollBar::add-line:horizontal 857 | { 858 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(97, 97, 97, 255),stop:1 rgba(90, 90, 90, 255)); 859 | border: 1px solid #2d2d2d; 860 | width: 15px; 861 | subcontrol-position: right; 862 | subcontrol-origin: margin; 863 | 864 | } 865 | 866 | 867 | QScrollBar::sub-line:horizontal 868 | { 869 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(97, 97, 97, 255),stop:1 rgba(90, 90, 90, 255)); 870 | border: 1px solid #2d2d2d; 871 | width: 15px; 872 | subcontrol-position: left; 873 | subcontrol-origin: margin; 874 | 875 | } 876 | 877 | 878 | QScrollBar::right-arrow:horizontal 879 | { 880 | image: url(://arrow-right.png); 881 | width: 6px; 882 | height: 6px; 883 | 884 | } 885 | 886 | 887 | QScrollBar::left-arrow:horizontal 888 | { 889 | image: url(://arrow-left.png); 890 | width: 6px; 891 | height: 6px; 892 | 893 | } 894 | 895 | 896 | QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal 897 | { 898 | background: none; 899 | 900 | } 901 | 902 | 903 | QScrollBar:vertical 904 | { 905 | background-color: #3d3d3d; 906 | width: 16px; 907 | border: 1px solid #2d2d2d; 908 | margin: 16px 0px 16px 0px; 909 | 910 | } 911 | 912 | 913 | QScrollBar::handle:vertical 914 | { 915 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(97, 97, 97, 255),stop:1 rgba(90, 90, 90, 255)); 916 | border: 1px solid #2d2d2d; 917 | min-height: 20px; 918 | 919 | } 920 | 921 | 922 | QScrollBar::add-line:vertical 923 | { 924 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(97, 97, 97, 255),stop:1 rgba(90, 90, 90, 255)); 925 | border: 1px solid #2d2d2d; 926 | height: 15px; 927 | subcontrol-position: bottom; 928 | subcontrol-origin: margin; 929 | 930 | } 931 | 932 | 933 | QScrollBar::sub-line:vertical 934 | { 935 | background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(97, 97, 97, 255),stop:1 rgba(90, 90, 90, 255)); 936 | border: 1px solid #2d2d2d; 937 | height: 15px; 938 | subcontrol-position: top; 939 | subcontrol-origin: margin; 940 | 941 | } 942 | 943 | 944 | QScrollBar::up-arrow:vertical 945 | { 946 | image: url(://arrow-up.png); 947 | width: 6px; 948 | height: 6px; 949 | 950 | } 951 | 952 | 953 | QScrollBar::down-arrow:vertical 954 | { 955 | image: url(://arrow-down.png); 956 | width: 6px; 957 | height: 6px; 958 | 959 | } 960 | 961 | 962 | QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical 963 | { 964 | background: none; 965 | 966 | } 967 | 968 | 969 | /*-----QProgressBar-----*/ 970 | QProgressBar 971 | { 972 | border: 1px solid #666666; 973 | text-align: center; 974 | color: #000; 975 | font-weight: bold; 976 | 977 | } 978 | 979 | 980 | QProgressBar::chunk 981 | { 982 | background-color: #b78620; 983 | width: 30px; 984 | margin: 0.5px; 985 | 986 | } 987 | 988 | -------------------------------------------------------------------------------- /mappings.py: -------------------------------------------------------------------------------- 1 | # this is a refernce set of the fields in Event Logs 2 | sigma_to_evtx_mapping = { 3 | "timestamp": "Event.System.TimeCreated", 4 | "EventID" : "Event.System.EventID", 5 | # "EventRecordID" : "Event.System.EventRecordID", 6 | "Computer" : "Event.System.Computer", 7 | # "EventData" : "Event.EventData", 8 | # "AccessList" : "Event.EventData.AccessList", 9 | "AccessMask" : "Event.EventData.AccessMask", 10 | # "Accesses" : "Event.EventData.Accesses", 11 | "AccountName" : "Event.EventData.AccountName", 12 | "Action" : "Event.EventData.Action", 13 | # "Address" : "Event.EventData.Address", 14 | # "AllowedToDelegateTo" : "Event.EventData.AllowedToDelegateTo", 15 | # "Application" : "Event.EventData.Application", 16 | # "ApplicationPath" : "Event.EventData.ApplicationPath", 17 | # "AttributeLDAPDisplayName" : "Event.EventData.AttributeLDAPDisplayName", 18 | # "AttributeValue" : "Event.EventData.AttributeValue", 19 | "AuditPolicyChanges" : "Event.EventData.AuditPolicyChanges", 20 | # "AuditSourceName" : "Event.EventData.AuditSourceName", 21 | # "AuthenticationPackageName" : "Event.EventData.AuthenticationPackageName", 22 | "CallTrace" : "Event.EventData.CallTrace", 23 | "CallerProcessName" : "Event.EventData.CallerProcessName", 24 | # "Caption" : "Event.EventData.Caption", 25 | # "CertThumbprint" : "Event.EventData.CertThumbprint", 26 | "Channel" : "Event.System.Channel", 27 | "ClassName" : "Event.EventData.ClassName", 28 | "CommandLine" : "Event.EventData.CommandLine", 29 | "Company" : "Event.EventData.Company", 30 | "ContextInfo" : "Event.EventData.ContextInfo", 31 | "CurrentDirectory" : "Event.EventData.CurrentDirectory", 32 | "Description" : "Event.EventData.Description", 33 | # "DestAddress" : "Event.EventData.DestAddress", 34 | # "DestPort" : "Event.EventData.DestPort", 35 | # "Destination" : "Event.EventData.Destination", 36 | "DestinationHostname" : "Event.EventData.DestinationHostname", 37 | "DestinationIp" : "Event.EventData.DestinationIp", 38 | "DestinationIsIpv6" : "Event.EventData.DestinationIsIpv6", 39 | "DestinationPort" : "Event.EventData.DestinationPort", 40 | "Details" : "Event.EventData.Details", 41 | # "Device" : "Event.EventData.Device", 42 | # "DeviceDescription" : "Event.EventData.DeviceDescription", 43 | # "DeviceName" : "Event.EventData.DeviceName", 44 | "EngineVersion" : "Event.EventData.EngineVersion", 45 | # "ErrorCode" : "Event.EventData.ErrorCode", 46 | # "EventType" : "Event.EventData.EventType", 47 | # "FailureCode" : "Event.EventData.FailureCode", 48 | "FileName" : "Event.EventData.FileName", 49 | "FileVersion" : "Event.EventData.FileVersion", 50 | "GrantedAccess" : "Event.EventData.GrantedAccess", 51 | "GrandparentCommandLine" : "Event.EventData.GrandparentCommandLine", 52 | "Hashes" : "Event.EventData.Hashes", 53 | # "HiveName" : "Event.EventData.HiveName", 54 | "HostApplication" : "Event.EventData.HostApplication", 55 | # "HostName" : "Event.EventData.HostName", 56 | # "HostVersion" : "Event.EventData.HostVersion", 57 | "Image" : "Event.EventData.Image", 58 | "ImageFileName" : "Event.EventData.ImageFileName", 59 | "ImageLoaded" : "Event.EventData.ImageLoaded", 60 | "ImagePath" : "Event.EventData.ImagePath", 61 | "Imphash" : "Event.EventData.Imphash", 62 | "Initiated" : "Event.EventData.Initiated", 63 | "IntegrityLevel" : "Event.EventData.IntegrityLevel", 64 | "IpAddress" : "Event.EventData.IpAddress", 65 | "KeyLength" : "Event.EventData.KeyLength", 66 | # "Keywords" : "Event.System.Keywords", 67 | # "LayerRTID" : "Event.EventData.LayerRTID", 68 | # "Level" : "Event.System.Level", 69 | # "LocalName" : "Event.EventData.LocalName", 70 | # "LogonId" : "Event.EventData.LogonId", 71 | "LogonProcessName" : "Event.EventData.LogonProcessName", 72 | "LogonType" : "Event.EventData.LogonType", 73 | # "Message" : "Event.EventData.Message", 74 | # "ModifyingApplication" : "Event.EventData.ModifyingApplication", 75 | # "NewName" : "Event.EventData.NewName", 76 | "NewTargetUserName" : "Event.EventData.NewTargetUserName", 77 | # "NewTemplateContent" : "Event.EventData.NewTemplateContent", 78 | # "NewUacValue" : "Event.EventData.NewUacValue", 79 | # "NewValue" : "Event.EventData.NewValue", 80 | # "ObjectClass" : "Event.EventData.ObjectClass", 81 | "ObjectName" : "Event.EventData.ObjectName", 82 | "ObjectServer" : "Event.EventData.ObjectServer", 83 | "ObjectType" : "Event.EventData.ObjectType", 84 | # "ObjectValueName" : "Event.EventData.ObjectValueName", 85 | "OldTargetUserName" : "Event.EventData.OldTargetUserName", 86 | # "OldUacValue" : "Event.EventData.OldUacValue", 87 | # "Origin" : "Event.EventData.Origin", 88 | "OriginalFileName" : "Event.EventData.OriginalFileName", 89 | # "OriginalName" : "Event.EventData.OriginalName", 90 | "ParentCommandLine" : "Event.EventData.ParentCommandLine", 91 | "ParentImage" : "Event.EventData.ParentImage", 92 | # "ParentUser" : "Event.EventData.ParentUser", 93 | # "PasswordLastSet" : "Event.EventData.PasswordLastSet", 94 | "Path" : "Event.EventData.Path", 95 | "Payload" : "Event.EventData.Payload", 96 | "PipeName" : "Event.EventData.PipeName", 97 | # "PossibleCause" : "Event.EventData.PossibleCause", 98 | # "PrivilegeList" : "Event.EventData.PrivilegeList", 99 | "ProcessId" : "Event.EventData.ProcessId", 100 | # "ProcessName" : "Event.EventData.ProcessName", 101 | "Product" : "Event.EventData.Product", 102 | # "Properties" : "Event.EventData.Properties", 103 | # "Protocol" : "Event.EventData.Protocol", 104 | # "Provider" : "Event.System.Provider", 105 | "ProviderName" : "Event.EventData.ProviderName", 106 | "Provider_Name" : "Event.EventData.Provider_Name", 107 | # "QNAME" : "Event.EventData.QNAME", 108 | # "Query" : "Event.EventData.Query", 109 | # "QueryName" : "Event.EventData.QueryName", 110 | # "QueryResults" : "Event.EventData.QueryResults", 111 | # "QueryStatus" : "Event.EventData.QueryStatus", 112 | "RelativeTargetName" : "Event.EventData.RelativeTargetName", 113 | # "RemoteAddress" : "Event.EventData.RemoteAddress", 114 | # "RemoteName" : "Event.EventData.RemoteName", 115 | "SamAccountName" : "Event.EventData.SamAccountName", 116 | "ScriptBlockText" : "Event.EventData.ScriptBlockText", 117 | # "SearchFilter" : "Event.EventData.SearchFilter", 118 | # "ServerName" : "Event.EventData.ServerName", 119 | # "Service" : "Event.EventData.Service", 120 | # "ServiceFileName" : "Event.EventData.ServiceFileName", 121 | "ServiceName" : "Event.EventData.ServiceName", 122 | "ServicePrincipalNames" : "Event.EventData.ServicePrincipalNames", 123 | "ServiceStartType" : "Event.EventData.ServiceStartType", 124 | "ServiceType" : "Event.EventData.ServiceType", 125 | "ShareName" : "Event.EventData.ShareName", 126 | # "SidHistory" : "Event.EventData.SidHistory", 127 | "Signed" : "Event.EventData.Signed", 128 | # "SourceAddress" : "Event.EventData.SourceAddress", 129 | "SourceImage" : "Event.EventData.SourceImage", 130 | "SourceIp" : "Event.EventData.SourceIp", 131 | "SourcePort" : "Event.EventData.SourcePort", 132 | "Source_Name" : "Event.EventData.Source_Name", 133 | # "StartAddress" : "Event.EventData.StartAddress", 134 | "StartFunction" : "Event.EventData.StartFunction", 135 | "StartModule" : "Event.EventData.StartModule", 136 | "State" : "Event.EventData.State", 137 | "Status" : "Event.EventData.Status", 138 | "SubjectDomainName" : "Event.EventData.SubjectDomainName", 139 | # "SubjectLogonId" : "Event.EventData.SubjectLogonId", 140 | "SubjectUserName" : "Event.EventData.SubjectUserName", 141 | "SubjectUserSid" : "Event.EventData.SubjectUserSid", 142 | # "TargetFilename" : "Event.EventData.TargetFilename", 143 | "TargetImage" : "Event.EventData.TargetImage", 144 | # "TargetLogonId" : "Event.EventData.TargetLogonId", 145 | # "TargetName" : "Event.EventData.TargetName", 146 | "TargetObject" : "Event.EventData.TargetObject", 147 | # "TargetParentProcessId" : "Event.EventData.TargetParentProcessId", 148 | # "TargetPort" : "Event.EventData.TargetPort", 149 | # "TargetServerName" : "Event.EventData.TargetServerName", 150 | # "TargetSid" : "Event.EventData.TargetSid", 151 | "TargetUserName" : "Event.EventData.TargetUserName", 152 | "TargetUserSid" : "Event.EventData.TargetUserSid", 153 | "TaskName" : "Event.EventData.TaskName", 154 | # "TemplateContent" : "Event.EventData.TemplateContent", 155 | "TicketEncryptionType" : "Event.EventData.TicketEncryptionType", 156 | "TicketOptions" : "Event.EventData.TicketOptions", 157 | # "Type" : "Event.EventData.Type", 158 | "User" : "Event.EventData.User", 159 | "UserName" : "Event.EventData.UserName", 160 | # "Value" : "Event.EventData.Value", 161 | # "Workstation" : "Event.EventData.Workstation", 162 | "WorkstationName" : "Event.EventData.WorkstationName", 163 | # "param1" : "Event.EventData.param1", 164 | # "param2" : "Event.EventData.param2", 165 | # "processPath" : "Event.EventData.processPath", 166 | "sha1" : "Event.EventData.sha1" 167 | } 168 | 169 | # this logsource_mapping is to tell the sigma_manager which rule would run against which event 170 | # fundamentally, all sigma rules can not run on all events because they will generate FP Noise and waste so much resources 171 | # SIGMA rules will run only on mapped Events, For example 172 | # if you add mapping for a process_creation in EventID of Sysmon Event 1, then you should add 4688 also to support corresponding Windows Logs as well 173 | 174 | logsource_mapping = { 175 | "windows": { 176 | "None" : { 177 | "None" : { 178 | "EventID" : ["*"], # "*" tells the sigma manager to run against all kinds of Events 179 | "Channels" : [ 180 | "Microsoft-Windows-Sysmon/Operational", 181 | "Security"] 182 | }, 183 | "create_remote_thread" : { 184 | "EventID" : ["8"], 185 | "Channels" : [ 186 | "Microsoft-Windows-Sysmon/Operational", 187 | "Security"] 188 | }, 189 | "create_stream_hash" : { 190 | "EventID" : ["15"], 191 | "Channels" : [ 192 | "Microsoft-Windows-Sysmon/Operational", 193 | "Security"] 194 | }, 195 | "dns_query" : { 196 | "EventID" : ["22"], 197 | "Channels" : [ 198 | "Microsoft-Windows-Sysmon/Operational", 199 | "Security"] 200 | }, 201 | "driver_load" : { 202 | "EventID" : ["6"], 203 | "Channels" : [ 204 | "Microsoft-Windows-Sysmon/Operational", 205 | "Security"] 206 | }, 207 | "image_load" : { 208 | "EventID" : ["7"], 209 | "Channels" : [ 210 | "Microsoft-Windows-Sysmon/Operational", 211 | "Security"] 212 | }, 213 | "network_connection" : { 214 | "EventID" : ["3"], 215 | "Channels" : [ 216 | "Microsoft-Windows-Sysmon/Operational", 217 | "Security"] 218 | }, 219 | "pipe_created" : { 220 | "EventID" : ["17","18","5145"], 221 | "Channels" : [ 222 | "Microsoft-Windows-Sysmon/Operational", 223 | "Security"] 224 | }, 225 | "process_access" : { 226 | "EventID" : ["10"], 227 | "Channels" : [ 228 | "Microsoft-Windows-Sysmon/Operational", 229 | "Security"] 230 | }, 231 | "process_creation" : { 232 | "EventID" : ["1","4688"], 233 | "Channels" : [ 234 | "Microsoft-Windows-Sysmon/Operational", 235 | "Security"] 236 | }, 237 | "raw_access_thread" : { 238 | "EventID" : ["9"], 239 | "Channels" : [ 240 | "Microsoft-Windows-Sysmon/Operational", 241 | "Security"] 242 | }, 243 | "sysmon_error" : { 244 | "EventID" : ["255"], 245 | "Channels" : [ 246 | "Microsoft-Windows-Sysmon/Operational", 247 | "Security"] 248 | }, 249 | "sysmon_status" : { 250 | "EventID" : ["4","16"], 251 | "Channels" : [ 252 | "Microsoft-Windows-Sysmon/Operational", 253 | "Security"] 254 | }, 255 | "file_block" : { 256 | "EventID" : ["27"], 257 | "Channels" : [ 258 | "Microsoft-Windows-Sysmon/Operational", 259 | "Security"] 260 | }, 261 | "process_tampering" : { 262 | "EventID" : ["25"], 263 | "Channels" : [ 264 | "Microsoft-Windows-Sysmon/Operational", 265 | "Security"] 266 | }, 267 | "wmi_event" : { 268 | "EventID" : ["19","20","21"], 269 | "Channels" : [ 270 | "Microsoft-Windows-Sysmon/Operational", 271 | "Security"] 272 | }, 273 | "registry_event" : { 274 | "EventID" : ["12","13","14","4657"], 275 | "Channels" : [ 276 | "Microsoft-Windows-Sysmon/Operational", 277 | "Security" 278 | ] 279 | }, 280 | "ps_module" : { 281 | "EventID" : ["4103"], 282 | "Channels" : [ 283 | "Microsoft-Windows-Sysmon/Operational", 284 | "Security" 285 | ] 286 | }, 287 | "ps_script" : { 288 | "EventID" : ["4104"], 289 | "Channels" : [ 290 | "Microsoft-Windows-Sysmon/Operational", 291 | "Security" 292 | ] 293 | }, 294 | "ps_classic_start" : { 295 | "EventID" : ["400"], 296 | "Channels" : [ 297 | "Microsoft-Windows-Sysmon/Operational", 298 | "Security" 299 | ] 300 | }, 301 | "ps_classic_provider_start" : { 302 | "EventID" : ["600"], 303 | "Channels" : [ 304 | "Microsoft-Windows-Sysmon/Operational", 305 | "Security" 306 | ] 307 | }, 308 | "ps_classic_script" : { 309 | "EventID" : ["800"], 310 | "Channels" : [ 311 | "Microsoft-Windows-Sysmon/Operational", 312 | "Security" 313 | ] 314 | } 315 | }, 316 | "sysmon" : { 317 | "None" : { 318 | "EventID" : ["*"], # "*" tells the sigma manager to run against all kinds of Events 319 | "Channels" : [ 320 | "Microsoft-Windows-Sysmon/Operational", 321 | "Security"] 322 | }, 323 | "create_remote_thread" : { 324 | "EventID" : ["8"], 325 | "Channels" : [ 326 | "Microsoft-Windows-Sysmon/Operational", 327 | "Security"] 328 | }, 329 | "create_stream_hash" : { 330 | "EventID" : ["15"], 331 | "Channels" : [ 332 | "Microsoft-Windows-Sysmon/Operational", 333 | "Security"] 334 | }, 335 | "dns_query" : { 336 | "EventID" : ["22"], 337 | "Channels" : [ 338 | "Microsoft-Windows-Sysmon/Operational", 339 | "Security"] 340 | }, 341 | "driver_load" : { 342 | "EventID" : ["6"], 343 | "Channels" : [ 344 | "Microsoft-Windows-Sysmon/Operational", 345 | "Security"] 346 | }, 347 | "image_load" : { 348 | "EventID" : ["7"], 349 | "Channels" : [ 350 | "Microsoft-Windows-Sysmon/Operational", 351 | "Security"] 352 | }, 353 | "network_connection" : { 354 | "EventID" : ["3"], 355 | "Channels" : [ 356 | "Microsoft-Windows-Sysmon/Operational", 357 | "Security"] 358 | }, 359 | "pipe_created" : { 360 | "EventID" : ["17","18","5145"], 361 | "Channels" : [ 362 | "Microsoft-Windows-Sysmon/Operational", 363 | "Security"] 364 | }, 365 | "process_access" : { 366 | "EventID" : ["10"], 367 | "Channels" : [ 368 | "Microsoft-Windows-Sysmon/Operational", 369 | "Security"] 370 | }, 371 | "process_creation" : { 372 | "EventID" : ["1","4688"], 373 | "Channels" : [ 374 | "Microsoft-Windows-Sysmon/Operational", 375 | "Security"] 376 | }, 377 | "raw_access_thread" : { 378 | "EventID" : ["9"], 379 | "Channels" : [ 380 | "Microsoft-Windows-Sysmon/Operational", 381 | "Security"] 382 | }, 383 | "sysmon_error" : { 384 | "EventID" : ["255"], 385 | "Channels" : [ 386 | "Microsoft-Windows-Sysmon/Operational", 387 | "Security"] 388 | }, 389 | "sysmon_status" : { 390 | "EventID" : ["4","16"], 391 | "Channels" : [ 392 | "Microsoft-Windows-Sysmon/Operational", 393 | "Security"] 394 | }, 395 | "file_block" : { 396 | "EventID" : ["27"], 397 | "Channels" : [ 398 | "Microsoft-Windows-Sysmon/Operational", 399 | "Security"] 400 | }, 401 | "process_tampering" : { 402 | "EventID" : ["25"], 403 | "Channels" : [ 404 | "Microsoft-Windows-Sysmon/Operational", 405 | "Security"] 406 | }, 407 | "wmi_event" : { 408 | "EventID" : ["19","20","21"], 409 | "Channels" : [ 410 | "Microsoft-Windows-Sysmon/Operational", 411 | "Security"] 412 | }, 413 | "registry_event" : { 414 | "EventID" : ["12","13","14","4657"], 415 | "Channels" : [ 416 | "Microsoft-Windows-Sysmon/Operational", 417 | "Security" 418 | ] 419 | }, 420 | "ps_module" : { 421 | "EventID" : ["4103"], 422 | "Channels" : [ 423 | "Microsoft-Windows-Sysmon/Operational", 424 | "Security" 425 | ] 426 | }, 427 | "ps_script" : { 428 | "EventID" : ["4104"], 429 | "Channels" : [ 430 | "Microsoft-Windows-Sysmon/Operational", 431 | "Security" 432 | ] 433 | }, 434 | "ps_classic_start" : { 435 | "EventID" : ["400"], 436 | "Channels" : [ 437 | "Microsoft-Windows-Sysmon/Operational", 438 | "Security" 439 | ] 440 | }, 441 | "ps_classic_provider_start" : { 442 | "EventID" : ["600"], 443 | "Channels" : [ 444 | "Microsoft-Windows-Sysmon/Operational", 445 | "Security" 446 | ] 447 | }, 448 | "ps_classic_script" : { 449 | "EventID" : ["800"], 450 | "Channels" : [ 451 | "Microsoft-Windows-Sysmon/Operational", 452 | "Security" 453 | ] 454 | } 455 | }, 456 | "security" : { 457 | "None" : { 458 | "EventID" : ["*"], # "*" tells the sigma manager to run against all kinds of Events 459 | "Channels" : [ 460 | "Microsoft-Windows-Sysmon/Operational", 461 | "Security"] 462 | }, 463 | "create_remote_thread" : { 464 | "EventID" : ["8"], 465 | "Channels" : [ 466 | "Microsoft-Windows-Sysmon/Operational", 467 | "Security"] 468 | }, 469 | "create_stream_hash" : { 470 | "EventID" : ["15"], 471 | "Channels" : [ 472 | "Microsoft-Windows-Sysmon/Operational", 473 | "Security"] 474 | }, 475 | "dns_query" : { 476 | "EventID" : ["22"], 477 | "Channels" : [ 478 | "Microsoft-Windows-Sysmon/Operational", 479 | "Security"] 480 | }, 481 | "driver_load" : { 482 | "EventID" : ["6"], 483 | "Channels" : [ 484 | "Microsoft-Windows-Sysmon/Operational", 485 | "Security"] 486 | }, 487 | "image_load" : { 488 | "EventID" : ["7"], 489 | "Channels" : [ 490 | "Microsoft-Windows-Sysmon/Operational", 491 | "Security"] 492 | }, 493 | "network_connection" : { 494 | "EventID" : ["3"], 495 | "Channels" : [ 496 | "Microsoft-Windows-Sysmon/Operational", 497 | "Security"] 498 | }, 499 | "pipe_created" : { 500 | "EventID" : ["17","18","5145"], 501 | "Channels" : [ 502 | "Microsoft-Windows-Sysmon/Operational", 503 | "Security"] 504 | }, 505 | "process_access" : { 506 | "EventID" : ["10"], 507 | "Channels" : [ 508 | "Microsoft-Windows-Sysmon/Operational", 509 | "Security"] 510 | }, 511 | "process_creation" : { 512 | "EventID" : ["1","4688"], 513 | "Channels" : [ 514 | "Microsoft-Windows-Sysmon/Operational", 515 | "Security"] 516 | }, 517 | "raw_access_thread" : { 518 | "EventID" : ["9"], 519 | "Channels" : [ 520 | "Microsoft-Windows-Sysmon/Operational", 521 | "Security"] 522 | }, 523 | "sysmon_error" : { 524 | "EventID" : ["255"], 525 | "Channels" : [ 526 | "Microsoft-Windows-Sysmon/Operational", 527 | "Security"] 528 | }, 529 | "sysmon_status" : { 530 | "EventID" : ["4","16"], 531 | "Channels" : [ 532 | "Microsoft-Windows-Sysmon/Operational", 533 | "Security"] 534 | }, 535 | "file_block" : { 536 | "EventID" : ["27"], 537 | "Channels" : [ 538 | "Microsoft-Windows-Sysmon/Operational", 539 | "Security"] 540 | }, 541 | "process_tampering" : { 542 | "EventID" : ["25"], 543 | "Channels" : [ 544 | "Microsoft-Windows-Sysmon/Operational", 545 | "Security"] 546 | }, 547 | "wmi_event" : { 548 | "EventID" : ["19","20","21"], 549 | "Channels" : [ 550 | "Microsoft-Windows-Sysmon/Operational", 551 | "Security"] 552 | }, 553 | "registry_event" : { 554 | "EventID" : ["12","13","14","4657"], 555 | "Channels" : [ 556 | "Microsoft-Windows-Sysmon/Operational", 557 | "Security" 558 | ] 559 | }, 560 | "ps_module" : { 561 | "EventID" : ["4103"], 562 | "Channels" : [ 563 | "Microsoft-Windows-Sysmon/Operational", 564 | "Security" 565 | ] 566 | }, 567 | "ps_script" : { 568 | "EventID" : ["4104"], 569 | "Channels" : [ 570 | "Microsoft-Windows-Sysmon/Operational", 571 | "Security" 572 | ] 573 | }, 574 | "ps_classic_start" : { 575 | "EventID" : ["400"], 576 | "Channels" : [ 577 | "Microsoft-Windows-Sysmon/Operational", 578 | "Security" 579 | ] 580 | }, 581 | "ps_classic_provider_start" : { 582 | "EventID" : ["600"], 583 | "Channels" : [ 584 | "Microsoft-Windows-Sysmon/Operational", 585 | "Security" 586 | ] 587 | }, 588 | "ps_classic_script" : { 589 | "EventID" : ["800"], 590 | "Channels" : [ 591 | "Microsoft-Windows-Sysmon/Operational", 592 | "Security" 593 | ] 594 | } 595 | } 596 | } 597 | } 598 | 599 | def is_queryable(Logsource, EventID): 600 | # Sanity check 601 | 602 | if "product" not in Logsource: 603 | print("Invalid Rule without logsource product encountered") 604 | pass 605 | if "category" not in Logsource: 606 | Logsource["category"] = "None" 607 | if "service" not in Logsource: 608 | Logsource["service"] = "None" 609 | if "source" not in Logsource: 610 | Logsource["source"] = "None" 611 | 612 | if ( 613 | EventID in logsource_mapping[Logsource["product"]][Logsource["service"]][Logsource["category"]]["EventID"] or 614 | logsource_mapping[Logsource["product"]][Logsource["service"]][Logsource["category"]]["EventID"] == "*" 615 | ): 616 | return True 617 | else: 618 | return False -------------------------------------------------------------------------------- /ThreatHound.py: -------------------------------------------------------------------------------- 1 | # total hours i speend here : 8472.1 2 | # contact me if u add more detections 3 | # Mohamed Alzhrani 4 | # https://github.com/MazX0p 5 | 6 | import sys 7 | import csv 8 | import re 9 | import io 10 | import json 11 | from netaddr import * 12 | import xml.etree.ElementTree as ET 13 | import pandas as pd 14 | from datetime import datetime, timezone, timedelta 15 | from dateutil.parser import parse 16 | from dateutil.parser import isoparse 17 | from pytz import timezone 18 | import html 19 | import base64 20 | import codecs 21 | import copy 22 | import random 23 | from sigma_manager import GetRuleFilesList 24 | from sigma_manager import GetIsSigmaLoad, SigmaPath 25 | import sigma_manager 26 | import concurrent.futures 27 | from time import sleep 28 | import os 29 | import argparse 30 | from colorama import init, Fore, Style 31 | import platform 32 | from PyQt5.QtWidgets import ( 33 | QApplication, QDialog, QMainWindow, QMessageBox, QWidget, QPushButton, QVBoxLayout, QFileDialog, QTableView, QLineEdit, QItemDelegate 34 | ) 35 | from PyQt5.QtCore import Qt, QModelIndex, QSortFilterProxyModel 36 | from PyQt5.QtGui import QStandardItemModel, QStandardItem, QTextDocument 37 | from PyQt5.uic import loadUi 38 | from PyQt5 import QtCore, QtGui, QtWidgets 39 | from PyQt5.QtCore import QTimer 40 | import pandas as pd 41 | 42 | try: 43 | from evtx import PyEvtxParser 44 | has_evtx = True 45 | except ImportError: 46 | has_evtx = False 47 | 48 | try: 49 | from lxml import etree 50 | has_lxml = True 51 | except ImportError: 52 | has_lxml = False 53 | 54 | try: 55 | import pandas as pd 56 | has_pandas = True 57 | except ImportError: 58 | has_pandas = False 59 | 60 | def get_os_type(): 61 | system = platform.system() 62 | if system == "Windows": 63 | return "Windows" 64 | elif system == "Linux": 65 | return "Linux" 66 | else: 67 | return "Unknown" 68 | 69 | os_type = get_os_type() 70 | print("[-] your system : " + os_type) 71 | 72 | IsAnalyzing = False 73 | IsSigmaLoaded = False 74 | Result_Event_list = [] 75 | Result_Rule_list = [] 76 | 77 | #======================= 78 | # Initiate list of JSON containing matched rules 79 | 80 | Susp_exe=["\\mshta.exe","\\regsvr32.exe","\\csc.exe",'whoami.exe','\\pl.exe','\\nc.exe','nmap.exe','psexec.exe','plink.exe','mimikatz','procdump.exe',' dcom.exe',' Inveigh.exe',' LockLess.exe',' Logger.exe',' PBind.exe',' PS.exe',' Rubeus.exe',' RunasCs.exe',' RunAs.exe',' SafetyDump.exe',' SafetyKatz.exe',' Seatbelt.exe',' SExec.exe',' SharpApplocker.exe',' SharpChrome.exe',' SharpCOM.exe',' SharpDPAPI.exe',' SharpDump.exe',' SharpEdge.exe',' SharpEDRChecker.exe',' SharPersist.exe',' SharpHound.exe',' SharpLogger.exe',' SharpPrinter.exe','EfsPotato.exe',' SharpSC.exe',' SharpSniper.exe',' SharpSocks.exe',' SharpSSDP.exe',' SharpTask.exe',' SharpUp.exe',' SharpView.exe',' SharpWeb.exe',' SharpWMI.exe',' Shhmon.exe',' SweetPotato.exe',' Watson.exe',' WExec.exe','7zip.exe', 'HOSTNAME.EXE', 'hostname.exe'] 81 | 82 | Susp_commands=['FromBase64String','DomainPasswordSpray','PasswordSpray','Password','Get-WMIObject','Get-GPPPassword','Get-Keystrokes','Get-TimedScreenshot','Get-VaultCredential','Get-ServiceUnquoted','Get-ServiceEXEPerms','Get-ServicePerms','Get-RegAlwaysInstallElevated','Get-RegAutoLogon','Get-UnattendedInstallFiles','Get-Webconfig','Get-ApplicationHost','Get-PassHashes','Get-LsaSecret','Get-Information','Get-PSADForestInfo','Get-KerberosPolicy','Get-PSADForestKRBTGTInfo','Get-PSADForestInfo','Get-KerberosPolicy','Invoke-Command','Invoke-Expression','iex(','Invoke-Shellcode','Invoke--Shellcode','Invoke-ShellcodeMSIL','Invoke-MimikatzWDigestDowngrade','Invoke-NinjaCopy','Invoke-CredentialInjection','Invoke-TokenManipulation','Invoke-CallbackIEX','Invoke-PSInject','Invoke-DllEncode','Invoke-ServiceUserAdd','Invoke-ServiceCMD','Invoke-ServiceStart','Invoke-ServiceStop','Invoke-ServiceEnable','Invoke-ServiceDisable','Invoke-FindDLLHijack','Invoke-FindPathHijack','Invoke-AllChecks','Invoke-MassCommand','Invoke-MassMimikatz','Invoke-MassSearch','Invoke-MassTemplate','Invoke-MassTokens','Invoke-ADSBackdoor','Invoke-CredentialsPhish','Invoke-BruteForce','Invoke-PowerShellIcmp','Invoke-PowerShellUdp','Invoke-PsGcatAgent','Invoke-PoshRatHttps','Invoke-PowerShellTcp','Invoke-PoshRatHttp','Invoke-PowerShellWmi','Invoke-PSGcat','Invoke-Encode','Invoke-Decode','Invoke-CreateCertificate','Invoke-NetworkRelay','EncodedCommand','New-ElevatedPersistenceOption','wsman','Enter-PSSession','DownloadString','DownloadFile','Out-Word','Out-Excel','Out-Java','Out-Shortcut','Out-CHM','Out-HTA','Out-Minidump','HTTP-Backdoor','Find-AVSignature','DllInjection','ReflectivePEInjection','Base64','System.Reflection','System.Management','Restore-ServiceEXE','Add-ScrnSaveBackdoor','Gupt-Backdoor','Execute-OnTime','DNS_TXT_Pwnage','Write-UserAddServiceBinary','Write-CMDServiceBinary','Write-UserAddMSI','Write-ServiceEXE','Write-ServiceEXECMD','Enable-DuplicateToken','Remove-Update','Execute-DNSTXT-Code','Download-Execute-PS','Execute-Command-MSSQL','Download_Execute','Copy-VSS','Check-VM','Create-MultipleSessions','Run-EXEonRemote','Port-Scan','Remove-PoshRat','TexttoEXE','Base64ToString','StringtoBase64','Do-Exfiltration','Parse_Keys','Add-Exfiltration','Add-Persistence','Remove-Persistence','Find-PSServiceAccounts','Discover-PSMSSQLServers','Discover-PSMSExchangeServers','Discover-PSInterestingServices','Discover-PSMSExchangeServers','Discover-PSInterestingServices','Mimikatz','powercat','powersploit','PowershellEmpire','GetProcAddress','ICM','.invoke',' -e ','hidden','-w hidden','Invoke-Obfuscation-master','Out-EncodedWhitespaceCommand','Out-Encoded',"-EncodedCommand","-enc","-w hidden","[Convert]::FromBase64String","iex(","New-Object","Net.WebClient","-windowstyle hidden","DownloadFile","DownloadString","Invoke-Expression","Net.WebClient","-Exec bypass" ,"-ExecutionPolicy bypass"] 83 | 84 | Susp_Arguments=["-EncodedCommand","-enc","-w hidden","[Convert]::FromBase64String","iex(","New-Object","Net.WebClient","-windowstyle hidden","DownloadFile","DownloadString","Invoke-Expression","Net.WebClient","-Exec bypass" ,"-ExecutionPolicy bypass"] 85 | 86 | all_suspicious=["\\csc.exe",'whoami.exe','\\pl.exe','\\nc.exe','nmap.exe','psexec.exe','plink.exe','kali','mimikatz','procdump.exe',' dcom.exe',' Inveigh.exe',' LockLess.exe',' Logger.exe',' PBind.exe',' PS.exe',' Rubeus.exe',' RunasCs.exe',' RunAs.exe',' SafetyDump.exe',' SafetyKatz.exe',' Seatbelt.exe',' SExec.exe',' SharpApplocker.exe',' SharpChrome.exe',' SharpCOM.exe',' SharpDPAPI.exe',' SharpDump.exe',' SharpEdge.exe',' SharpEDRChecker.exe',' SharPersist.exe',' SharpHound.exe',' SharpLogger.exe',' SharpPrinter.exe',' SharpRoast.exe',' SharpSC.exe',' SharpSniper.exe',' SharpSocks.exe',' SharpSSDP.exe',' SharpTask.exe',' SharpUp.exe',' SharpView.exe',' SharpWeb.exe',' SharpWMI.exe',' Shhmon.exe',' SweetPotato.exe',' Watson.exe',' WExec.exe','7zip.exe','FromBase64String','DomainPasswordSpray','PasswordSpray','Password','Get-WMIObject','Get-GPPPassword','Get-Keystrokes','Get-TimedScreenshot','Get-VaultCredential','Get-ServiceUnquoted','Get-ServiceEXEPerms','Get-ServicePerms','Get-RegAlwaysInstallElevated','Get-RegAutoLogon','Get-UnattendedInstallFiles','Get-Webconfig','Get-ApplicationHost','Get-PassHashes','Get-LsaSecret','Get-Information','Get-PSADForestInfo','Get-KerberosPolicy','Get-PSADForestKRBTGTInfo','Get-PSADForestInfo','Get-KerberosPolicy','Invoke-Command','Invoke-Expression','iex(','Invoke-Shellcode','Invoke--Shellcode','Invoke-ShellcodeMSIL','Invoke-MimikatzWDigestDowngrade','Invoke-NinjaCopy','Invoke-CredentialInjection','Invoke-TokenManipulation','Invoke-CallbackIEX','Invoke-PSInject','Invoke-DllEncode','Invoke-ServiceUserAdd','Invoke-ServiceCMD','Invoke-ServiceStart','Invoke-ServiceStop','Invoke-ServiceEnable','Invoke-ServiceDisable','Invoke-FindDLLHijack','Invoke-FindPathHijack','Invoke-AllChecks','Invoke-MassCommand','Invoke-MassMimikatz','Invoke-MassSearch','Invoke-MassTemplate','Invoke-MassTokens','Invoke-ADSBackdoor','Invoke-CredentialsPhish','Invoke-BruteForce','Invoke-PowerShellIcmp','Invoke-PowerShellUdp','Invoke-PsGcatAgent','Invoke-PoshRatHttps','Invoke-PowerShellTcp','Invoke-PoshRatHttp','Invoke-PowerShellWmi','Invoke-PSGcat','Invoke-Encode','Invoke-Decode','Invoke-CreateCertificate','Invoke-NetworkRelay','EncodedCommand','New-ElevatedPersistenceOption','wsman','Enter-PSSession','DownloadString','DownloadFile','Out-Word','Out-Excel','Out-Java','Out-Shortcut','Out-CHM','Out-HTA','Out-Minidump','HTTP-Backdoor','Find-AVSignature','DllInjection','ReflectivePEInjection','Base64','System.Reflection','System.Management','Restore-ServiceEXE','Add-ScrnSaveBackdoor','Gupt-Backdoor','Execute-OnTime','DNS_TXT_Pwnage','Write-UserAddServiceBinary','Write-CMDServiceBinary','Write-UserAddMSI','Write-ServiceEXE','Write-ServiceEXECMD','Enable-DuplicateToken','Remove-Update','Execute-DNSTXT-Code','Download-Execute-PS','Execute-Command-MSSQL','Download_Execute','Copy-VSS','Check-VM','Create-MultipleSessions','Run-EXEonRemote','Port-Scan','Remove-PoshRat','TexttoEXE','Base64ToString','StringtoBase64','Do-Exfiltration','Parse_Keys','Add-Exfiltration','Add-Persistence','Remove-Persistence','Find-PSServiceAccounts','Discover-PSMSSQLServers','Discover-PSMSExchangeServers','Discover-PSInterestingServices','Discover-PSMSExchangeServers','Discover-PSInterestingServices','Mimikatz','powercat','powersploit','PowershellEmpire','GetProcAddress','ICM','.invoke',' -e ','hidden','-w hidden','Invoke-Obfuscation-master','Out-EncodedWhitespaceCommand','Out-Encoded',"-EncodedCommand","-enc","-w hidden","[Convert]::FromBase64String","iex(","New-Object","Net.WebClient","-windowstyle hidden","DownloadFile","DownloadString","Invoke-Expression","Net.WebClient","-Exec bypass" ,"-ExecutionPolicy bypass","-EncodedCommand","-enc","-w hidden","[Convert]::FromBase64String","iex(","New-Object","Net.WebClient","-windowstyle hidden","DownloadFile","DownloadString","Invoke-Expression","Net.WebClient","-Exec bypass" ,"-ExecutionPolicy bypass"] 87 | 88 | Susp_Path=['\\temp\\',' C:\Windows\System32\mshta.exe','/temp/','//windows//temp//','/windows/temp/','\\windows\\temp\\','\\appdata\\','/appdata/','//appdata//','//programdata//','\\programdata\\','/programdata/'] 89 | 90 | Usual_Path=['\\Windows\\','/Windows/','//Windows//','Program Files','\\Windows\\SysWOW64\\','/Windows/SysWOW64/','//Windows//SysWOW64//','\\Windows\\Cluster\\','/Windows/Cluster/','//Windows//Cluster//'] 91 | 92 | #======================= 93 | #Regex for security logs 94 | MatchedRulesAgainstLogs = dict() 95 | 96 | EventID_rex = re.compile('(.*)<\/EventID>', re.IGNORECASE) 97 | 98 | LogonType_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 99 | 100 | #====================== 101 | # My Regex For Sysmon Logs 102 | User_Name_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 103 | ProcessId_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 104 | DestinationIp_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 105 | Destination_Is_Ipv6_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 106 | Source_IP_SourceIp_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 107 | Source_IP_IpAddress_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 108 | # UtcTime_rex = re.compile('(.*)|(.*)|', re.IGNORECASE) 109 | UtcTime_rex = re.compile('\n ', re.IGNORECASE) 110 | Protocol_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 111 | SourcePort_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 112 | DestinationPort_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 113 | SourceHostname_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 114 | FileVersion_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 115 | Description_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 116 | Hashes_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 117 | Computer_Name_rex = re.compile('(.*)', re.IGNORECASE) 118 | ParentProcessId_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 119 | ParentImage_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 120 | ParentCommandLine_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 121 | GrandparentCommandLine_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 122 | Signed_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 123 | Signature_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 124 | State_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 125 | Status_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 126 | # My Regex For Event Logs 127 | Channel_rex = re.compile('(.*)<\/Channel>', re.IGNORECASE) 128 | Provider_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 131 | Service_Image_Path_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 132 | ServiceType_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 133 | Service_Account_Name_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 134 | ServiceStartType_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 135 | # My Regex for Security logs 136 | AccountName_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 137 | AccountDomain_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 138 | # My NetWork Regex 139 | IpPort_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 140 | # My AD regex 141 | ShareName_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 142 | ShareLocalPath_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 143 | RelativeTargetName_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 144 | AccountName_Target_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 145 | # My Task regex 146 | TaskName_rex=re.compile('(.*)|(.*)', re.IGNORECASE) 147 | TaskContent_rex = re.compile('([^"]*)|([^"]*)', re.IGNORECASE) 148 | TaskContent2_rex = re.compile('(.*)', re.IGNORECASE) 149 | # My PowerShell regex 150 | Powershell_Command_rex= re.compile('(.*)', re.IGNORECASE) 151 | # My process Command Line Regex 152 | Process_Command_Line_rex=re.compile('(.*)|(.*)', re.IGNORECASE) 153 | # My New Process Name regex 154 | New_Process_Name_rex=re.compile('(.*)', re.IGNORECASE) 155 | # My Regex 156 | TokenElevationType_rex=re.compile('(.*)', re.IGNORECASE) 157 | # My PipeName Regex 158 | PipeName_rex=re.compile("(.*)") 159 | # My ImageName Regex 160 | Image_rex=re.compile("(.*)") 161 | ServicePrincipalNames_rex=re.compile("(.*)") 162 | SamAccountName_rex=re.compile("(.*)") 163 | NewTargetUserName_rex=re.compile("(.*)") 164 | OldTargetUserName_rex=re.compile("(.*)") 165 | # My Call Trace regex 166 | CallTrace_rex=re.compile("(.*)") 167 | # My GrantedAccess Regex 168 | GrantedAccess_rex=re.compile("(.*)") 169 | # My TargetImage Regex 170 | TargetImage_rex=re.compile("(.*)") 171 | # My SourceImage Regex 172 | SourceImage_rex=re.compile("(.*)") 173 | 174 | SourceProcessId_rex=re.compile("(.*)") 175 | SourceProcessGuid_rex=re.compile("(.*)") 176 | TargetProcessGuid_rex=re.compile("(.*)") 177 | TargetProcessId_rex=re.compile("(.*)") 178 | PowershellUserId_rex=re.compile("UserId=(.*)") 179 | PowershellHostApplication_rex=re.compile("HostApplication=(.*)") 180 | Powershell_ContextInfo= re.compile('(.*)', re.IGNORECASE) 181 | Powershell_Payload= re.compile('(.*)', re.IGNORECASE) 182 | Powershell_Path= re.compile('(.*)', re.IGNORECASE) 183 | Command_Name_rex = re.compile('CommandName = (.*)') 184 | PowerShellCommand_rex = re.compile('[\s\S]*?') # i will come back continue 185 | CommandLine_powershell_rex = re.compile('CommandLine= (.*)') 186 | ScriptName_rex = re.compile('ScriptName=(.*)') 187 | ErrorMessage_rex = re.compile('ErrorMessage=(.*)') 188 | #====================== 189 | 190 | Security_ID_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 191 | Security_ID_Target_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 192 | Account_Domain_Target_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 193 | Workstation_Name_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 194 | Logon_Process_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 195 | Key_Length_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 196 | AccessMask_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 197 | TicketOptions_rex=re.compile('(.*)|(.*)', re.IGNORECASE) 198 | TicketEncryptionType_rex=re.compile('(.*)|(.*)', re.IGNORECASE) 199 | Group_Name_rex=re.compile('(.*)|(.*)', re.IGNORECASE) 200 | Process_Name_sec_rex = re.compile('(.*)|(.*)|(.*)|(.*)', re.IGNORECASE) 201 | Parent_Process_Name_sec_rex=re.compile('(.*)|(.*)', re.IGNORECASE) 202 | Category_sec_rex= re.compile('(.*)|(.*)', re.IGNORECASE) 203 | Subcategory_rex= re.compile('(.*)|(.*)', re.IGNORECASE) 204 | Changes_rex= re.compile('(.*)|(.*)', re.IGNORECASE) 205 | Member_Name_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 206 | Member_Sid_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 207 | Object_Name_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 208 | ObjectType_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 209 | ObjectServer_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 210 | #======================= 211 | #Regex for windows defender logs 212 | 213 | Name_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 214 | Severity_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 215 | Category_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 216 | Path_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 217 | Defender_Remediation_User_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 218 | Defender_User_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 219 | Process_Name_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 220 | Action_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 221 | 222 | #======================= 223 | #Regex for system logs 224 | 225 | #======================= 226 | #Regex for task scheduler logs 227 | Task_Name = re.compile('(.*)|(.*)', re.IGNORECASE) 228 | Task_Registered_User_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 229 | Task_Deleted_User_rex = re.compile('(.*)|(.*)', re.IGNORECASE) 230 | 231 | #====================== 232 | #Regex for powershell operational logs 233 | Powershell_ContextInfo= re.compile('(.*)', re.IGNORECASE) 234 | Powershell_Payload= re.compile('(.*)', re.IGNORECASE) 235 | Powershell_Path= re.compile('(.*)', re.IGNORECASE) 236 | 237 | Host_Application_rex = re.compile('Host Application = (.*)') 238 | #Command_Name_rex = re.compile('Command Name = (.*)') 239 | Command_Type_rex = re.compile('Command Type = (.*)') 240 | Engine_Version_rex = re.compile('Engine Version = (.*)') 241 | User_rex = re.compile('User = (.*)') 242 | Error_Message_rex = re.compile('Error Message = (.*)') 243 | 244 | #====================== 245 | #Regex for powershell logs 246 | HostApplication_rex = re.compile('HostApplication=(.*)') 247 | CommandLine_rex = re.compile('CommandLine=(.*)') 248 | ScriptName_rex = re.compile('ScriptName=(.*)') 249 | EngineVersion_rex = re.compile('EngineVersion=(.*)') 250 | UserId_rex = re.compile('UserId=(.*)') 251 | ErrorMessage_rex = re.compile('ErrorMessage=(.*)') 252 | #====================== 253 | #TerminalServices Local Session Manager Logs 254 | #Source_Network_Address_Terminal_rex= re.compile('Source Network Address: (.*)') 255 | #Source_Network_Address_Terminal_rex= re.compile('
(.*)
') 256 | Source_Network_Address_Terminal_rex= re.compile('
((\d{1,3}\.){3}\d{1,3})
') 257 | Source_Network_Address_Terminal_NotIP_rex= re.compile('
(.*)
') 258 | User_Terminal_rex=re.compile('User>(.*)') 259 | Session_ID_rex=re.compile('(.*)') 260 | #====================== 261 | #Microsoft-Windows-WinRM logs 262 | Connection_rex=re.compile('(.*)|(.*)', re.IGNORECASE) 263 | Winrm_UserID_rex=re.compile('.*)\'\/><\/System>""") 266 | #src_device_rex=re.compile("""(?.*)<\/Computer>""") 267 | #====================== 268 | #Sysmon Logs 269 | Sysmon_CommandLine_rex=re.compile("(.*)") 270 | Sysmon_ProcessGuid_rex=re.compile("(.*)") 271 | Sysmon_ProcessId_rex=re.compile("(.*)") 272 | Sysmon_FileName_rex=re.compile("(.*)") 273 | Sysmon_ImageFileName_rex=re.compile("(.*)") 274 | Sysmon_Initiated_rex=re.compile("(.*)") 275 | Sysmon_FileVersion_rex=re.compile("(.*)") 276 | Sysmon_Company_rex=re.compile("(.*)") 277 | Sysmon_Product_rex=re.compile("(.*)") 278 | Sysmon_Description_rex=re.compile("(.*)") 279 | Sysmon_User_rex=re.compile("(.*)") 280 | Sysmon_LogonGuid_rex=re.compile("(.*)") 281 | Sysmon_TerminalSessionId_rex=re.compile("(.*)") 282 | Sysmon_Hashes_MD5_rex=re.compile("(.*)") 285 | Sysmon_ParentProcessGuid_rex=re.compile("(.*)") 286 | Sysmon_ParentProcessId_rex=re.compile("(.*)") 287 | Sysmon_ParentCommandLine_rex=re.compile("(.*)") 288 | Sysmon_ParentUser_rex=re.compile("(.*)") 289 | Sysmon_ProviderName_rex=re.compile("(.*)") 290 | Sysmon_CurrentDirectory_rex=re.compile("(.*)") 291 | Sysmon_OriginalFileName_rex=re.compile("(.*)") 292 | Sysmon_TargetObject_rex=re.compile("(.*)") 293 | ######### 294 | #Sysmon event ID 3 295 | Sysmon_Protocol_rex=re.compile("(.*)") 296 | Sysmon_SourceIp_rex=re.compile("(.*)") 297 | Sysmon_SourceHostname_rex=re.compile("(.*)") 298 | Sysmon_SourcePort_rex=re.compile("(.*)") 299 | Sysmon_DestinationIp_rex=re.compile("(.*)") 300 | Sysmon_DestinationHostname_rex=re.compile("(.*)") 301 | Sysmon_DestinationPort_rex=re.compile("(.*)") 302 | 303 | ######### 304 | #Sysmon event ID 8 305 | Sysmon_StartFunction_rex=re.compile("(.*)") 306 | Sysmon_StartModule_rex=re.compile("(.*)") 307 | 308 | ######### 309 | Sysmon_ImageLoaded_rex=re.compile("(.*)") 310 | Sysmon_Details_rex=re.compile("(.*)") 311 | Sysmon_GrantedAccess_rex=re.compile("(.*)") 312 | Sysmon_CallTrace_rex=re.compile("(.*)") 313 | 314 | ########## 315 | 316 | Security_Authentication_Summary=[{'User':[],'SID':[],'Number of Successful Logins':[]}] 317 | Logon_Events=[{'Date and Time':[],'timestamp':[],'Event ID':[],'Account Name':[],'Account Domain':[],'Logon Type':[],'Logon Process':[],'Source IP':[],'Workstation Name':[],'Computer Name':[],'Channel':[],'Original Event Log':[]}] 318 | 319 | EVTX_HEADER = b"\x45\x6C\x66\x46\x69\x6C\x65\x00" 320 | evtx_list = [] 321 | user_list = [] 322 | user_list_2 = [] 323 | sourceIp_list = [] 324 | sourceIp_list_2 = [] 325 | #cve-2021-42287 Detect 326 | REQUEST_TGT_CHECK_list = [] 327 | New_Target_User_Name_Check_list = [] 328 | SAM_ACCOUNT_NAME_CHECK_list = [] 329 | ATTACK_REPLAY_CHECK_list = [] 330 | 331 | 332 | # IPv4 regex 333 | IPv4_PATTERN = re.compile(r"\A\d+\.\d+\.\d+\.\d+\Z", re.DOTALL) 334 | 335 | # IPv6 regex 336 | IPv6_PATTERN = re.compile(r"\A(::(([0-9a-f]|[1-9a-f][0-9a-f]{1,3})(:([0-9a-f]|[1-9a-f][0-9a-f]{1,3})){0,5})?|([0-9a-f]|[1-9a-f][0-9a-f]{1,3})(::(([0-9a-f]|[1-9a-f][0-9a-f]{1,3})(:([0-9a-f]|[1-9a-f][0-9a-f]{1,3})){0,4})?|:([0-9a-f]|[1-9a-f][0-9a-f]{1,3})(::(([0-9a-f]|[1-9a-f][0-9a-f]{1,3})(:([0-9a-f]|[1-9a-f][0-9a-f]{1,3})){0,3})?|:([0-9a-f]|[1-9a-f][0-9a-f]{1,3})(::(([0-9a-f]|[1-9a-f][0-9a-f]{1,3})(:([0-9a-f]|[1-9a-f][0-9a-f]{1,3})){0,2})?|:([0-9a-f]|[1-9a-f][0-9a-f]{1,3})(::(([0-9a-f]|[1-9a-f][0-9a-f]{1,3})(:([0-9a-f]|[1-9a-f][0-9a-f]{1,3}))?)?|:([0-9a-f]|[1-9a-f][0-9a-f]{1,3})(::([0-9a-f]|[1-9a-f][0-9a-f]{1,3})?|(:([0-9a-f]|[1-9a-f][0-9a-f]{1,3})){3}))))))\Z", re.DOTALL) 337 | 338 | evtx_list2 = ["/mnt/c/Users/ahmad/Desktop/biz/project/downloads/EVTX-ATTACK-SAMPLES-master/Discovery/discovery_psloggedon.evtx"] 339 | 340 | #detect base64 commands 341 | def isBase64(command): 342 | try: 343 | return base64.b64encode(base64.b64decode(command)) == command 344 | except Exception: 345 | return False 346 | 347 | def to_lxml(record_xml): 348 | rep_xml = record_xml.replace("xmlns=\"http://schemas.microsoft.com/win/2004/08/events/event\"", "") 349 | fin_xml = rep_xml.encode("utf-8") 350 | parser = etree.XMLParser(resolve_entities=False) 351 | return etree.fromstring(fin_xml, parser) 352 | 353 | def xml_records(filename): 354 | evtx = None 355 | if evtx is None: 356 | with open(filename, "rb") as evtx: 357 | parser = PyEvtxParser(evtx) 358 | for record in parser.records(): 359 | try: 360 | yield to_lxml(record["data"]), None 361 | except etree.XMLSyntaxError as e: 362 | yield record["data"], e 363 | 364 | def checker(check): 365 | if check == "REQUEST_TGT_CHECK": 366 | REQUEST_TGT_CHECK_list.append("True") 367 | if check == "New_Target_User_Name_Check": 368 | New_Target_User_Name_Check_list.append("True") 369 | if check == "SAM_ACCOUNT_NAME_CHECK": 370 | SAM_ACCOUNT_NAME_CHECK_list.append("True") 371 | if check == "ATTACK_REPLAY_CHECK": 372 | ATTACK_REPLAY_CHECK_list.append("True") 373 | 374 | def event_sanity_check(field): 375 | if isinstance(field,list): 376 | if len(field) == 0: 377 | return field 378 | else: 379 | if isinstance(field[0],tuple): 380 | return field[0][0] 381 | else: 382 | return field[0] 383 | elif isinstance(field,tuple): 384 | return field[0] 385 | elif isinstance(field,str): 386 | return field 387 | 388 | def field_filter(field,key): 389 | # add logic here to filter fields and troubleshoot 390 | if key == "Hashes": 391 | md5 = "" 392 | sha1 = "" 393 | sha256 = "" 394 | imphash = "" 395 | if len(field) == 0: 396 | return md5, sha1, sha256, imphash 397 | else: 398 | hashes = field.split(",") 399 | for hash in hashes: 400 | if hash.startswith("MD5="): 401 | md5 = hash.strip("MD5=") 402 | if hash.startswith("SHA1="): 403 | sha1 = hash.strip("SHA1=") 404 | if hash.startswith("SHA256="): 405 | sha256 = hash.strip("SHA256=") 406 | if hash.startswith("IMPHASH="): 407 | imphash = hash.strip("IMPHASH=") 408 | return md5, sha1, sha256, imphash 409 | 410 | def check_type(object, type_name): 411 | if str(type(object)).find(type_name) != -1: 412 | return True 413 | 414 | return False 415 | 416 | def get_value_from_list(rex, record_data): 417 | obj_list = rex.findall(record_data) 418 | 419 | result = [] 420 | try: 421 | if check_type(obj_list, "list") and len(obj_list) > 0: 422 | if check_type(obj_list[0], "list"): 423 | if len(obj_list[0]) > 1 and len(obj_list[0][1]) > 0: 424 | result = obj_list[0][1].strip() 425 | elif len(obj_list[0][0]) > 0: 426 | result = obj_list[0][0].strip() 427 | elif check_type(obj_list[0], "str"): 428 | if len(obj_list) > 1 and len(obj_list[1]) > 0: 429 | result = obj_list[1].strip() 430 | elif len(obj_list[0]) > 0: 431 | result = obj_list[0].strip() 432 | else: 433 | result = obj_list 434 | else: 435 | result = obj_list 436 | except Exception as e: 437 | print("[-] get_value_from_list: error= " + str(e)) 438 | print(rex) 439 | 440 | return result 441 | 442 | def change_key_names(json_object, key_mapping): 443 | """ 444 | Change key names in a JSON object based on the provided mapping. 445 | 446 | Parameters: 447 | - json_object: The input JSON object. 448 | - key_mapping: A dictionary specifying the mapping from old keys to new keys. 449 | 450 | Returns: 451 | - A new JSON object with updated key names. 452 | """ 453 | if not isinstance(json_object, dict): 454 | # If the input is not a dictionary, return it unchanged 455 | return json_object 456 | 457 | new_object = {} 458 | for old_key, value in json_object.items(): 459 | new_key = key_mapping.get(old_key, old_key) 460 | if isinstance(value, dict): 461 | # If the value is a nested dictionary, recursively update its keys 462 | new_value = change_key_names(value, key_mapping) 463 | elif isinstance(value, list): 464 | # If the value is a list, recursively update keys in list items 465 | new_value = [change_key_names(item, key_mapping) for item in value] 466 | else: 467 | new_value = value 468 | new_object[new_key] = new_value 469 | 470 | return new_object 471 | 472 | def change_array(json_array, key_mapping): 473 | new_array = [] 474 | for json_object in json_array: 475 | new_array.append(change_key_names(json_object, key_mapping)) 476 | 477 | return new_array 478 | 479 | field_mapping = { 480 | "ProcessId": "ProcessId", 481 | "Level": "Level", 482 | "Task Category": "Task Category", 483 | "RuleName": "RuleName", 484 | "ProcessGuid": "ProcessGuid", 485 | "Image": "Image", 486 | "UtcTime": "Timestamp", 487 | "Event ID": "EventID", 488 | "FileVersion": "FileVersion", 489 | "Description": "Description", 490 | "Product": "Product", 491 | "Company": "Company", 492 | "OriginalFileName": "OriginalFileName", 493 | "CommandLine": "Command_line", 494 | "CurrentDirectory": "CurrentDirectory", 495 | "User": "User", 496 | "LogonGuid": "LogonGuid", 497 | "LogonId": "LogonId", 498 | "TerminalSessionId": "TerminalSessionId", 499 | "IntegrityLevel": "IntegrityLevel", 500 | "Hashes": "Hashes", 501 | "ParentProcessGuid": "ParentProcessGuid", 502 | "ParentProcessId": "ParentProcessId", 503 | "ParentImage": "ParentImage", 504 | "ParentCommandLine": "pid" 505 | # ... add other mappings as needed 506 | } 507 | 508 | def csv_string_to_json(file): 509 | f = open(file, mode="r", encoding="utf-8") 510 | csv_string = f.read() 511 | f.close() 512 | 513 | csv_string = csv_string.replace("\ufeff", "") 514 | 515 | data = [] 516 | # Create a file-like object from the CSV string 517 | csv_file = io.StringIO(csv_string) 518 | 519 | # Read CSV data 520 | csv_reader = csv.DictReader(csv_file) 521 | data = [row for row in csv_reader] 522 | 523 | 524 | # Convert to JSON 525 | json_data_string = json.dumps(data, indent=2) 526 | 527 | json_data = json.loads(json_data_string) 528 | 529 | for i in range(len(json_data)): 530 | if 'null' in json_data[i]: 531 | json_temp = convert_log_to_json(json_data[i]['null'][0]) 532 | 533 | for key, value in json_temp.items(): 534 | json_data[i][key] = value 535 | 536 | json_data = change_array(json_data, field_mapping) 537 | 538 | return json_data 539 | 540 | def parse_timestamp(timestamp_str): 541 | # Convert timestamp string to datetime object 542 | return datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S.%f') 543 | 544 | def parse_hashes(hashes_str): 545 | # Split the hashes string into a list of key-value pairs 546 | hash_pairs = hashes_str.split(', ') 547 | # Create a dictionary from the key-value pairs 548 | return {key: value for key, value in [pair.split('=') for pair in hash_pairs]} 549 | 550 | def convert_log_to_json(log_text): 551 | # Define a regex pattern to extract key-value pairs 552 | pattern = re.compile(r'(\w+): (.+?)\n') 553 | 554 | # Use regex to find all key-value pairs in the log text 555 | matches = pattern.findall(log_text) 556 | 557 | # Create a dictionary from the matches 558 | log_dict = dict(matches) 559 | 560 | # Convert specific fields to appropriate types 561 | #log_dict['UtcTime'] = parse_timestamp(log_dict['UtcTime']) 562 | #log_dict['Hashes'] = parse_hashes(log_dict['Hashes']) 563 | 564 | return log_dict 565 | 566 | #========================================== END OF SPRAY Detect 567 | 568 | #def sigmahq(): 569 | ## we need to convert the .yml to varible 570 | ## store all .yml files values to them varible 571 | ## compare the .yml varible values with .xml varible values 572 | ## prin tthe result with .yml tag value. 573 | 574 | def print_colored(text, color): 575 | print(color + text + Style.RESET_ALL) 576 | 577 | from colorama import Fore 578 | 579 | def LOGO(): 580 | bcolor_random = [Fore.RED, Fore.CYAN, Fore.MAGENTA, Fore.BLUE, Fore.YELLOW, 581 | Fore.GREEN] 582 | random.shuffle(bcolor_random) 583 | x = bcolor_random[0] + """ 584 | 585 | ████████╗██╗░░██╗██████╗░███████╗░█████╗░████████╗  ██╗░░██╗░█████╗░██╗░░░██╗███╗░░██╗██████╗░ 586 | ╚══██╔══╝██║░░██║██╔══██╗██╔════╝██╔══██╗╚══██╔══╝  ██║░░██║██╔══██╗██║░░░██║████╗░██║██╔══██╗ 587 | ░░░██║░░░███████║██████╔╝█████╗░░███████║░░░██║░░░  ███████║██║░░██║██║░░░██║██╔██╗██║██║░░██║ 588 | ░░░██║░░░██╔══██║██╔══██╗██╔══╝░░██╔══██║░░░██║░░░  ██╔══██║██║░░██║██║░░░██║██║╚████║██║░░██║ 589 | ░░░██║░░░██║░░██║██║░░██║███████╗██║░░██║░░░██║░░░  ██║░░██║╚█████╔╝╚██████╔╝██║░╚███║██████╔╝ 590 | ░░░╚═╝░░░╚═╝░░╚═╝╚═╝░░╚═╝╚══════╝╚═╝░░╚═╝░░░╚═╝░░░  ╚═╝░░╚═╝░╚════╝░░╚═════╝░╚═╝░░╚══╝╚═════╝░ 591 | 592 | \n""" 593 | 594 | for c in x: 595 | print(c, end='') 596 | sys.stdout.flush() 597 | sleep(0.0004) 598 | y = "\t||||||||||||||||||||||||||||||||||||||||||||||||||||||\n" 599 | for c in y: 600 | print(Fore.RED + c, end='') 601 | sys.stdout.flush() 602 | sleep(0.0005) 603 | y = "\t|| THREAT HOUND ||\n" 604 | for c in y: 605 | print(Fore.WHITE + c, end='') 606 | sys.stdout.flush() 607 | sleep(0.0005) 608 | x = "\t|| ||\n" 609 | for c in x: 610 | print(Fore.WHITE + c, end='') 611 | sys.stdout.flush() 612 | sleep(0.0005) 613 | z = "\t|| This Tool Made BY: Mohamed Alzhrani ||\n" 614 | for c in z: 615 | print(Fore.WHITE + c, end='') 616 | sys.stdout.flush() 617 | sleep(0.0005) 618 | y = "\t||||||||||||||||||||||||||||||||||||||||||||||||||||||\n" 619 | for c in y: 620 | print(Fore.RED + c, end='') 621 | sys.stdout.flush() 622 | sleep(0.0005) 623 | y = "\t|| http://github.com/MazX0p ||\n" 624 | for c in y: 625 | print(Fore.WHITE + c, end='') 626 | sys.stdout.flush() 627 | sleep(0.0005) 628 | 629 | y = "\t||||||||||||||||||||||||||||||||||||||||||||||||||||||\n" 630 | for c in y: 631 | print(Fore.RED + c, end='') 632 | sys.stdout.flush() 633 | sleep(0.0065) 634 | 635 | print(Fore.GREEN + c) 636 | 637 | def list_files(startpath): 638 | filelist = [] 639 | for root, dirs, files in os.walk(startpath): 640 | for f in files: 641 | if f.find(".evtx") != -1 or f.find(".csv") != -1: 642 | #print(root + "\\" + f) 643 | if get_os_type() == "Windows": 644 | filelist.append(root + "/" + f) 645 | else: 646 | filelist.append(root + "\\" + f) 647 | 648 | return filelist 649 | 650 | def parse_arguments(): 651 | parser = argparse.ArgumentParser(description="THREAT HOUND") 652 | 653 | # Add arguments 654 | parser.add_argument("--path", help="Path to the file(evtx, csv) or directory", required=False) 655 | parser.add_argument("--sigma", "-s", help="Path of custom sigma folder", required=False) 656 | parser.add_argument("--form", "-f", action="store_true", help="Display a form", required=False) 657 | 658 | if len(sys.argv) == 1: 659 | parser.print_help() 660 | sys.exit(1) 661 | 662 | args = parser.parse_args() 663 | 664 | if args.path == None and args.form == None: 665 | parser.print_help() 666 | sys.exit(1) 667 | 668 | return args 669 | 670 | class CustomFilterProxyModel(QSortFilterProxyModel): 671 | def __init__(self, parent=None): 672 | super().__init__(parent) 673 | self.filter_value = "" 674 | 675 | def setFilterValue(self, value): 676 | self.filter_value = value 677 | self.invalidateFilter() 678 | 679 | def filterAcceptsRow(self, source_row, source_parent): 680 | # Override the filter method to check for exact match 681 | for column in range(self.sourceModel().columnCount()): 682 | index = self.sourceModel().index(source_row, column, source_parent) 683 | text = self.sourceModel().data(index, Qt.DisplayRole) 684 | if self.filter_value.lower() == text.lower(): 685 | return True 686 | return False 687 | 688 | class Ui_Form(object): 689 | def setupUi(self, Form): 690 | Form.setObjectName("Form") 691 | Form.resize(1532, 861) 692 | self.horizontalLayoutWidget = QtWidgets.QWidget(Form) 693 | self.horizontalLayoutWidget.setGeometry(QtCore.QRect(20, 20, 721, 41)) 694 | self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget") 695 | self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget) 696 | self.horizontalLayout.setContentsMargins(0, 0, 0, 0) 697 | self.horizontalLayout.setObjectName("horizontalLayout") 698 | self.label = QtWidgets.QLabel(self.horizontalLayoutWidget) 699 | font = QtGui.QFont() 700 | font.setPointSize(12) 701 | self.label.setFont(font) 702 | self.label.setObjectName("label") 703 | self.horizontalLayout.addWidget(self.label) 704 | self.lineEdit = QtWidgets.QLineEdit(self.horizontalLayoutWidget) 705 | font = QtGui.QFont() 706 | font.setPointSize(12) 707 | self.lineEdit.setFont(font) 708 | self.lineEdit.setObjectName("lineEdit") 709 | self.horizontalLayout.addWidget(self.lineEdit) 710 | 711 | self.pushButton = QtWidgets.QPushButton(self.horizontalLayoutWidget) 712 | font = QtGui.QFont() 713 | font.setPointSize(12) 714 | self.pushButton.setFont(font) 715 | self.pushButton.setObjectName("pushButton") 716 | self.pushButton.clicked.connect(self.show_folder_dialog) 717 | self.horizontalLayout.addWidget(self.pushButton) 718 | 719 | self.pushButton_2 = QtWidgets.QPushButton(self.horizontalLayoutWidget) 720 | font = QtGui.QFont() 721 | font.setPointSize(12) 722 | self.pushButton_2.setFont(font) 723 | self.pushButton_2.setObjectName("pushButton_2") 724 | self.pushButton_2.clicked.connect(self.show_file_dialog) 725 | self.horizontalLayout.addWidget(self.pushButton_2) 726 | 727 | self.horizontalLayoutWidget_2 = QtWidgets.QWidget(Form) 728 | self.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(750, 20, 761, 41)) 729 | self.horizontalLayoutWidget_2.setObjectName("horizontalLayoutWidget_2") 730 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_2) 731 | self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) 732 | self.horizontalLayout_2.setObjectName("horizontalLayout_2") 733 | 734 | self.label_2 = QtWidgets.QLabel(self.horizontalLayoutWidget_2) 735 | font = QtGui.QFont() 736 | font.setPointSize(12) 737 | self.label_2.setFont(font) 738 | self.label_2.setObjectName("label_2") 739 | self.horizontalLayout_2.addWidget(self.label_2) 740 | 741 | self.lineEdit_2 = QtWidgets.QLineEdit(self.horizontalLayoutWidget_2) 742 | font = QtGui.QFont() 743 | font.setPointSize(12) 744 | self.lineEdit_2.setFont(font) 745 | self.lineEdit_2.setObjectName("lineEdit_2") 746 | self.horizontalLayout_2.addWidget(self.lineEdit_2) 747 | 748 | self.pushButton_4 = QtWidgets.QPushButton(self.horizontalLayoutWidget_2) 749 | font = QtGui.QFont() 750 | font.setPointSize(12) 751 | self.pushButton_4.setFont(font) 752 | self.pushButton_4.setObjectName("pushButton_4") 753 | self.pushButton_4.clicked.connect(self.show_folder_dialog_sigma) 754 | self.horizontalLayout_2.addWidget(self.pushButton_4) 755 | 756 | self.pushButton_3 = QtWidgets.QPushButton(self.horizontalLayoutWidget_2) 757 | font = QtGui.QFont() 758 | font.setPointSize(12) 759 | self.pushButton_3.setFont(font) 760 | self.pushButton_3.setObjectName("pushButton_3") 761 | self.pushButton_3.clicked.connect(self.do_start) 762 | #self.pushButton_3.clicked.connect(self.start_progress) 763 | self.horizontalLayout_2.addWidget(self.pushButton_3) 764 | 765 | # Create the data model 766 | self.model = QStandardItemModel(self) 767 | 768 | # Set headers 769 | self.model.setHorizontalHeaderLabels(["DateTime", "EventID", "User", "Other", "RuleId"]) 770 | 771 | self.tableView = QtWidgets.QTableView(Form) 772 | self.tableView.setGeometry(QtCore.QRect(580, 100, 931, 711)) 773 | self.tableView.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) 774 | self.tableView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) 775 | self.tableView.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerItem) 776 | self.tableView.setObjectName("tableView") 777 | 778 | # Set the model to the QTableView 779 | self.tableView.setModel(self.model) 780 | 781 | # Create a proxy model for filtering 782 | self.proxy_model = QSortFilterProxyModel(self) 783 | self.proxy_model.setSourceModel(self.model) 784 | self.tableView.setModel(self.proxy_model) 785 | 786 | """ 787 | # Create a proxy model for filtering 788 | self.proxy_model = CustomFilterProxyModel(self) 789 | self.proxy_model.setSourceModel(self.model) 790 | self.tableView.setModel(self.proxy_model) 791 | """ 792 | 793 | self.label_4 = QtWidgets.QLabel(Form) 794 | self.label_4.setGeometry(QtCore.QRect(1190, 70, 131, 31)) 795 | font = QtGui.QFont() 796 | font.setPointSize(12) 797 | self.label_4.setFont(font) 798 | self.label_4.setObjectName("label_4") 799 | self.lineEdit_3 = QtWidgets.QLineEdit(Form) 800 | self.lineEdit_3.setPlaceholderText("Search...") 801 | self.lineEdit_3.textChanged.connect(self.filter_data) 802 | self.lineEdit_3.setGeometry(QtCore.QRect(1340, 70, 167, 25)) 803 | font = QtGui.QFont() 804 | font.setPointSize(12) 805 | self.lineEdit_3.setFont(font) 806 | self.lineEdit_3.setObjectName("lineEdit_3") 807 | 808 | # Create the data model 809 | self.model_rule = QStandardItemModel(self) 810 | 811 | # Set headers 812 | self.model_rule.setHorizontalHeaderLabels(["Count", "RuleName", "FalsePositives"]) 813 | 814 | self.tableView_rule = QtWidgets.QTableView(Form) 815 | self.tableView_rule.setGeometry(QtCore.QRect(20, 100, 551, 711)) 816 | self.tableView_rule.setObjectName("tableView_rule") 817 | 818 | # Set the model to the QTableView 819 | self.tableView_rule.setModel(self.model_rule) 820 | 821 | # Click event for all rows 822 | self.tableView_rule.clicked.connect(self.handle_table_click) 823 | 824 | self.pushButton_showall = QtWidgets.QPushButton(Form) 825 | self.pushButton_showall.setGeometry(QtCore.QRect(1250, 70, 75, 27)) 826 | font = QtGui.QFont() 827 | font.setPointSize(12) 828 | self.pushButton_showall.setFont(font) 829 | self.pushButton_showall.setObjectName("pushButton_showall") 830 | self.pushButton_showall.clicked.connect(self.click_button_showall) 831 | 832 | self.pushButton_save = QtWidgets.QPushButton(Form) 833 | self.pushButton_save.setGeometry(QtCore.QRect(1160, 70, 75, 27)) 834 | font = QtGui.QFont() 835 | font.setPointSize(12) 836 | self.pushButton_save.setFont(font) 837 | self.pushButton_save.setObjectName("pushButton_save") 838 | self.pushButton_save.clicked.connect(self.click_button_save) 839 | 840 | self.label_3 = QtWidgets.QLabel(Form) 841 | self.label_3.setGeometry(QtCore.QRect(20, 820, 551, 29)) 842 | font = QtGui.QFont() 843 | font.setPointSize(12) 844 | self.label_3.setFont(font) 845 | self.label_3.setLineWidth(50) 846 | self.label_3.setObjectName("label_3") 847 | self.progressBar = QtWidgets.QProgressBar(Form) 848 | self.progressBar.setGeometry(QtCore.QRect(578, 830, 971, 21)) 849 | self.progressBar.setProperty("value", 24) 850 | self.progressBar.setObjectName("progressBar") 851 | self.start_progress() 852 | 853 | self.retranslateUi(Form) 854 | QtCore.QMetaObject.connectSlotsByName(Form) 855 | 856 | def detect_events_security_log(self, file_name): 857 | global Result_Event_list 858 | global Result_Rule_list 859 | global MatchedRulesAgainstLogs 860 | 861 | MatchedRulesAgainstLogs = dict() 862 | 863 | x = 100 / len(file_name) 864 | pos = 0 865 | 866 | for file in file_name: 867 | Event_list = [] 868 | 869 | if file.find(".evtx") != -1: 870 | print("[-] parsing file: " + file) 871 | parser = PyEvtxParser(file) 872 | 873 | """ 874 | max_threads = 100 875 | 876 | # Define parameters for your tasks 877 | params_list = [(record, 1) for record in parser.records()] 878 | 879 | print("[-] detect_events_security_log: len(params_list)= " + str(len(params_list))) 880 | 881 | with concurrent.futures.ThreadPoolExecutor(max_threads) as executor: 882 | futures = [executor.submit(analysis_record, i, *params) for i, params in enumerate(params_list)] 883 | #futures = [executor.submit(task, i, ) for i in range(RuleFilesList)] 884 | 885 | # Wait for all tasks to complete 886 | concurrent.futures.wait(futures) 887 | """ 888 | 889 | for record in parser.records(): 890 | record_data = record['data'] 891 | EventID = EventID_rex.findall(record_data) 892 | 893 | #Parsing starts here 894 | if len(EventID) > 0: 895 | LogonType = get_value_from_list(LogonType_rex, record_data) 896 | UtcTime = get_value_from_list(UtcTime_rex, record_data) 897 | UserName_2 = get_value_from_list(User_Name_rex, record_data) 898 | IpAddress = get_value_from_list(Source_IP_IpAddress_rex, record_data) 899 | SourceIp = get_value_from_list(Source_IP_SourceIp_rex, record_data) 900 | Destination_IP = get_value_from_list(DestinationIp_rex, record_data) 901 | SourcePort = get_value_from_list(SourcePort_rex, record_data) 902 | IpPort = get_value_from_list(IpPort_rex, record_data) 903 | DestinationPort = get_value_from_list(DestinationPort_rex, record_data) 904 | SourceHostname = get_value_from_list(SourceHostname_rex, record_data) 905 | ProcessId = get_value_from_list(ProcessId_rex, record_data) 906 | Protocol = get_value_from_list(Protocol_rex, record_data) 907 | Command_line = get_value_from_list(Process_Command_Line_rex, record_data) 908 | FileVersion = get_value_from_list(FileVersion_rex, record_data) 909 | Hashes = get_value_from_list(Hashes_rex, record_data) 910 | Description = get_value_from_list(Description_rex, record_data) 911 | Computer_Name = get_value_from_list(Computer_Name_rex, record_data) 912 | Computer = Computer_Name_rex.findall(record_data) 913 | ParentProcessId = get_value_from_list(ParentProcessId_rex, record_data) 914 | ParentImage = get_value_from_list(ParentImage_rex, record_data) 915 | ParentCommandLine = get_value_from_list(ParentCommandLine_rex, record_data) 916 | ParentCommandLine = html.unescape(ParentCommandLine) 917 | Channel = get_value_from_list(Channel_rex, record_data) 918 | ProviderName = get_value_from_list(Provider_rex, record_data) 919 | EventSourceName = get_value_from_list(EventSourceName_rex, record_data) 920 | ServiceName = get_value_from_list(ServiceName_rex, record_data) 921 | Service_Image_Path = get_value_from_list(Service_Image_Path_rex, record_data) 922 | ServiceType = get_value_from_list(ServiceType_rex, record_data) 923 | ServiceStartType = get_value_from_list(ServiceStartType_rex, record_data) 924 | Service_Account_Name = get_value_from_list(Service_Account_Name_rex, record_data) 925 | Account_Name = get_value_from_list(AccountName_rex, record_data) 926 | Account_Domain = get_value_from_list(AccountDomain_rex, record_data) 927 | ShareName = get_value_from_list(ShareName_rex, record_data) 928 | ShareLocalPath = get_value_from_list(ShareLocalPath_rex, record_data) 929 | RelativeTargetName = get_value_from_list(RelativeTargetName_rex, record_data) 930 | Task_Name = get_value_from_list(TaskName_rex, record_data) 931 | TargetAccount_Name = get_value_from_list(AccountName_Target_rex, record_data) 932 | Target_Account_Domain = get_value_from_list(Account_Domain_Target_rex, record_data) 933 | Workstation_Name = get_value_from_list(Workstation_Name_rex, record_data) 934 | PowerShell_Command = get_value_from_list(Powershell_Command_rex, record_data) 935 | New_Process_Name = get_value_from_list(New_Process_Name_rex, record_data) 936 | TokenElevationType = get_value_from_list(TokenElevationType_rex, record_data) 937 | PipeName = get_value_from_list(PipeName_rex, record_data) 938 | ImageName = get_value_from_list(Image_rex, record_data) 939 | ServicePrincipalNames = get_value_from_list(ServicePrincipalNames_rex, record_data) 940 | SamAccountName = get_value_from_list(SamAccountName_rex, record_data) 941 | NewTargetUserName = get_value_from_list(NewTargetUserName_rex, record_data) 942 | OldTargetUserName = get_value_from_list(OldTargetUserName_rex, record_data) 943 | TargetProcessId = get_value_from_list(TargetProcessId_rex, record_data) 944 | TargetProcessGuid = get_value_from_list(TargetProcessGuid_rex, record_data) 945 | SourceProcessGuid = get_value_from_list(SourceProcessGuid_rex, record_data) 946 | SourceProcessId = get_value_from_list(SourceProcessId_rex, record_data) 947 | SourceImage = get_value_from_list(SourceImage_rex, record_data) 948 | TargetImage = get_value_from_list(TargetImage_rex, record_data) 949 | GrantedAccess = get_value_from_list(GrantedAccess_rex, record_data) 950 | CallTrace = get_value_from_list(CallTrace_rex, record_data) 951 | PowershellUserId = get_value_from_list(PowershellUserId_rex, record_data) 952 | PowershellHostApplication = get_value_from_list(PowershellHostApplication_rex, record_data) 953 | Command_Name = get_value_from_list(Command_Name_rex, record_data) 954 | CommandLine_powershell = get_value_from_list(CommandLine_powershell_rex, record_data) 955 | PowerShellCommand = get_value_from_list(PowerShellCommand_rex, record_data) 956 | ScriptName = get_value_from_list(ScriptName_rex, record_data) 957 | #==================== 958 | Logon_Process = get_value_from_list(Logon_Process_rex, record_data) 959 | Key_Length = get_value_from_list(Key_Length_rex, record_data) 960 | Security_ID = get_value_from_list(Security_ID_rex, record_data) 961 | Process_Name = get_value_from_list(Process_Name_sec_rex, record_data) 962 | Object_Name = get_value_from_list(Object_Name_rex, record_data) 963 | ObjectType = ObjectType_rex.findall(record_data) 964 | ObjectServer = ObjectServer_rex.findall(record_data) 965 | 966 | AccessMask = AccessMask_rex.findall(record_data) 967 | 968 | Task_Content = str(TaskContent_rex.findall(record_data)) 969 | Task_arguments = get_value_from_list(re.compile("Arguments(.*)/Arguments"), Task_Content) 970 | Task_Command = get_value_from_list(re.compile("Command(.*)/Command"), Task_Content) 971 | 972 | ##The function will probably be called here . Just adding the comment for now. 973 | ### Create JSON of Event 974 | Event = { 975 | "Timestamp" : UtcTime, 976 | "EventID" : EventID, 977 | "Computer_Name" : Computer_Name, 978 | "AccessMask" : AccessMask, 979 | "AccountName" : Service_Account_Name, 980 | "Action" : Action_rex.findall(record_data), 981 | "AuditPolicyChanges" : Changes_rex.findall(record_data), 982 | "CallTrace" : CallTrace, 983 | "CallerProcessName":Process_Name, 984 | "Channel" : Channel, 985 | "CommandLine" : Sysmon_CommandLine_rex.findall(record_data), 986 | "Company" : Sysmon_Company_rex.findall(record_data), 987 | "ContextInfo" : Powershell_ContextInfo.findall(record_data), 988 | "CurrentDirectory" : Sysmon_CurrentDirectory_rex.findall(record_data), 989 | "Description" : Description, 990 | "DestinationHostname" : Sysmon_DestinationHostname_rex.findall(record_data), 991 | "DestinationIp" : Destination_IP, 992 | "DestinationIsIpv6" : Destination_Is_Ipv6_rex.findall(record_data), 993 | "DestinationPort" : DestinationPort, 994 | "Details" : Sysmon_Details_rex.findall(record_data), 995 | "EngineVersion" : EngineVersion_rex.findall(record_data), 996 | "FileName" : Sysmon_FileName_rex.findall(record_data), 997 | "FileVersion" : FileVersion, 998 | "GrantedAccess" : GrantedAccess, 999 | "GrandparentCommandLine" : GrandparentCommandLine_rex.findall(record_data), 1000 | "Hashes" : Hashes, 1001 | "HostApplication" : HostApplication_rex.findall(record_data), 1002 | "Image" : ImageName, 1003 | "ImageFileName" : Sysmon_ImageFileName_rex.findall(record_data), 1004 | "ImageLoaded" : Sysmon_ImageLoaded_rex.findall(record_data), 1005 | "ImagePath" : Service_Image_Path, 1006 | "Initiated" : Sysmon_Initiated_rex.findall(record_data), 1007 | "IntegrityLevel" : Sysmon_IntegrityLevel_rex.findall(record_data), 1008 | "IpAddress" : IpAddress, 1009 | "KeyLength" : Key_Length, 1010 | "LogonProcessName" : Logon_Process, 1011 | "LogonType" : LogonType, 1012 | "NewTargetUserName" : NewTargetUserName, 1013 | "ObjectName" : Object_Name, 1014 | "ObjectServer" : ObjectServer, 1015 | "ObjectType" : ObjectType, 1016 | "OldTargetUserName" : OldTargetUserName, 1017 | "OriginalFileName" : Sysmon_OriginalFileName_rex.findall(record_data), 1018 | "ParentCommandLine" : ParentCommandLine, 1019 | "ParentImage" : ParentImage, 1020 | "ParentUser" : Sysmon_ParentUser_rex.findall(record_data), 1021 | "Path" : Path_rex.findall(record_data), 1022 | "Payload" : Powershell_Payload.findall(record_data), 1023 | "PipeName" : PipeName, 1024 | "ProcessId" : ProcessId, 1025 | "Product" : Sysmon_Product_rex.findall(record_data), 1026 | "Protocol" : Protocol, 1027 | "ProviderName" : ProviderName, 1028 | "RelativeTargetName" : RelativeTargetName, 1029 | "SamAccountName" : SamAccountName, 1030 | "ScriptBlockText" : PowerShell_Command, 1031 | "ServiceName" : ServiceName, 1032 | "ServicePrincipalNames" : ServicePrincipalNames, 1033 | "ServiceStartType" : ServiceStartType, 1034 | "ServiceType" : ServiceType, 1035 | "ShareName" : ShareName, 1036 | "Signed" : Signed_rex.findall(record_data), 1037 | "Signature" : Signature_rex.findall(record_data), 1038 | "SourceImage" : SourceImage, 1039 | "SourceIp" : SourceIp, 1040 | "SourcePort" : SourcePort, 1041 | "EventSourceName" : EventSourceName, 1042 | "StartFunction" : Sysmon_StartFunction_rex.findall(record_data), 1043 | "StartModule" : Sysmon_StartModule_rex.findall(record_data), 1044 | "State" : State_rex.findall(record_data), 1045 | "Status" : Status_rex.findall(record_data), 1046 | "SubjectDomainName" : Account_Domain, 1047 | "SubjectUserName" : Account_Name, 1048 | "SubjectUserSid" : Security_ID, 1049 | "TargetImage" : TargetImage, 1050 | "TargetObject" : Sysmon_TargetObject_rex.findall(record_data), 1051 | "TargetUserName" : TargetAccount_Name, 1052 | "TargetUserSid" : Security_ID_Target_rex.findall(record_data), 1053 | "Task_Name" : Task_Name, 1054 | "TicketEncryptionType" : TicketEncryptionType_rex.findall(record_data), 1055 | "TicketOptions" : TicketOptions_rex.findall(record_data), 1056 | "User" : UserName_2, 1057 | "UserName_2" : UserName_2, 1058 | "UserName" : Task_Deleted_User_rex.findall(record_data), 1059 | "WorkstationName" : Workstation_Name, 1060 | "ParentProcessId" : ParentProcessId, 1061 | "Command_line" : Command_line, 1062 | "Task_arguments" : Task_arguments, 1063 | "Task_Command" : Task_Command, 1064 | "Target_Account_Domain" : Target_Account_Domain, 1065 | "PowerShellCommand" : PowerShellCommand, 1066 | "CommandLine_powershell" : CommandLine_powershell, 1067 | "PowershellHostApplication" : PowershellHostApplication, 1068 | "PowershellUserId" : PowershellUserId, 1069 | "ScriptName" : ScriptName, 1070 | "New_Process_Name" : New_Process_Name, 1071 | "SourceProcessId" : SourceProcessId, 1072 | "TargetProcessId" : TargetProcessId 1073 | } 1074 | 1075 | Event_list.append(Event) 1076 | elif file.find(".csv") != -1: 1077 | Event_list = csv_string_to_json(file) 1078 | 1079 | y = x / len(Event_list) 1080 | for Event in Event_list: 1081 | pos = pos + y 1082 | 1083 | if hasattr(self, "progressBar"): 1084 | self.progressBar.setValue(int(pos)) 1085 | 1086 | PASS = False 1087 | PASS1 = False 1088 | EventID = Event["EventID"] 1089 | 1090 | if not "Command_line" in Event: 1091 | Event['Command_line'] = "" 1092 | 1093 | if not "Computer_Name" in Event: 1094 | Event['Computer_Name'] = "" 1095 | 1096 | if not "CommandLine" in Event: 1097 | Event['CommandLine'] = Event['Command_line'] 1098 | 1099 | if not "ParentCommandLine" in Event: 1100 | Event['ParentCommandLine'] = "" 1101 | 1102 | if not "UserName" in Event: 1103 | if "User" in Event: 1104 | Event['UserName'] = Event["User"] 1105 | else: 1106 | Event['UserName'] = "" 1107 | 1108 | if not "SourceIp" in Event: 1109 | Event['SourceIp'] = "" 1110 | 1111 | if not "DestinationIp" in Event: 1112 | Event['DestinationIp'] = "" 1113 | 1114 | if not "DestinationIp" in Event: 1115 | Event['DestinationIp'] = "" 1116 | 1117 | for key in Event: 1118 | Event[key] = event_sanity_check(Event[key]) 1119 | 1120 | if "Hashes" in Event: 1121 | # minor field corrections 1122 | Event["md5"], Event["sha1"], Event["sha256"], Event["Imphash"] = field_filter(Event["Hashes"], "Hashes") 1123 | #Event.pop('Hashes', None) 1124 | else: 1125 | Event["md5"] = "" 1126 | Event["sha1"] = "" 1127 | Event["sha256"] = "" 1128 | Event["Imphash"] = "" 1129 | 1130 | #check for matched rules 1131 | #Loader function 1132 | 1133 | #print(Event) 1134 | Matched_Rules = sigma_manager.MatchRules(Event) 1135 | 1136 | #print("\n[-] MatchRules: Scanning end len(Matched_Rules)= " + str(len(Matched_Rules))) 1137 | #exit(0) 1138 | #if len(Matched_Rules) > 0: 1139 | # input() 1140 | 1141 | if len(Matched_Rules) == 0: 1142 | pass 1143 | else: 1144 | for matched_rule in range(0,len(Matched_Rules)): 1145 | rule_title = Matched_Rules[matched_rule]["title"] 1146 | if "falsepositives" in Matched_Rules[matched_rule]: 1147 | rule_fp = Matched_Rules[matched_rule]["falsepositives"] 1148 | else: 1149 | rule_fp = ["None"] 1150 | if rule_title in MatchedRulesAgainstLogs.keys(): 1151 | MatchedRulesAgainstLogs[rule_title]["Events"].append(Event) 1152 | else: 1153 | MatchedRulesAgainstLogs[rule_title] = { 1154 | "falsepositives" : rule_fp, 1155 | "Events" : list() 1156 | } 1157 | MatchedRulesAgainstLogs[rule_title]["Events"].append(Event) 1158 | 1159 | #Detect any log that contain suspicious process name or argument 1160 | if EventID[0]=="3": 1161 | try: 1162 | for i in Susp_exe: 1163 | if i in record_data.lower(): 1164 | print("\n__________ " + Event['Timestamp'] + " __________ \n\n ", end='') 1165 | print_colored(" Found Suspicios "+ i +" Process Make TCP Connection", Fore.RED) 1166 | print(" [+] Source IP : ( %s ) \n " % Event['SourceIp'], end='') 1167 | print(" [+] Source Port : ( %s ) \n " % Event['SourcePort'], end='') 1168 | print(" [+] User Name : ( %s ) \n " % Event['UserName_2'], end='') 1169 | print(" [+] Host Name : ( %s ) \n " % Event['SourceHostname'], end='') 1170 | print(" [+] Destination IP : ( %s ) \n " % Event['DestinationIp'], end='') 1171 | print(" [+] Destination port : ( %s ) \n " % Event['DestinationPort'], end='') 1172 | print(" [+] Protocol : ( %s ) \n " % Event['Protocol'], end='') 1173 | print(" [+] Process ID : ( %s ) \n " % Event['ProcessId'], end='') 1174 | print("____________________________________________________\n") 1175 | 1176 | PASS = True 1177 | Suspicios_Event3 = i 1178 | 1179 | except Exception as e: 1180 | pass 1181 | 1182 | elif EventID[0]=="1" and PASS== True: 1183 | try: 1184 | hashes = re.findall(r'(?i)(?0: 1396 | PowerShellCommand = html.unescape(Event['PowerShellCommand']) 1397 | CommandLine_powershell = html.unescape(Event['CommandLine_powershell']) 1398 | PowerShellCommand_All = html.unescape(str(Event)) 1399 | PowershellHostApplication = html.unescape(Event['PowershellHostApplication']) 1400 | PowerShellCommand = re.findall(r' (.*)', PowerShellCommand) 1401 | words = [r"Invoke-Mimikatz.ps1"] 1402 | results = [x for x in PowerShellCommand if all(re.search("\\b{}\\b".format(w), x) for w in words)] 1403 | results = results[0].strip() 1404 | 1405 | # detect winrm code execution can you show where i have to work 1406 | if 1 == 1: 1407 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') ### Fix Time 1408 | print_colored(" Winrm Detect !!", Fore.RED)# we need voice call yes 1409 | print(" [+] Computer Name : ( %s ) \n " % Event['Computer_Name'] , end='') 1410 | print(" [+] channel : ( %s ) \n " % Event['Channel'], end='') 1411 | print(" [+] user Name: ( %s ) \n " % Event['PowershellUserId'], end='') 1412 | #print(" [+] Command Name: ( %s ) \n " % Command_Name, end='') 1413 | print(" [+] PowerShell Script: ( %s ) \n " % Event['ScriptName'], end='') 1414 | print(" [+] PowerShell Mode: ( %s ) \n " % CommandLine_powershell, end='') 1415 | print(" [+] PowerShell Command: ( %s ) \n " % PowershellHostApplication, end='') 1416 | for element in PowerShellCommand: 1417 | if 'name="Arguments"' in element: 1418 | print(" [+] PowerShell OutPut: \n ", end='') 1419 | print(element.split('value')[1]) 1420 | print("____________________________________________________\n") 1421 | 1422 | # detect winrm code execution can you show where i have to work 1423 | if results != None: 1424 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') ### Fix Time 1425 | print_colored(" Winrm Invoke-Mimikatz Detect !!", Fore.RED) 1426 | print(" [+] Computer Name: ( %s ) \n " % Event['Computer_Name'] , end='') 1427 | print(" [+] channel : ( %s ) \n " % channel, end='') 1428 | print(" [+] user Name: ( %s ) \n " % Event['PowershellUserId'], end='') 1429 | print(" [+] PowerShell Command: ( %s ) \n " % PowershellHostApplication, end='') 1430 | print(" [+] PowerShell Script: ( %s ) \n " % Event['ScriptName'], end='') 1431 | print(" [+] Mimikatz Command: ( %s ) \n " % results, end='') 1432 | print(bcolor.RED + " [+] PowerShell OutPut:\n ", end='') 1433 | for element in PowerShellCommand: 1434 | print(bcolor.CBLUE + element, end='\n') 1435 | print("____________________________________________________\n") 1436 | 1437 | except Exception as e: 1438 | #print(e) 1439 | pass 1440 | 1441 | # Detect Remote Task Creation 1442 | elif EventID[0]=="5145": 1443 | try: 1444 | # Detect Remote Task Creation via ATSVC named pipe 1445 | if "atsvc" in RelativeTargetName: 1446 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') ### Fix Time 1447 | print_colored(" Suspicios ATSVC Detect !!", Fore.RED) 1448 | print(" [+] Computer Name: ( %s ) \n " % Event['Computer_Name'], end='') 1449 | print(" [+] channel : ( %s ) \n " % Event['Channel'], end='') 1450 | print(" [+] User Name : ( %s ) \n " % Event['SubjectUserName'], end='') 1451 | print(" [+] Account Domain Name : ( %s ) \n " % Event['SubjectDomainName'], end='') 1452 | print(" [+] Source IP : ( %s ) \n " % Event['IpAddress'], end='') 1453 | print(" [+] Source Port : ( %s ) \n " % IpPort, end='') 1454 | print(" [+] Share Name : ( %s ) \n " % Event['ShareName'], end='') 1455 | print(" [+] Local Share Path : ( %s ) \n " % ShareLocalPath, end='') 1456 | print(" [+] File Path : ( %s ) \n " % Evnet['RelativeTargetName'], end='') 1457 | print("____________________________________________________\n") 1458 | 1459 | PASS1 = True 1460 | 1461 | 1462 | except Exception as e: 1463 | pass 1464 | 1465 | # Detect Remote Task Creation via ATSVC named pipe 1466 | elif EventID[0] == "4698" or EventID[0] == "4699" and PASS1 == True: 1467 | try: 1468 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') ### Fix Time 1469 | print_colored(" Remote Task Creation via ATSVC named pipe Detect !!", Fore.RED) 1470 | print(" [+] Computer Name: ( %s ) \n " % Event['Computer_Name'], end='') 1471 | print(" [+] channel : ( %s ) \n " % Event['Channel'], end='') 1472 | print(" [+] User Name : ( %s ) \n " % Event['SubjectUserName'], end='') 1473 | print(" [+] Task Name : ( %s ) \n " % Event['Task_Name'], end='') 1474 | print(" [+] Task Command : ( %s ) \n " % Event['Task_Command'], end='') 1475 | print(" [+] Task Command Arguments : ( %s ) \n " % Event['Task_arguments'], end='') 1476 | print("____________________________________________________\n") 1477 | except Exception as e: 1478 | pass 1479 | 1480 | # Kerberos AS-REP Attack Detect 1481 | if EventID[0] == "4768": 1482 | try: 1483 | if Event['ServiceName'] == "krbtgt": 1484 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') ### Fix Time 1485 | print_colored(" Kerberos AS-REP Attack Detected !", Fore.RED) 1486 | print("[+] User Name : ( %s ) \n" % Event['TargetUserName'], end='') 1487 | print(" [+] Computer Name: ( %s ) \n" % Event['Computer_Name'], end='') 1488 | print(" [+] Channel : ( %s ) \n" % Event['Channel'], end='') 1489 | print(" [+] Service Name : ( %s ) \n" % Event['ServiceName'], end='') 1490 | print(" [+] Domain Name : ( %s ) \n" % Event['Target_Account_Domain'], end='') 1491 | print(" [+] Source IP : ( %s ) \n " % Event['IpAddress'], end='') 1492 | print(" [+] Source Port : ( %s ) \n" % IpPort, end='') 1493 | print("____________________________________________________\n") 1494 | except Exception as e: 1495 | pass 1496 | 1497 | # PowerShell Download Detect 1498 | if EventID[0] == "4104": # TODO Base64 command Detect 1499 | try: 1500 | if len(Computer[0])>0: 1501 | Command = html.unescape(Event['ScriptBlockText']) 1502 | 1503 | IsEncoded = True 1504 | #check if command is encoded 1505 | if isBase64(Command) == False: 1506 | IsEncoded = False 1507 | 1508 | #check if download start 1509 | if IsEncoded == False and "IEX(New-Object Net.WebClient).downloadString" in Event['ScriptBlockText'] or "(New-Object Net.WebClient)" in Event['ScriptBlockText'] or "[System.NET.WebRequest]" in Event['ScriptBlockText']: 1510 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') ### Fix Time 1511 | print_colored(" PowerShell Download Detect !", Fore.RED) 1512 | print("[+] PowerShell Command : ( %s ) \n" % Command, end='') 1513 | print(" [+] Computer : ( %s ) \n" % Event['Computer_Name'], end='') 1514 | print(" [+] Channel : ( %s ) \n" % Event['Channel'], end='') 1515 | print("____________________________________________________\n") 1516 | 1517 | except Exception as e: 1518 | pass 1519 | 1520 | #Detect suspicious process Runing PowerShell Command 1521 | if EventID[0]=="4688": 1522 | Command_unescape = html.unescape(Event['Command_line']) 1523 | try: 1524 | Base64Finder = re.findall(r'(?:[A-Za-z0-9+/]{4}){2,}(?:[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=|[A-Za-z0-9+/][AQgw]==)', Command_unescape) 1525 | 1526 | if "powershell.exe" in Command_unescape.lower() or "powershell" in Command_unescape.lower() and "%%1936" in TokenElevationType: #and "cmd.exe" in Process_Name.lower(): 1527 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') 1528 | print_colored(" [+] Found Suspicios Process Runing PowerShell Command On Full Privilege", Fore.RED) 1529 | print(" [+] Computer Name : ( %s ) \n " % Event['SubjectDomainName'], end='') 1530 | print(" [+] User Name : ( %s ) \n " % Event['SubjectUserName'], end='') 1531 | print(" [+] Process ID : ( %s ) \n " % Event['ProcessId'], end='') 1532 | print(" [+] Process Name : ( %s ) \n " % Event['New_Process_Name'], end='') 1533 | print(" [+] Process Command Line : ( %s ) \n " % Command_unescape, end='') 1534 | if len(Base64Finder[0])>5: 1535 | print(" [+] Base64 Command : ( %s ) \n " % Base64Finder[0], end='') 1536 | print("____________________________________________________\n") 1537 | # PipeName 1538 | pipe = r'\.\pipe' 1539 | # SMBEXEC 1540 | SMBEXEC = r'cmd.exe /q /c echo cd' 1541 | SMBEXEC2 = r'\\127.0.0.1\c$' 1542 | wmiexec = r'cmd.exe /q /c' 1543 | wmiexec2 = r'1> \\127.0.0.1\admin$\__' 1544 | wmiexec3 = r'2>&1' 1545 | msiexec = r'msiexec.exe /i Site24x7WindowsAgent.msi EDITA1=asdasd /qn' 1546 | msiexec2 = r'comsvcs.dll MiniDump C:\windows\temp\logctl.zip full' 1547 | msiexec3 = r'windows\temp\ekern.exe' 1548 | #Detect Privilege esclation "GetSystem" 1549 | if "cmd.exe /c echo" in Command_unescape.lower() and "%%1936" in TokenElevationType and "cmd.exe" in Event['CallerProcessName'].lower() and pipe in Command_unescape.lower(): 1550 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') 1551 | print_colored(" GetSystem Detect By metasploit & Cobalt Strike & Empire & PoshC2", Fore.RED) 1552 | print(" [+] Computer Name : ( %s ) \n " % Event['SubjectDomainName'], end='') 1553 | print(" [+] User Name : ( %s ) \n " % Event['SubjectUserName'], end='') 1554 | print(" [+] Process ID : ( %s ) \n " % Event['ProcessId'], end='') 1555 | print(" [+] Process Name : ( %s ) \n " % Event['New_Process_Name'], end='') 1556 | print(" [+] Process Command Line : ( %s ) \n " % Command_unescape, end='') 1557 | print("____________________________________________________\n") 1558 | #Detect Cmd.exe command 1559 | if "cmd.exe" in Command_unescape.lower() and "%%1936" in TokenElevationType and "cmd.exe" in Event['CallerProcessName'].lower(): 1560 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') 1561 | print_colored(" Found Suspicios Process Runing cmd Command On Full Privilege", Fore.RED) 1562 | print(" [+] Computer Name : ( %s ) \n " % Event['SubjectDomainName'], end='') 1563 | print(" [+] User Name : ( %s ) \n " % Event['SubjectUserName'], end='') 1564 | print(" [+] Process ID : ( %s ) \n " % Event['ProcessId'], end='') 1565 | print(" [+] Process Name : ( %s ) \n " % Event['New_Process_Name'], end='') 1566 | print(" [+] Process Command Line : ( %s ) \n " % Command_unescape, end='') 1567 | print("____________________________________________________\n") 1568 | 1569 | #Detect SMBEXEC 1570 | if SMBEXEC in Command_unescape.lower() and SMBEXEC2 in Command_unescape.lower() and wmiexec3 in Command_unescape.lower() and "%%1936" in TokenElevationType: 1571 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') 1572 | print_colored(" SMBEXEC Detected !!", Fore.RED) 1573 | print(" [+] Computer Name : ( %s ) \n " % Event['SubjectDomainName'], end='') 1574 | print(" [+] User Name : ( %s ) \n " % Event['SubjectUserName'], end='') 1575 | print(" [+] Process ID : ( %s ) \n " % Event['ProcessId'], end='') 1576 | print(" [+] Process Name : ( %s ) \n " % Event['New_Process_Name'], end='') 1577 | print(" [+] Process Command Line : ( %s ) \n " % Command_unescape, end='') 1578 | print("____________________________________________________\n") 1579 | 1580 | #Detect wmiexec variation 1581 | if wmiexec in Command_unescape.lower() and wmiexec2 in Command_unescape.lower() and "%%1936" in TokenElevationType: 1582 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') 1583 | print_colored(" WMIEXEC Detected !!", Fore.RED) 1584 | print(" [+] Computer Name : ( %s ) \n " % Event['SubjectDomainName'], end='') 1585 | print(" [+] User Name : ( %s ) \n " % Event['SubjectUserName'], end='') 1586 | print(" [+] Process ID : ( %s ) \n " % Event['ProcessId'], end='') 1587 | print(" [+] Process Name : ( %s ) \n " % Event['New_Process_Name'], end='') 1588 | print(" [+] Process Command Line : ( %s ) \n " % Command_unescape, end='') 1589 | print("____________________________________________________\n") 1590 | 1591 | #Detect CVE-2021-44077 1592 | if msiexec in Command_unescape: 1593 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') 1594 | print_colored(" CVE-2021-44077 first stage Detected !!", Fore.RED) 1595 | print(" [+] Computer Name : ( %s ) \n " % Event['SubjectDomainName'], end='') 1596 | print(" [+] User Name : ( %s ) \n " % Event['SubjectUserName'], end='') 1597 | print(" [+] Process ID : ( %s ) \n " % Event['ProcessId'], end='') 1598 | print(" [+] Process Name : ( %s ) \n " % Event['New_Process_Name'], end='') 1599 | print(" [+] Process Command Line : ( %s ) \n " % Command_unescape, end='') 1600 | print("____________________________________________________\n") 1601 | 1602 | #Detect CVE-2021-44077 second 1603 | if msiexec2 in Command_unescape: 1604 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') 1605 | print_colored(" CVE-2021-44077 2th stage Detected !!", Fore.RED) 1606 | print(" [+] Computer Name : ( %s ) \n " % Event['SubjectDomainName'], end='') 1607 | print(" [+] User Name : ( %s ) \n " % Event['SubjectUserName'], end='') 1608 | print(" [+] Process ID : ( %s ) \n " % Event['ProcessId'], end='') 1609 | print(" [+] Process Name : ( %s ) \n " % Event['New_Process_Name'], end='') 1610 | print(" [+] Process Command Line : ( %s ) \n " % Command_unescape, end='') 1611 | print("____________________________________________________\n") 1612 | 1613 | #Detect CVE-2021-44077 3th 1614 | if msiexec3 in Command_unescape: 1615 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') 1616 | print_colored(" [+] CVE-2021-44077 3th stage Detected !!", Fore.RED) 1617 | print(" [+] Computer Name : ( %s ) \n " % Event['SubjectDomainName'], end='') 1618 | print(" [+] User Name : ( %s ) \n " % Event['SubjectUserName'], end='') 1619 | print(" [+] Process ID : ( %s ) \n " % Event['ProcessId'], end='') 1620 | print(" [+] Process Name : ( %s ) \n " % Event['New_Process_Name'], end='') 1621 | print(" [+] Process Command Line : ( %s ) \n " % Command_unescape, end='') 1622 | print("____________________________________________________\n") 1623 | 1624 | except Exception as e: 1625 | pass 1626 | 1627 | #Detect Privilege esclation "GetSystem" 1628 | if EventID[0]=="7045": 1629 | try: 1630 | # PipeName 1631 | pipe = r'\.\pipe' 1632 | #Detect Privilege esclation "GetSystem" 1633 | if "cmd.exe /c echo" in Command_unescape.lower() and "%%1936" in TokenElevationType and "cmd.exe" in Event['New_Process_Name'].lower() and pipe in Command_unescape.lower(): 1634 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') 1635 | print_colored(" GetSystem Detect By metasploit & Cobalt Strike & Empire & PoshC2", Fore.RED) 1636 | print(" [+] Computer Name : ( %s ) \n " % Event['SubjectDomainName'], end='') 1637 | print(" [+] User Name : ( %s ) \n " % Event['SubjectUserName'], end='') 1638 | print(" [+] Process ID : ( %s ) \n " % Event['ProcessId'], end='') 1639 | print(" [+] Process Name : ( %s ) \n " % Event['New_Process_Name'], end='') 1640 | print(" [+] Process Command Line : ( %s ) \n " % Command_unescape, end='') 1641 | print("____________________________________________________\n") 1642 | 1643 | except Exception as e: 1644 | pass 1645 | 1646 | #Detect PsExec execution 1647 | if EventID[0]=="1": 1648 | try: 1649 | hashes = re.findall(r'(?i)(?0: 1707 | Event['Timestamp'] = UtcTime[0][0].strip() 1708 | 1709 | # Detect PsExec Pipe Creation 1710 | if "\psexesvc" in Event['PipeName'].lower() and "stderr" in Event['PipeName'].lower() or "\psexesvc" in Event['PipeName'].lower() and "stdin" in Event['PipeName'].lower() or "\psexesvc" in Event['PipeName'].lower() and "stdout" in Event['PipeName'].lower(): 1711 | print("\n__________ " + Event['Timestamp'] + " __________ \n\n ", end='') 1712 | print_colored(" PsExec Pipe Creation Detected !!", Fore.RED) 1713 | print(" [+] Computer Name : ( %s ) \n " % Event['Computer_Name'], end='') 1714 | print(" [+] Image Name : ( %s ) \n " % Event['Image'], end='') 1715 | print(" [+] Process ID : ( %s ) \n " % Event['ProcessId'], end='') 1716 | print(" [+] PipeName : ( %s ) \n " % Event['PipeName'], end='') 1717 | print("____________________________________________________\n") 1718 | 1719 | except Exception as e: 1720 | pass 1721 | 1722 | #Detect SMBV3 CVE-2020-0769 1723 | if EventID[0]=="10": 1724 | try: 1725 | # Detect SMBV3 CVE-2020-0769 1726 | if "0x1fffff" in Event['GrantedAccess'] and "winlogon.exe" in Event['TargetImage'] and "ntdll.dll" in Event['CallTrace'] and "KERNELBASE.dll" in Event['CallTrace']: 1727 | print("\n__________ " + Event['Timestamp'] + " __________ \n\n ", end='') 1728 | print_colored(" START OF CVE-2020-0769 Detected !!", Fore.RED) 1729 | print(" [+] Source Process Id : ( %s ) \n " % Event['SourceProcessId'], end='') 1730 | print(" [+] Source Image : ( %s ) \n " % Event['SourceImage'], end='') 1731 | print(" [+] Target Process Id : ( %s ) \n " % Event['TargetProcessId'], end='') 1732 | print(" [+] Target Image : ( %s ) \n " % Event['TargetImage'], end='') 1733 | print(" [+] Granted Access : ( %s ) \n " % Event['GrantedAccess'], end='') 1734 | print(" [+] CallTrace : ( %s ) \n " % Event['CallTrace'], end='') 1735 | print("____________________________________________________\n") 1736 | 1737 | except Exception as e: 1738 | pass 1739 | 1740 | #detect pass the hash 1741 | if EventID[0] == "4625" or EventID[0] == "4624": 1742 | try: 1743 | #print(Logon_Events) 1744 | user=Event['SubjectUserName'] 1745 | 1746 | if logon_type == "3" or logon_type == "9" and Event['TargetUserName'] != "ANONYMOUS LOGON" and Event['KeyLength'] == "0": 1747 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') ### Fix Time 1748 | print("[+] \033[0;31;47mPass The Hash Detected", Fore.RED) 1749 | print("[+] User Name : ( %s ) \n" % Event['TargetUserName'], end='') 1750 | print(" [+] Computer : ( %s ) \n" % Event['Computer_Name'], end='') 1751 | print(" [+] Channel : ( %s ) \n" % Event['Channel'], end='') 1752 | print(" [+] Account Domain : ( %s ) \n" % Event['Target_Account_Domain'], end='') 1753 | print(" [+] Logon Type : ( %s ) \n" % Event['LogonType'], end='') 1754 | print(" [+] Logon Process : ( %s ) \n" % Event['LogonProcessName'], end='') 1755 | print(" [+] Source IP : ( %s ) \n " % Event['IpAddress'], end='') 1756 | print(" [+] Workstation Name : ( %s ) \n" % Event['WorkstationName'], end='') 1757 | print("____________________________________________________\n") 1758 | 1759 | except Exception as e: 1760 | pass 1761 | 1762 | #Start Of Detecting cve-2021-42287 1763 | if EventID[0]=="4741": #+ EventID[0]=="4673" + EventID[0]=="4742" + EventID[0]=="4781" + EventID[0]=="4768" + EventID[0]=="4781" and EventID[0]=="4769": 1764 | try: 1765 | if "-" in Event['ServicePrincipalNames']: 1766 | checker("ATTACK_REPLAY_CHECK") 1767 | 1768 | except Exception as e: 1769 | pass 1770 | 1771 | 1772 | # Detecting Sam Account name changed to domain controller name 1773 | if EventID[0]=="4742": 1774 | try: 1775 | UserName = Event['TargetUserName'] 1776 | if "-" not in Event['SamAccountName']: 1777 | checker("SAM_ACCOUNT_NAME_CHECK") 1778 | 1779 | except Exception as e: 1780 | pass 1781 | 1782 | # Verify Sam Account name changed to domain controller name 1783 | if EventID[0]=="4781": 1784 | try: 1785 | if Event['NewTargetUserName'] in Event['Computer_Name']: 1786 | checker("New_Target_User_Name_Check") 1787 | 1788 | except Exception as e: 1789 | pass 1790 | 1791 | # Kerberos AS-REP Attack Detect 1792 | if EventID[0] == "4768": 1793 | try: 1794 | if serviceName == "krbtgt": 1795 | checker("REQUEST_TGT_CHECK") 1796 | 1797 | except Exception as e: 1798 | pass 1799 | 1800 | ################ end of CVE-2021-42278 DETECTION 1801 | 1802 | #detect PasswordSpray Attack 1803 | if EventID[0] == "4648": 1804 | try: 1805 | if len(Account_Name[0][0])>0: 1806 | user=Event['SubjectUserName'] 1807 | 1808 | #For Defrinceation 1809 | user_list.append(user) 1810 | user_list_2.append(user) 1811 | sourceIp_list.append(Event['SourceIp']) 1812 | sourceIp_list_2.append(Event['SourceIp']) 1813 | 1814 | except Exception as e: 1815 | pass 1816 | 1817 | # FULL CVE-2021-42278 DETECTION 1818 | if "True" in REQUEST_TGT_CHECK_list and "True" in New_Target_User_Name_Check_list and "True" in SAM_ACCOUNT_NAME_CHECK_list and "True" in ATTACK_REPLAY_CHECK_list: 1819 | parser = PyEvtxParser(file) 1820 | for record in parser.records(): 1821 | record_data = record['data'] 1822 | EventID2 = EventID_rex.findall(record_data) 1823 | NewTargetUserName = NewTargetUserName_rex.findall(record_data) 1824 | OldTargetUserName = OldTargetUserName_rex.findall(record_data) 1825 | Computer_Name = Computer_Name_rex.findall(record_data) 1826 | Target_Account_Domain=Account_Domain_Target_rex.findall(record_data) 1827 | Account_Name = AccountName_rex.findall(record_data) 1828 | 1829 | if len(EventID2) > 0: 1830 | if EventID2[0] == "4781": 1831 | try: 1832 | if len(Account_Name[0])>0: 1833 | NewTargetUserName = NewTargetUserName[0].strip() 1834 | computer = Computer_Name[0].strip() 1835 | OldTargetUserName = OldTargetUserName[0].strip() 1836 | accountName = Account_Name[0][0].strip() 1837 | 1838 | if OldTargetUserName in computer: #and "True" in REQUEST_TGT_CHECK_list and "True" in New_Target_User_Name_Check_list:# and "True" in SAM_ACCOUNT_NAME_CHECK_list and "True" in ATTACK_REPLAY_CHECK_list: 1839 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') 1840 | print_colored(" CVE-2021-42287 and CVE-2021-42278 DETCTED !!", Fore.RED) 1841 | print(" [+] Computer Name : ( %s ) \n " % computer, end='') 1842 | print(" [+] User Name : ( %s ) \n " % accountName, end='') 1843 | print(" [+] New User Name : ( %s ) \n " % NewTargetUserName, end='') 1844 | print(" [+] Old User Name : ( %s ) \n " % OldTargetUserName, end='') 1845 | print(" [+] Domain Name : ( %s ) \n " % Target_Account_Domain, end='') 1846 | print("____________________________________________________\n") 1847 | 1848 | 1849 | except Exception as e: 1850 | pass 1851 | #### END 1852 | 1853 | # For Defrinceation and Detect the attack 1854 | if range(len(user_list)) == range(len(user_list_2)) and range(len(sourceIp_list)) == range(len(sourceIp_list_2)): 1855 | SprayUserDetector = 0 1856 | for x in range(len(user_list)): 1857 | if user_list[x] == user_list_2[x]: 1858 | SprayUserDetector += 1 1859 | 1860 | if SprayUserDetector >= 10: 1861 | print("\n__________ " + record["timestamp"] + " __________ \n\n ", end='') ### Fix Time 1862 | print("[+] \033[0;31;47mPassword Spray Detected!!", Fore.RED) 1863 | print("[+] Attacker User Name : ( %s ) \n" % user, end='') 1864 | print(" [+] Account Domain : ( %s ) \n" % target_account_domain, end='') 1865 | print(" [+] Source IP : ( %s ) \n" % source_ip, end='') 1866 | print(" [+] Number Of Spray : ( %s ) \n" % SprayUserDetector, end='') 1867 | print("____________________________________________________\n") 1868 | 1869 | #### print the final report of the SIGMA scanning 1870 | Result_Rule_list = [] 1871 | Result_Event_list = [] 1872 | 1873 | try: 1874 | for RuleName in MatchedRulesAgainstLogs.keys(): 1875 | print(f"[!] Rule Name: {RuleName}", end="\t\t\t\t\t\t\n") 1876 | print(f" [-] Potential False-Positives: {MatchedRulesAgainstLogs[RuleName]['falsepositives']}") 1877 | 1878 | Result_Rule = {} 1879 | Result_Rule['RuleName'] = RuleName 1880 | Result_Rule['Counts'] = len(MatchedRulesAgainstLogs[RuleName]["Events"]) 1881 | Result_Rule['FalsePositives'] = str(MatchedRulesAgainstLogs[RuleName]['falsepositives']) 1882 | Result_Rule_list.append(Result_Rule) 1883 | 1884 | count = 0 1885 | for Event in MatchedRulesAgainstLogs[RuleName]["Events"]: 1886 | New_Event = {} 1887 | 1888 | for key in Event.keys(): 1889 | if key in Event: 1890 | New_Event[key] = Event[key] 1891 | 1892 | New_Event['RuleName'] = RuleName 1893 | New_Event['RuleId'] = RuleName + Result_Rule['FalsePositives'][2:7] 1894 | New_Event['FalsePositives'] = Result_Rule['FalsePositives'] 1895 | 1896 | if "Timestamp" in Event and len(Event["Timestamp"]) != 0: 1897 | print("\n__________ " + str(Event["Timestamp"]) + " __________ \n\n ") 1898 | else: 1899 | print("\n__________ no time __________ \n\n ") 1900 | if len(Event["EventID"]) != 0: 1901 | print(" [*] EventID: " + str(Event["EventID"])) 1902 | if "Computer_Name" in Event and len(Event["Computer_Name"]) != 0: 1903 | print(" [*] Computer: " + str(Event["Computer_Name"])) 1904 | if "Image" in Event and len(Event["Image"]) != 0: 1905 | print(" [*] Process Image: " + str(Event["Image"])) 1906 | if "CommandLine" in Event and len(Event["CommandLine"]) != 0: 1907 | print(" [*] CommandLine: " + str(Event["CommandLine"])) 1908 | if "ParentImage" in Event and len(Event["ParentImage"]) != 0: 1909 | print(" [*] Parent Process Image: " + str(Event["ParentImage"])) 1910 | if "ParentCommandLine" in Event and len(Event["ParentCommandLine"]) != 0: 1911 | print(" [*] Parent Process CommandLine: " + str(Event["ParentCommandLine"])) 1912 | if "User" in Event and len(Event["User"]) != 0: 1913 | print(" [*] User: " + str(Event["User"])) 1914 | if "UserName" in Event and len(Event["UserName"]) != 0: 1915 | print(" [*] UserName: " + str(Event["UserName"])) 1916 | if "SourceIp" in Event and len(Event["SourceIp"]) != 0: 1917 | print(" [*] Source IP Address: " + str(Event["SourceIp"]) + ":" + str(Event["SourcePort"])) 1918 | if "DestinationIp" in Event and len(Event["DestinationIp"]) != 0: 1919 | print(" [*] Destionation IP Address: " + str(Event["DestinationIp"]) + ":" + str(Event["DestinationPort"])) 1920 | if "OriginalFileName" in Event and len(Event["OriginalFileName"]) != 0: 1921 | print(" [*] Original File Name: " + str(Event["OriginalFileName"])) 1922 | if "SubjectUserName" in Event and len(Event["SubjectUserName"]) != 0: 1923 | print(" [*] Subject User Name: " + str(Event["SubjectUserName"])) 1924 | if "TargetUserName" in Event and len(Event["TargetUserName"]) != 0: 1925 | print(" [*] Target User Name: " + str(Event["TargetUserName"])) 1926 | if "SubjectDomainName" in Event and len(Event["SubjectDomainName"]) != 0: 1927 | print(" [*] Subject Domain Name: " + str(Event["SubjectDomainName"])) 1928 | if "Product" in Event and len(Event["Product"]) != 0: 1929 | print(" [*] Product: " + str(Event["Product"])) 1930 | if "MD5" in Event and len(Event["MD5"]) != 0: 1931 | print(" [*] MD5: " + str(Event["MD5"])) 1932 | if "SHA1" in Event and len(Event["SHA1"]) != 0: 1933 | print(" [*] SHA1: " + str(Event["SHA1"])) 1934 | if "SHA256" in Event and len(Event["SHA256"]) != 0: 1935 | print(" [*] SHA256: " + str(Event["SHA256"])) 1936 | if "IMPHASH" in Event and len(Event["IMPHASH"]) != 0: 1937 | print(" [*] IMPHASH: " + str(Event["IMPHASH"])) 1938 | 1939 | Result_Event_list.append(New_Event) 1940 | print("____________________________________________________\n") 1941 | print("____________________________________________________\n") 1942 | 1943 | #if count != Result_Rule['Counts']: 1944 | except Exception as ERROR: 1945 | print(str(ERROR)) 1946 | print_colored("Error printing the Matched Rules", Fore.RED) 1947 | exit(0) 1948 | 1949 | return Result_Rule_list, Result_Event_list 1950 | 1951 | # Print the list of all rules that match. Each rule key contains all corresponding events that matched 1952 | # print(MatchedRulesAgainstLogs.keys()) 1953 | # You can use this variable MatchedRulesAgainstLogs any way you want 1954 | 1955 | # Parsing Evtx File 1956 | def parse_evtx(self, evtx_list): 1957 | try: 1958 | # count = 0 1959 | # record_sum = 0 1960 | # evtx = None 1961 | # for evtx_file in evtx_list: 1962 | # if evtx is None: 1963 | # with open(evtx_file, "rb") as fb: 1964 | # fb_data = fb.read(8) 1965 | # if fb_data != EVTX_HEADER: 1966 | # sys.exit("[!] This file is not EVTX format {0}.".format(evtx_file)) 1967 | 1968 | # with open(evtx_file, "rb") as evtx: 1969 | # parser = PyEvtxParser(evtx) 1970 | # records = list(parser.records()) 1971 | # record_sum += len(records) 1972 | 1973 | # print("[+] Last record number is {0}.".format(record_sum)) 1974 | 1975 | # # Parse Event log 1976 | # print("[+] Start parsing the EVTX file.") 1977 | 1978 | # for evtx_file in evtx_list: 1979 | # print("[+] Parse the EVTX file {0}.".format(evtx_file)) 1980 | 1981 | # for record, err in xml_records(evtx_file): 1982 | # if err is not None: 1983 | # continue 1984 | # count += 1 1985 | 1986 | # if evtx_file == evtx_file: 1987 | # sys.stdout.write("\r[+] Now loading {0} records.".format(count)) 1988 | # sys.stdout.flush() 1989 | 1990 | return self.detect_events_security_log(evtx_list) 1991 | except Exception as e: 1992 | print_colored("Exception Occurred", Fore.RED) 1993 | print_colored(str(e), Fore.RED) 1994 | print_colored("Opps !", Fore.RED) 1995 | print_colored("Enter a Correct Path", Fore.RED) 1996 | 1997 | def main_func(self, file): 1998 | filelist = [] 1999 | 2000 | if file.find(".evtx") == -1 and file.find(".csv") == -1: 2001 | if os.path.isdir(file): 2002 | filelist = list_files(file) 2003 | else: 2004 | print_colored ("[-] error: input dirctory path correctly.", Fore.RED) 2005 | sys.exit(1) 2006 | elif os.path.isfile(file): 2007 | filelist.append(file) 2008 | else: 2009 | print_colored ("[-] error: input file path correctly. " + file, Fore.RED) 2010 | 2011 | sys.exit(1) 2012 | 2013 | start_datetime = datetime.now() 2014 | self.parse_evtx(filelist) 2015 | 2016 | end_datetime = datetime.now() 2017 | # Calculate the time difference 2018 | time_difference = end_datetime - start_datetime 2019 | 2020 | # Convert the time difference to milliseconds 2021 | milliseconds = time_difference.total_seconds() * 1000 2022 | print_colored ("[-] time= " + str(milliseconds), Fore.GREEN) 2023 | 2024 | return milliseconds 2025 | 2026 | def start_progress(self): 2027 | self.progressBar.setValue(0) # Reset the progress bar 2028 | 2029 | # Use a QTimer to simulate progress over time 2030 | self.timer = QTimer(self) 2031 | self.timer.timeout.connect(self.update_progress) 2032 | self.timer.start(100) # Update every 100 milliseconds 2033 | 2034 | def update_progress(self): 2035 | """ 2036 | current_value = self.progress_bar.value() 2037 | if current_value < 100: 2038 | self.progress_bar.setValue(current_value + 1) 2039 | else: 2040 | self.timer.stop() 2041 | """ 2042 | pass 2043 | 2044 | def filter_data(self): 2045 | filter_text = self.lineEdit_3.text() 2046 | self.proxy_model.setFilterRegExp(filter_text) 2047 | self.proxy_model.setFilterKeyColumn(-1) 2048 | result_count = self.proxy_model.rowCount() 2049 | self.label_3.setText(f"Result Count: {result_count}") 2050 | self.tableView.resizeColumnsToContents() 2051 | self.tableView.resizeRowsToContents() 2052 | 2053 | def do_start(self): 2054 | global IsSigmaLoaded 2055 | global IsAnalyzing 2056 | global Result_Rule_list 2057 | global Result_Event_list 2058 | 2059 | if IsSigmaLoaded == False: 2060 | self.label_3.setText(f"No Sigma, Please load it.") 2061 | return 2062 | 2063 | if IsAnalyzing == True: 2064 | self.label_3.setText(f"working now, try later") 2065 | return 2066 | 2067 | IsAnalyzing = True 2068 | 2069 | sel_text = self.lineEdit.text() 2070 | 2071 | #self.model_rule.removeRows(0, self.model_rule.rowCount()) 2072 | #self.model.removeRows(0, self.model.rowCount()) 2073 | self.model_rule.clear() 2074 | self.model.clear() 2075 | 2076 | Result_Rule_list = [] 2077 | Result_Event_list = [] 2078 | 2079 | if len(sel_text) > 0: 2080 | #result_rule_list, result_event_list, milliseconds = main_func(sel_text) 2081 | milliseconds = self.main_func(sel_text) 2082 | 2083 | for Rule in Result_Rule_list: 2084 | item1 = QStandardItem(str(Rule['Counts'])) 2085 | item2 = QStandardItem(Rule['RuleName']) 2086 | item3 = QStandardItem(Rule['FalsePositives']) 2087 | 2088 | self.model_rule.appendRow([item1, item2, item3]) 2089 | 2090 | self.tableView_rule.resizeColumnsToContents() 2091 | self.tableView_rule.resizeRowsToContents() 2092 | 2093 | cnt = 0 2094 | for Event in Result_Event_list: 2095 | # Add sample data 2096 | other = "" 2097 | if "Computer_Name" in Event and len(str(Event["Computer_Name"])) != 0: 2098 | other = other + "Computer: " + str(Event["Computer_Name"]) + "\n" 2099 | if "Image" in Event and len(Event["Image"]) != 0: 2100 | other = other + "Process Image: " + str(Event["Image"]) + "\n" 2101 | if "CommandLine" in Event and len(Event["CommandLine"]) != 0: 2102 | other = other + "CommandLine: " + str(Event["CommandLine"]) + "\n" 2103 | if "ParentImage" in Event and len(Event["ParentImage"]) != 0: 2104 | other = other + "Parent Process Image: " + str(Event["ParentImage"]) + "\n" 2105 | if "ParentCommandLine" in Event and len(Event["ParentCommandLine"]) != 0: 2106 | other = other + "Parent Process CommandLine: " + str(Event["ParentCommandLine"]) + "\n" 2107 | if "SourceIp" in Event and len(Event["SourceIp"]) != 0: 2108 | other = other + "Source IP Address: " + str(Event["SourceIp"]) + "\n" 2109 | if "DestinationIp" in Event and len(Event["DestinationIp"]) != 0: 2110 | other = other + "Destionation IP Address: " + str(Event["DestinationIp"]) + "\n" 2111 | if "OriginalFileName" in Event and len(Event["OriginalFileName"]) != 0: 2112 | other = other + "Original File Name: " + str(Event["OriginalFileName"]) + "\n" 2113 | if "SubjectUserName" in Event and len(Event["SubjectUserName"]) != 0: 2114 | other = other + "Subject User Name: " + str(Event["SubjectUserName"]) + "\n" 2115 | if "TargetUserName" in Event and len(Event["TargetUserName"]) != 0: 2116 | other = other + "Target User Name: " + str(Event["TargetUserName"]) + "\n" 2117 | if "SubjectDomainName" in Event and len(Event["SubjectDomainName"]) != 0: 2118 | other = other + "Subject Domain Name: " + str(Event["SubjectDomainName"]) + "\n" 2119 | if "Product" in Event and len(Event["Product"]) != 0: 2120 | other = other + "Product: " + str(Event["Product"]) + "\n" 2121 | if "MD5" in Event and len(Event["MD5"]) != 0: 2122 | other = other + "MD5: " + str(Event["MD5"]) + "\n" 2123 | if "SHA1" in Event and len(Event["SHA1"]) != 0: 2124 | other = other + "SHA1: " + str(Event["SHA1"]) + "\n" 2125 | if "SHA256" in Event and len(Event["SHA256"]) != 0: 2126 | other = other + "SHA256: " + str(Event["SHA256"]) + "\n" 2127 | if "IMPHASH" in Event and len(Event["IMPHASH"]) != 0: 2128 | other = other + "IMPHASH: " + str(Event["IMPHASH"]) + "\n" 2129 | 2130 | item1 = QStandardItem(str(Event['Timestamp'])) 2131 | item2 = QStandardItem(str(Event['EventID'])) 2132 | 2133 | if "User" in Event and len(str(Event["User"])) != 0: 2134 | item3 = QStandardItem(str(Event['User'])) 2135 | elif "UserName" in Event and len(str(Event["UserName"])) != 0: 2136 | item3 = QStandardItem(str(Event['UserName'])) 2137 | else: 2138 | item3 = QStandardItem("") 2139 | 2140 | item4 = QStandardItem(other) 2141 | item5 = QStandardItem(str(Event['RuleId'])) 2142 | 2143 | self.model.appendRow([item1, item2, item3, item4, item5]) 2144 | 2145 | self.tableView.resizeColumnsToContents() 2146 | self.tableView.resizeRowsToContents() 2147 | 2148 | self.model_rule.setHorizontalHeaderLabels(["Count", "RuleName", "FalsePositives"]) 2149 | self.model.setHorizontalHeaderLabels(["DateTime", "EventID", "User", "Other", "RuleId"]) 2150 | self.label_3.setText(f"time = {milliseconds} ms") 2151 | else: 2152 | self.label_3.setText(f"error: no file or dir to check (evtx, csv)") 2153 | 2154 | IsAnalyzing = False 2155 | 2156 | def handle_table_click(self, index): 2157 | # Handle click event for all rows 2158 | row = index.row() 2159 | column = index.column() 2160 | item = self.model_rule.item(row, column) 2161 | data = self.model_rule.index(row, 1).data() + self.model_rule.index(row, 2).data()[2:7] 2162 | 2163 | self.model_rule.setHorizontalHeaderLabels(["Count", "RuleName", "FalsePositives"]) 2164 | self.model.setHorizontalHeaderLabels(["DateTime", "EventID", "User", "Other", "RuleId"]) 2165 | self.proxy_model.setFilterRegExp(data) 2166 | self.proxy_model.setFilterKeyColumn(4) 2167 | result_count = self.proxy_model.rowCount() 2168 | self.label_3.setText(f"Result Count: {result_count}") 2169 | self.tableView.resizeColumnsToContents() 2170 | self.tableView.resizeRowsToContents() 2171 | 2172 | def click_button_showall(self): 2173 | self.proxy_model.setFilterRegExp("") 2174 | self.proxy_model.setFilterKeyColumn(-1) 2175 | result_count = self.proxy_model.rowCount() 2176 | self.label_3.setText(f"Result Count: {result_count}") 2177 | self.tableView.resizeColumnsToContents() 2178 | self.tableView.resizeRowsToContents() 2179 | 2180 | def click_button_save(self): 2181 | global Result_Event_list 2182 | 2183 | if len(Result_Event_list) == 0: 2184 | return 2185 | 2186 | # Get the current datetime 2187 | now = datetime.now() 2188 | 2189 | # Extracting keys 2190 | all_keys = set() # Using a set to avoid duplicates 2191 | for entry in Result_Event_list: 2192 | all_keys.update(entry.keys()) 2193 | 2194 | new_keys = ["RuleName", "FalsePositives"] 2195 | 2196 | for key in all_keys: 2197 | if key == "RuleName" or key == "FalsePositives": 2198 | continue 2199 | 2200 | new_keys.append(key) 2201 | 2202 | # Create a new list with dictionaries having the desired key order 2203 | new_json_array = [ 2204 | {key: entry[key] for key in new_keys} for entry in Result_Event_list 2205 | ] 2206 | 2207 | # Format the datetime as a string 2208 | datetime_str = now.strftime("%Y-%m-%d %H%M%S") 2209 | 2210 | # Specify the file name 2211 | file_name = "result_" + datetime_str + ".csv" 2212 | 2213 | # Writing to CSV file 2214 | with open(file_name, 'w', encoding='utf-8', newline='') as file: 2215 | writer = csv.DictWriter(file, fieldnames=new_keys) 2216 | 2217 | # Write the header 2218 | writer.writeheader() 2219 | 2220 | # Write the data 2221 | writer.writerows(new_json_array) 2222 | 2223 | print(f"JSON array has been written to {file_name}") 2224 | 2225 | self.show_notice() 2226 | 2227 | def show_notice(self): 2228 | # Create a QMessageBox with an information role 2229 | QMessageBox.information(self, 'Notice', 'The reuslts are saved successfully.') 2230 | 2231 | 2232 | def retranslateUi(self, Form): 2233 | _translate = QtCore.QCoreApplication.translate 2234 | Form.setWindowTitle(_translate("Form", "ThreadHound")) 2235 | self.label.setText(_translate("Form", "Path: ")) 2236 | self.pushButton.setText(_translate("Form", "Open Dir")) 2237 | self.pushButton_2.setText(_translate("Form", "Open File")) 2238 | self.label_2.setText(_translate("Form", "Rule Dir Path:")) 2239 | self.pushButton_4.setText(_translate("Form", "Open Dir")) 2240 | self.pushButton_3.setText(_translate("Form", "Start")) 2241 | self.label_3.setText(_translate("Form", "Status:")) 2242 | self.label_4.setText(_translate("Form", "")) 2243 | self.pushButton_save.setText(_translate("Form", "Save")) 2244 | self.pushButton_showall.setText(_translate("Form", "Show All")) 2245 | 2246 | def show_file_dialog(self): 2247 | options = QFileDialog.Options() 2248 | options |= QFileDialog.DontUseNativeDialog 2249 | 2250 | fileDialog = QFileDialog() 2251 | fileDialog.setFileMode(QFileDialog.ExistingFile) 2252 | fileDialog.setNameFilter("Event Log Files (*.evtx);;CSV Files (*.csv)") 2253 | 2254 | file_name, _ = fileDialog.getOpenFileName(self, 'Open File', '', 'Event Log Files (*.evtx);;CSV Files (*.csv)', options=options) 2255 | 2256 | if os_type == "Windows": 2257 | file_name = file_name.replace("/", "\\") 2258 | 2259 | if file_name: 2260 | self.lineEdit.setText(file_name) 2261 | print(f'Selected file: {file_name}') 2262 | 2263 | def show_folder_dialog(self): 2264 | options = QFileDialog.Options() 2265 | options |= QFileDialog.DontUseNativeDialog 2266 | 2267 | folder_dialog = QFileDialog() 2268 | folder_dialog.setFileMode(QFileDialog.DirectoryOnly) 2269 | 2270 | folder_name = folder_dialog.getExistingDirectory(self, 'Open Folder', '', options=options) 2271 | 2272 | if os_type == "Windows": 2273 | folder_name = folder_name.replace("/", "\\") 2274 | 2275 | if folder_name: 2276 | self.lineEdit.setText(folder_name) 2277 | print(f'Selected folder: {folder_name}') 2278 | 2279 | def show_folder_dialog_sigma(self): 2280 | global IsSigmaLoaded 2281 | IsSigmaLoaded = False 2282 | 2283 | options = QFileDialog.Options() 2284 | options |= QFileDialog.DontUseNativeDialog 2285 | 2286 | folder_dialog = QFileDialog() 2287 | folder_dialog.setFileMode(QFileDialog.DirectoryOnly) 2288 | 2289 | folder_name = folder_dialog.getExistingDirectory(self, 'Open Folder', '', options=options) 2290 | 2291 | if os_type == "Windows": 2292 | folder_name = folder_name.replace("/", "\\") 2293 | 2294 | if folder_name: 2295 | self.lineEdit_2.setText(folder_name) 2296 | print(f'Selected folder: {folder_name}') 2297 | 2298 | self.label_3.setText("Status: Loading sigma") 2299 | 2300 | GetRuleFilesList(folder_name) 2301 | 2302 | self.label_3.setText("Status: Load sigma Successfully!") 2303 | IsSigmaLoaded = True 2304 | 2305 | class Window(QMainWindow, Ui_Form): 2306 | def __init__(self, parent=None): 2307 | super().__init__(parent) 2308 | self.setupUi(self) 2309 | #self.connectSignalsSlots() 2310 | 2311 | def main_form(): 2312 | app = QApplication(sys.argv) 2313 | app.setStyleSheet(open('Combinear.qss').read()) 2314 | win = Window() 2315 | win.show() 2316 | sys.exit(app.exec()) 2317 | 2318 | if __name__ == '__main__': 2319 | # Initialize colorama 2320 | init() 2321 | 2322 | LOGO() 2323 | 2324 | # Parse command-line arguments 2325 | args = parse_arguments() 2326 | 2327 | sigma_manager.CheckUpdate() 2328 | 2329 | if args.form == True: 2330 | main_form() 2331 | pass 2332 | elif args.path != None: 2333 | rule_path = args.sigma 2334 | 2335 | if rule_path != None and len(rule_path) > 0: 2336 | if os.path.exists(rule_path) and os.path.isdir(rule_path): 2337 | pass 2338 | else: 2339 | print_colored("[-] error: rule path is incorrect.", Fore.RED) 2340 | sys.exit(1) 2341 | else: 2342 | os_type = get_os_type() 2343 | CurrentPath = os.getcwd() 2344 | 2345 | if os_type == "Windows": 2346 | RulesDirectory = f"{CurrentPath}\\windows" 2347 | else: 2348 | RulesDirectory = f"{CurrentPath}/windows" 2349 | 2350 | rule_path = RulesDirectory 2351 | 2352 | GetRuleFilesList(rule_path) 2353 | 2354 | ui = Ui_Form() 2355 | ui.main_func(args.path) 2356 | 2357 | #original 104s 2358 | #sigma_manager multi 114s 2359 | #threathound.py multi 90s 2360 | #https://qss-stock.devsecstudio.com/templates.php 2361 | #pyuic5 -o main_window_ui.py ui/main_window.ui 2362 | --------------------------------------------------------------------------------