JPCERT API Abuse, Metabase Exploitation and Webshells — Sentinel Hunts

Threat Overview

JPCERT/CC published alert JPCERT-AT-2026-0030 on 8 October 2026 and expanded it on 9 October following multiple recent unauthorized-access incidents and personal-data leaks in Japan. It describes **separate observed attack patterns, not one proven common campaign**: probing known vulnerabilities and exposed backup/configuration files; misuse of mobile and internal APIs to create accounts, change privileges, test malformed tokens and use stolen API keys; exploitation of Metabase CVE-2026-72898 (a previously disclosed, confirmed exploited SQL injection); and newly added reports of WAR archives containing JSP command-execution webshells on application servers accessible through public web servers. JPCERT published historical source IPs and User-Agent strings but warned that the IPs may now serve legitimate traffic. The Metabase vulnerability itself dates to August, but the October 9 advisory adds fresh observed indicators and the WAR/JSP case. The hunt combines behavior with dated indicators and does not equate every hit to compromise.

References

Impacted Systems

  • Generic API abuse: Internet-accessible consumer/mobile API backends, employee/admin APIs and business-intelligence or management applications; no single affected vendor, operating system, version or fixed build was identified for the generic incidents.
  • Metabase self-hosted (including public-facing BI application/API role): CVE-2026-72898 affects branches x.63 before x.63.5, x.62 before x.62.9, x.61 before x.61.11, x.60 before x.60.17, x.59 before x.59.21, and x.58 before x.58.24. Versions before the 58 branch are stated by Metabase to be unaffected. Metabase Cloud was already remediated by the vendor.
  • Metabase exposure: unauthenticated HTTP requests to `/api/session/reset_password`; confirmed attack sequence includes POST to that endpoint (400) followed by GET `/api/user/current` (200). An Internet-exposed endpoint materially increases risk. Fixed versions are the listed branch thresholds or newer vendor releases.
  • WAR/JSP webshell case: a publicly reachable web server can reach a Java application server accepting or loading `.war` deployments; specific Java application product, version, deployment path, OS and exploit vector were not confirmed. This is an observed post-compromise artifact, not a disclosed product-specific CVE.
  • Historical source IPs and user agents are supporting pivots only; do not treat them as exclusive or currently malicious.

Why this matters

JPCERT reports real data-loss incidents spanning mobile APIs, BI platforms and Java application servers. The shared risk is poorly protected Internet-reachable application functionality rather than a single product.

Exploitation Status

Confirmed: JPCERT incident reports of unauthorized API activity, Metabase exploitation, and WAR/JSP webshell placement; Metabase independently confirmed exploitation of CVE-2026-72898. JPCERT caveat: cases are fragmentary and need not share a single actor or exploit chain. Historical IP associations do not prove current malicious use.

What this hunt looks for

Prepared Sentinel hunts for the confirmed Metabase endpoint sequence, reported source addresses/User-Agent, unusual API access and enumeration, WAR/JSP file creation, Java-to-shell execution, Linux deployment messages, and post-compromise Java egress. No customer workspace was queried.

Required logs

Microsoft Sentinel tables, where ingested: AzureDiagnostics, CommonSecurityLog, DeviceFileEvents, DeviceNetworkEvents, DeviceProcessEvents, Syslog. Query results depend on appropriate collection, schema and retention.

1. First pass — Metabase exploit-sequence HTTP requests

AzureDiagnostics
| where TimeGenerated >= ago(30d)
| extend URI=tostring(column_ifexists("requestUri_s","")), ClientIP=tostring(column_ifexists("clientIP_s","")), Method=tostring(column_ifexists("httpMethod_s",column_ifexists("requestMethod_s",""))), Status=tostring(column_ifexists("httpStatus_d",""))
| where URI contains "/api/session/reset_password" or URI contains "/api/user/current"
| summarize Reset400=countif(URI contains "/api/session/reset_password" and Method =~ "POST" and Status == "400"), Current200=countif(URI contains "/api/user/current" and Method =~ "GET" and Status == "200"), Examples=make_set(strcat(Method," ",URI," ",Status),8) by Resource, ClientIP, bin(TimeGenerated,1h)
| where Reset400 > 0 and Current200 > 0
| order by Reset400 desc

2. Metabase endpoint access where HTTP status is unavailable

CommonSecurityLog
| where TimeGenerated >= ago(30d)
| extend URI=tostring(column_ifexists("RequestURL",""))
| where URI contains "/api/session/reset_password" or URI contains "/api/user/current"
| summarize ResetRequests=countif(URI contains "/api/session/reset_password"), CurrentRequests=countif(URI contains "/api/user/current"), SampleURLs=make_set(URI,5) by SourceIP, DestinationIP, bin(TimeGenerated,1h)
| where ResetRequests > 0 and CurrentRequests > 0
| order by ResetRequests desc

3. JPCERT reported historical source IPs in perimeter telemetry

let HistoricalIPs=dynamic(["20.210.128.125","3.112.252.14","54.95.112.6","69.10.51.162","172.86.91.7","210.149.87.120","31.76.91.2","136.117.40.140","136.85.58.5","141.11.187.186","207.241.172.54","213.163.202.171","221.216.140.49","221.216.140.129","124.133.237.18"]);
CommonSecurityLog
| where TimeGenerated >= ago(30d)
| where SourceIP in (HistoricalIPs)
| project TimeGenerated, SourceIP, DestinationIP, DestinationPort, RequestURL, DeviceAction, DeviceVendor, DeviceProduct
| order by TimeGenerated desc

4. API endpoint probing, privilege and account-management activity

AzureDiagnostics
| where TimeGenerated >= ago(14d)
| extend URI=tostring(column_ifexists("requestUri_s","")), ClientIP=tostring(column_ifexists("clientIP_s","")), Status=tostring(column_ifexists("httpStatus_d",""))
| where URI contains "/api/" and (URI has_any ("admin","user","role","permission","token","account") or URI contains "reset_password")
| summarize Requests=count(), Paths=dcount(URI), Failures=countif(Status startswith "4" or Status startswith "5"), Examples=make_set(URI,8) by Resource, ClientIP, bin(TimeGenerated,30m)
| where Requests >= 40 and (Paths >= 5 or Failures >= 20)
| order by Requests desc

5. Repeated API requests and endpoint diversity from one source

CommonSecurityLog
| where TimeGenerated >= ago(14d)
| extend URI=tostring(column_ifexists("RequestURL",""))
| where URI contains "/api/"
| summarize Requests=count(), Paths=dcount(URI), Targets=dcount(DestinationIP), Samples=make_set(URI,8) by SourceIP, bin(TimeGenerated,15m)
| where Requests >= 100 and (Paths >= 10 or Targets >= 3)
| order by Requests desc

6. Unexpected WAR/JSP artifacts on Java application hosts

DeviceFileEvents
| where TimeGenerated >= ago(30d)
| where FileName endswith ".war" or FileName endswith ".jsp"
| where FolderPath has_any ("webapps","tomcat","deploy","www","tmp") or InitiatingProcessFileName in~ ("java","java.exe","tomcat","bash","sh")
| project TimeGenerated, DeviceName, ActionType, FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessCommandLine, SHA256
| order by TimeGenerated desc

7. Java or Tomcat spawning shells and network utilities

DeviceProcessEvents
| where TimeGenerated >= ago(30d)
| where InitiatingProcessFileName in~ ("java","java.exe","tomcat","catalina.sh")
| where FileName in~ ("sh","bash","dash","cmd.exe","powershell.exe","curl","wget","python","python3","nc","ncat")
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine, FolderPath
| order by TimeGenerated desc

8. Linux Syslog webshell deployment and WAR/JSP messages

Syslog
| where TimeGenerated >= ago(30d)
| where SyslogMessage has_any (".war",".jsp","webshell","web shell")
| where SyslogMessage has_any ("tomcat","deploy","java","webapps","uploaded","manager","shell")
| project TimeGenerated, Computer, ProcessName, SeverityLevel, SyslogMessage
| order by TimeGenerated desc

9. Metabase-specific User-Agent and reported historical sources

CommonSecurityLog
| where TimeGenerated >= ago(30d)
| extend UA=strcat(tostring(column_ifexists("RequestClientApplication",""))," ",tostring(column_ifexists("DeviceCustomString1","")))
| where UA contains "Metabase-GHSA-vwf4/2.0" or (SourceIP in ("213.163.202.171","221.216.140.49","221.216.140.129") and RequestURL contains "/api/")
| project TimeGenerated, SourceIP, DestinationIP, DestinationPort, RequestURL, UA, DeviceAction
| order by TimeGenerated desc

10. New outbound destinations initiated by Java server processes

let Seen=DeviceNetworkEvents
| where TimeGenerated between (ago(30d) .. ago(3d))
| where InitiatingProcessFileName in~ ("java","java.exe") and isnotempty(RemoteIP)
| summarize by DeviceId, RemoteIP;
DeviceNetworkEvents
| where TimeGenerated >= ago(3d)
| where InitiatingProcessFileName in~ ("java","java.exe") and isnotempty(RemoteIP)
| join kind=leftanti Seen on DeviceId, RemoteIP
| project TimeGenerated, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, RemoteIP, RemoteUrl, RemotePort, ActionType
| order by TimeGenerated desc

Detection Notes

  • Highest signal: POST `/api/session/reset_password` with 400 followed by GET `/api/user/current` with 200 from the same source to the same Metabase service; an unexpected WAR containing JSP command execution or Java spawning shells is also high signal.
  • HTTP request method, URI, status, and client IP require WAF/access logs with those fields populated. `CommonSecurityLog` typically lacks HTTP status and may omit URL; the corresponding query is a weaker pivot.
  • The IPs in the JPCERT advisory were observed in August–October and may now have legitimate use. Do not auto-block solely on these indicators. The User-Agent strings `curl` and `python-requests` are common.
  • A `.war` file or `java` spawning a shell can be normal during CI/CD, administrative scripts, and Tomcat maintenance; correlate with deployment accounts, paths and access logs.
  • Metabase affected-version information is vendor-confirmed for CVE-2026-72898. Do not extrapolate those versions to the generic API or WAR/JSP cases.

Leave a Reply