Created
April 28, 2025 06:55
-
-
Save CodeAdminDe/8619126604306821d9acd6114b0fabb0 to your computer and use it in GitHub Desktop.
Azure Sentinel NGINX analytic rules // Merged analytic rules based on offical solution provided by https://github.com/Azure/Azure-Sentinel/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Merged Azure Sentinel analytics rules for reference and quick access. | |
| # Original rules from https://github.com/Azure/Azure-Sentinel/tree/a49751dd87f6cab723010d60ee0e7518456532a5/Solutions/NGINX%20HTTP%20Server/Analytic%20Rules | |
| # | |
| --- | |
| id: d84739ce-2f46-4391-b25e-a2edbea19d7e | |
| name: NGINX - Command in URI | |
| description: | | |
| 'Detects command in URI' | |
| severity: High | |
| status: Available | |
| requiredDataConnectors: | |
| - connectorId: CustomLogsAma | |
| dataTypes: | |
| - NGINX_CL | |
| queryFrequency: 10m | |
| queryPeriod: 10m | |
| triggerOperator: gt | |
| triggerThreshold: 0 | |
| tactics: | |
| - InitialAccess | |
| relevantTechniques: | |
| - T1190 | |
| - T1133 | |
| query: | | |
| let cmd_list = dynamic(['cat%20/etc/passwd', '/etc/passwd', 'ping -i', '/usr/bin/id(', '%2f%75%73%72%2f%62%69%6e%2f%69%64', 'phpinfo()', '%70%68%70%69%6e%66%6f%28%29', ';id', '%3b%69%64', '/bin/bash -c', '%2f%62%69%6e%2f%62%61%73%68%20%2d%63%27', '/bin/bash', '%2f%62%69%6e%2f%62%61%73%68', 'sleep(', '%73%6c%65%65%70%28', 'curl', '%63%75%72%6c', '&dir', '%26%64%69%72', '& dir', '%26%20%64%69%72', '<script>', '%3c%73%63%72%69%70%74%3e', 'eval(', '%65%76%61%6c%28', 'exec(', '%65%78%65%63%28', 'whoami', '%77%68%6f%61%6d%69', 'wget', 'python', 'gcc', 'uname', 'systeminfo', '%77%67%65%74', '%70%79%74%68%6f%6e', '%75%6e%61%6d%65', '%73%79%73%74%65%6d%69%6e%66%6f']); | |
| NGINXHTTPServer | |
| | where UrlOriginal has_any (cmd_list) | |
| | extend UrlCustomEntity = UrlOriginal | |
| entityMappings: | |
| - entityType: URL | |
| fieldMappings: | |
| - identifier: Url | |
| columnName: UrlCustomEntity | |
| version: 1.0.3 | |
| kind: Scheduled | |
| --- | |
| id: 9a7f5a97-354b-4eac-b407-a1cc7fc4b4ec | |
| name: NGINX - Core Dump | |
| description: | | |
| 'Detects a core dump of a crashing Nginx worker process, which could be a signal of a serious problem or exploitation attempts.' | |
| severity: High | |
| status: Available | |
| requiredDataConnectors: | |
| - connectorId: CustomLogsAma | |
| dataTypes: | |
| - NGINX_CL | |
| queryFrequency: 10m | |
| queryPeriod: 10m | |
| triggerOperator: gt | |
| triggerThreshold: 0 | |
| tactics: | |
| - Impact | |
| relevantTechniques: | |
| - T1499 | |
| query: | | |
| NGINXHTTPServer | |
| | where EventType =~ "ErrorLog" | |
| | where EventMessage contains 'exited on signal 6 (core dumped)' | |
| | extend ProcessIdCustomEntity = ProcessId | |
| entityMappings: | |
| - entityType: Process | |
| fieldMappings: | |
| - identifier: ProcessId | |
| columnName: ProcessIdCustomEntity | |
| version: 1.0.3 | |
| kind: Scheduled | |
| --- | |
| id: 83a0b48f-1cb7-4b4f-a018-23c3203a239b | |
| name: NGINX - Multiple user agents for single source | |
| description: | | |
| 'Detects requests with different user agents from one source in short timeframe.' | |
| severity: Medium | |
| status: Available | |
| requiredDataConnectors: | |
| - connectorId: CustomLogsAma | |
| dataTypes: | |
| - NGINX_CL | |
| queryFrequency: 1h | |
| queryPeriod: 1h | |
| triggerOperator: gt | |
| triggerThreshold: 0 | |
| tactics: | |
| - InitialAccess | |
| relevantTechniques: | |
| - T1190 | |
| - T1133 | |
| query: | | |
| let threshold = 5; | |
| NGINXHTTPServer | |
| | summarize makeset(HttpUserAgentOriginal) by SrcIpAddr, bin(TimeGenerated, 5m) | |
| | extend ua_count = array_length(set_HttpUserAgentOriginal) | |
| | where ua_count > threshold | |
| | extend IPCustomEntity = SrcIpAddr | |
| entityMappings: | |
| - entityType: IP | |
| fieldMappings: | |
| - identifier: Address | |
| columnName: IPCustomEntity | |
| version: 1.0.2 | |
| kind: Scheduled | |
| --- | |
| id: a10c6551-bbf2-492c-aa8a-fe6efd8c9cc1 | |
| name: NGINX - Known malicious user agent | |
| description: | | |
| 'Detects known malicious user agents' | |
| severity: High | |
| status: Available | |
| requiredDataConnectors: | |
| - connectorId: CustomLogsAma | |
| dataTypes: | |
| - NGINX_CL | |
| queryFrequency: 10m | |
| queryPeriod: 10m | |
| triggerOperator: gt | |
| triggerThreshold: 0 | |
| tactics: | |
| - InitialAccess | |
| relevantTechniques: | |
| - T1190 | |
| - T1133 | |
| query: | | |
| let mal_ua_list = dynamic(['Nikto', '(hydra)', '.nasl', 'absinthe', 'advanced email extractor', 'arachni/', 'autogetcontent', 'bilbo', 'BFAC', 'brutus', 'brutus/aet', 'bsqlbf', 'cgichk', 'cisco-torch', 'commix', 'core-project/1.0', 'crimscanner/', 'datacha0s', 'dirbuster', 'domino hunter', 'dotdotpwn', 'email extractor', 'fhscan core 1.', 'floodgate', 'get-minimal', 'gootkit auto-rooter scanner', 'grabber', 'grendel-scan', 'havij', 'inspath', 'internet ninja', 'jaascois', 'zmeu', 'masscan', 'metis', 'morfeus', 'mysqloit', 'n-stealth', 'nessus', 'netsparker', 'nmap nse', 'nmap scripting engine', 'nmap-nse', 'nsauditor', 'openvas', 'pangolin', 'paros', 'pmafind', 'prog.customcrawler', 'qualys was', 's.t.a.l.k.e.r.', 'security scan', 'springenwerk', 'sql power injector', 'sqlmap', 'sqlninja', 'teh forest lobster', 'this is an exploit', 'toata dragostea', 'toata dragostea mea pentru diavola', 'uil2pn', 'user-agent:', 'vega/', 'voideye', 'w3af.sf.net', 'w3af.sourceforge.net', 'w3af.org', 'webbandit', 'webinspect', 'webshag', 'webtrends security analyzer', 'webvulnscan', 'whatweb', 'whcc/', 'wordpress hash grabber', 'xmlrpc exploit', 'WPScan', 'XSpider', 'SF/', 'FooBar/42', 'ScanAlert', 'Webscanner', 'Webster', 'fantomCrew', 'fantomBrowser', 'visvo', 'magereport', 'ltx71', 'websiteprotection', 'BigCliqueBOT', '(BOT for JCE)']); | |
| NGINXHTTPServer | |
| | where HttpUserAgentOriginal has_any (mal_ua_list) | |
| | extend IPCustomEntity = SrcIpAddr, MalwareCustomEntity = HttpUserAgentOriginal | |
| entityMappings: | |
| - entityType: IP | |
| fieldMappings: | |
| - identifier: Address | |
| columnName: IPCustomEntity | |
| - entityType: Malware | |
| fieldMappings: | |
| - identifier: Name | |
| columnName: MalwareCustomEntity | |
| version: 1.0.3 | |
| kind: Scheduled | |
| --- | |
| id: 42771afe-edb3-4330-bc4a-abf6a5714454 | |
| name: NGINX - Multiple client errors from single IP address | |
| description: | | |
| 'Detects multiple client errors from one source in short timeframe' | |
| severity: Medium | |
| status: Available | |
| requiredDataConnectors: | |
| - connectorId: CustomLogsAma | |
| dataTypes: | |
| - NGINX_CL | |
| queryFrequency: 1h | |
| queryPeriod: 1h | |
| triggerOperator: gt | |
| triggerThreshold: 0 | |
| tactics: | |
| - InitialAccess | |
| relevantTechniques: | |
| - T1190 | |
| - T1133 | |
| query: | | |
| let threshold = 100; | |
| NGINXHTTPServer | |
| | where tolong(HttpStatusCode) >= 400 and tolong(HttpStatusCode) <= 499 | |
| | summarize MultipleClientErrors = count() by SrcIpAddr, bin(TimeGenerated, 5m) | |
| | where MultipleClientErrors > threshold | |
| | extend IPCustomEntity = SrcIpAddr | |
| entityMappings: | |
| - entityType: IP | |
| fieldMappings: | |
| - identifier: Address | |
| columnName: IPCustomEntity | |
| version: 1.0.2 | |
| kind: Scheduled | |
| --- | |
| id: b3ae0033-552e-4c3c-b493-3edffb4473bb | |
| name: NGINX - Multiple server errors from single IP address | |
| description: | | |
| 'Detects multiple server errors from one source in short timeframe' | |
| severity: Medium | |
| status: Available | |
| requiredDataConnectors: | |
| - connectorId: CustomLogsAma | |
| dataTypes: | |
| - NGINX_CL | |
| queryFrequency: 1h | |
| queryPeriod: 1h | |
| triggerOperator: gt | |
| triggerThreshold: 0 | |
| tactics: | |
| - Impact | |
| - InitialAccess | |
| relevantTechniques: | |
| - T1498 | |
| - T1190 | |
| - T1133 | |
| query: | | |
| let threshold = 100; | |
| NGINXHTTPServer | |
| | where tolong(HttpStatusCode) >= 500 and tolong(HttpStatusCode) <= 599 | |
| | summarize MultipleServerErrors = count() by SrcIpAddr, bin(TimeGenerated, 5m) | |
| | where MultipleServerErrors > threshold | |
| | extend IPCustomEntity = SrcIpAddr | |
| entityMappings: | |
| - entityType: IP | |
| fieldMappings: | |
| - identifier: Address | |
| columnName: IPCustomEntity | |
| version: 1.0.2 | |
| kind: Scheduled | |
| --- | |
| id: 1aa6bfed-f11b-402f-9007-0dccc1152ede | |
| name: NGINX - Private IP address in URL | |
| description: | | |
| 'Detects requests to unusual URL' | |
| severity: Medium | |
| status: Available | |
| requiredDataConnectors: | |
| - connectorId: CustomLogsAma | |
| dataTypes: | |
| - NGINX_CL | |
| queryFrequency: 1h | |
| queryPeriod: 1h | |
| triggerOperator: gt | |
| triggerThreshold: 0 | |
| tactics: | |
| - InitialAccess | |
| relevantTechniques: | |
| - T1190 | |
| - T1133 | |
| query: | | |
| NGINXHTTPServer | |
| | where UrlOriginal matches regex @'(10\.\d{1,3}\.\d{1,3}\.\d{1,3})|(172\.1[6-9]\.\d{1,3}\.\d{1,3})|(172\.2[0-9]\.\d{1,3}\.\d{1,3})|(172\.3[0-1]\.\d{1,3}\.\d{1,3})|(192\.168\.\d{1,3}\.\d{1,3})' | |
| | extend UrlCustomEntity = UrlOriginal | |
| entityMappings: | |
| - entityType: URL | |
| fieldMappings: | |
| - identifier: Url | |
| columnName: UrlCustomEntity | |
| version: 1.0.2 | |
| kind: Scheduled | |
| --- | |
| id: e04fa38e-9fb7-438d-887a-381d5dd235e6 | |
| name: NGINX - Put file and get file from same IP address | |
| description: | | |
| 'Detects put or get files from one source in short timeframe' | |
| severity: Medium | |
| status: Available | |
| requiredDataConnectors: | |
| - connectorId: CustomLogsAma | |
| dataTypes: | |
| - NGINX_CL | |
| queryFrequency: 1h | |
| queryPeriod: 1h | |
| triggerOperator: gt | |
| triggerThreshold: 0 | |
| tactics: | |
| - InitialAccess | |
| relevantTechniques: | |
| - T1190 | |
| - T1133 | |
| query: | | |
| let p = NGINXHTTPServer | |
| | where HttpRequestMethod in~ ('POST', 'PUT') | |
| | sort by EventStartTime asc | |
| | summarize post_time=min(EventStartTime) by SrcIpAddr, tostring(UrlOriginal); | |
| NGINXHTTPServer | |
| | where HttpRequestMethod =~ 'GET' | |
| | sort by EventStartTime asc | |
| | summarize get_time=min(EventStartTime) by SrcIpAddr, tostring(UrlOriginal) | |
| | join kind=innerunique (p) on UrlOriginal, SrcIpAddr | |
| | extend second = datetime_diff('second',get_time,post_time) | |
| | where second between (1 .. 300) | |
| | project second, post_time, get_time, SrcIpAddr, UrlOriginal | |
| | extend IPCustomEntity = SrcIpAddr, UrlCustomEntity = tostring(UrlOriginal) | |
| entityMappings: | |
| - entityType: IP | |
| fieldMappings: | |
| - identifier: Address | |
| columnName: IPCustomEntity | |
| - entityType: URL | |
| fieldMappings: | |
| - identifier: Url | |
| columnName: UrlCustomEntity | |
| version: 1.0.2 | |
| kind: Scheduled | |
| --- | |
| id: 2141ef6c-d158-4d44-b739-b145a4c21947 | |
| name: NGINX - Request to sensitive files | |
| description: | | |
| 'Detects request to sensitive files.' | |
| severity: Medium | |
| status: Available | |
| requiredDataConnectors: | |
| - connectorId: CustomLogsAma | |
| dataTypes: | |
| - NGINX_CL | |
| queryFrequency: 1h | |
| queryPeriod: 1h | |
| triggerOperator: gt | |
| triggerThreshold: 0 | |
| tactics: | |
| - InitialAccess | |
| relevantTechniques: | |
| - T1189 | |
| query: | | |
| let forbidden_files = dynamic(['shadow', 'passwd', 'id_rsa']); | |
| NGINXHTTPServer | |
| | extend File = extract(@"(.*\/)?(.*)", 2, tostring(UrlOriginal)) | |
| | where File in (forbidden_files) | |
| | extend FileCustomEntity = File, UrlCustomEntity = UrlOriginal | |
| entityMappings: | |
| - entityType: File | |
| fieldMappings: | |
| - identifier: Name | |
| columnName: FileCustomEntity | |
| - entityType: URL | |
| fieldMappings: | |
| - identifier: Url | |
| columnName: UrlCustomEntity | |
| version: 1.0.2 | |
| kind: Scheduled | |
| --- | |
| id: 3bac451d-f919-4c92-9be7-694990e0ca4b | |
| name: NGINX - Sql injection patterns | |
| description: | | |
| 'Detects possible sql injection patterns' | |
| severity: High | |
| status: Available | |
| requiredDataConnectors: | |
| - connectorId: CustomLogsAma | |
| dataTypes: | |
| - NGINX_CL | |
| queryFrequency: 10m | |
| queryPeriod: 10m | |
| triggerOperator: gt | |
| triggerThreshold: 0 | |
| tactics: | |
| - InitialAccess | |
| relevantTechniques: | |
| - T1190 | |
| query: | | |
| let sql_patterns = dynamic([@"1/*'*/", @"1'||'asd'||'", @"'1'='1", @"1' or '1'='1", @"1 or 1=1", @"1=1", @"1/*!1111'*/", @"'or''='"]); | |
| NGINXHTTPServer | |
| | where UrlOriginal has_any (sql_patterns) | |
| | extend IPCustomEntity = SrcIpAddr, UrlCustomEntity = UrlOriginal | |
| entityMappings: | |
| - entityType: IP | |
| fieldMappings: | |
| - identifier: Address | |
| columnName: IPCustomEntity | |
| - entityType: URL | |
| fieldMappings: | |
| - identifier: Url | |
| columnName: UrlCustomEntity | |
| version: 1.0.3 | |
| kind: Scheduled |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment