|
| 1 | +[metadata] |
| 2 | +creation_date = "2025/11/27" |
| 3 | +integration = ["endpoint", "network_traffic"] |
| 4 | +maturity = "production" |
| 5 | +updated_date = "2025/11/27" |
| 6 | + |
| 7 | +[rule] |
| 8 | +author = ["Elastic"] |
| 9 | +description = """ |
| 10 | +This rule detects potential initial access activity where an adversary uploads a web shell or malicious script |
| 11 | +to a web server via a file upload mechanism (e.g., through a web form using multipart/form-data), followed by |
| 12 | +a GET or POST request to access the uploaded file. By checking the body content of HTTP requests for file upload |
| 13 | +indicators such as "Content-Disposition: form-data" and "filename=", the rule identifies suspicious upload |
| 14 | +activities. This sequence of actions is commonly used by attackers to gain and maintain access to compromised web |
| 15 | +servers. |
| 16 | +""" |
| 17 | +from = "now-9m" |
| 18 | +index = ["logs-endpoint.events.*", "logs-network_traffic.*"] |
| 19 | +language = "eql" |
| 20 | +license = "Elastic License v2" |
| 21 | +name = "Initial Access via File Upload Followed by GET Request" |
| 22 | +risk_score = 47 |
| 23 | +rule_id = "1d306bf0-7bcf-4acd-83fd-042f5711acc9" |
| 24 | +setup = """## Setup |
| 25 | +
|
| 26 | +This rule requires data coming in from both Elastic Defend (for file events) and Network Packet Capture integrations (for HTTP traffic analysis). |
| 27 | +
|
| 28 | +### Network Packet Capture Integration Setup |
| 29 | +
|
| 30 | +**IMPORTANT**: This rule requires HTTP request body capture to be enabled in order to detect the multipart/form-data content containing WebKitFormBoundary indicators. The network traffic integration must be configured to capture HTTP request bodies for POST requests with `multipart/form-data` content type. |
| 31 | +
|
| 32 | +To enable HTTP request body capture, follow these steps: |
| 33 | +1. Navigate to the Fleet policy leveraging the Network Packet Capture integration in Kibana. |
| 34 | +2. Locate and select the "Network Packet Capture" integration, and edit the integration. |
| 35 | +3. Locate "Change Default", and scroll down to the "HTTP" section. |
| 36 | +4. Enable the "HTTP" toggle to capture HTTP traffic, add the correct ports for your web application, and click "advanced options". |
| 37 | +5. Edit the integration settings to enable HTTP request body capture for POST requests with `multipart/form-data` content type. |
| 38 | +6. Save the integration configuration and wait for the policy to deploy to the agents. |
| 39 | +""" |
| 40 | +severity = "medium" |
| 41 | +tags = [ |
| 42 | + "Domain: Endpoint", |
| 43 | + "Domain: Web", |
| 44 | + "Domain: Network", |
| 45 | + "OS: Linux", |
| 46 | + "OS: Windows", |
| 47 | + "OS: macOS", |
| 48 | + "Use Case: Threat Detection", |
| 49 | + "Tactic: Initial Access", |
| 50 | + "Tactic: Persistence", |
| 51 | + "Data Source: Elastic Defend", |
| 52 | + "Data Source: Network Traffic", |
| 53 | +] |
| 54 | +type = "eql" |
| 55 | +query = ''' |
| 56 | +sequence by agent.id with maxspan=5m |
| 57 | + [network where |
| 58 | + data_stream.dataset == "network_traffic.http" and |
| 59 | + http.request.method in ("POST", "PUT") and |
| 60 | + /* We can restrict to 200 in the future, but I prefer to broaden the scope and decrease it later if necessary */ |
| 61 | + http.response.status_code in (200, 201, 204, 301, 302, 303, 409) and |
| 62 | + /* These should detect most common file upload activities, adhering to browser standards */ |
| 63 | + http.request.body.content like "*Content-Disposition: form-data*" and |
| 64 | + http.request.body.content like "*filename=*" |
| 65 | + /* May add a lower/upper boundary limit to reduce FPs in the future, e.g. |
| 66 | + and http.request.body.bytes >= 500 |
| 67 | + */ |
| 68 | + ] |
| 69 | + [file where |
| 70 | + event.dataset == "endpoint.events.file" and |
| 71 | + event.action in ("creation", "rename") and |
| 72 | + file.extension in ("php", "phtml", "pht", "php5", "asp", "aspx", "jsp", "jspx", "war", "cgi") |
| 73 | + /* We can add file.path values here in the future, if telemetry is noisy */ |
| 74 | + ] |
| 75 | + [network where |
| 76 | + data_stream.dataset == "network_traffic.http" and |
| 77 | + http.request.method in ("GET", "POST") and |
| 78 | + /* we may restrict to 200, but keeping it broader right now */ |
| 79 | + http.response.status_code >= 200 and http.response.status_code < 600 and |
| 80 | + url.extension in ("php", "phtml", "pht", "php5", "asp", "aspx", "jsp", "jspx", "war", "cgi") |
| 81 | + ] |
| 82 | +''' |
| 83 | + |
| 84 | +[[rule.threat]] |
| 85 | +framework = "MITRE ATT&CK" |
| 86 | + |
| 87 | +[[rule.threat.technique]] |
| 88 | +id = "T1190" |
| 89 | +name = "Exploit Public-Facing Application" |
| 90 | +reference = "https://attack.mitre.org/techniques/T1190/" |
| 91 | + |
| 92 | +[rule.threat.tactic] |
| 93 | +id = "TA0001" |
| 94 | +name = "Initial Access" |
| 95 | +reference = "https://attack.mitre.org/tactics/TA0001/" |
| 96 | + |
| 97 | +[[rule.threat]] |
| 98 | +framework = "MITRE ATT&CK" |
| 99 | + |
| 100 | +[[rule.threat.technique]] |
| 101 | +id = "T1505" |
| 102 | +name = "Server Software Component" |
| 103 | +reference = "https://attack.mitre.org/techniques/T1505/" |
| 104 | + |
| 105 | +[[rule.threat.technique.subtechnique]] |
| 106 | +id = "T1505.003" |
| 107 | +name = "Web Shell" |
| 108 | +reference = "https://attack.mitre.org/techniques/T1505/003/" |
| 109 | + |
| 110 | +[rule.threat.tactic] |
| 111 | +id = "TA0003" |
| 112 | +name = "Persistence" |
| 113 | +reference = "https://attack.mitre.org/tactics/TA0003/" |
0 commit comments