Detecting Fastjson 1.2.83 “Gadget-Free” RCE — a WAF / RASP / SIEM Playbook

The previous article, Fastjson 1.2.83 Gadget-Free RCE Explained, focused on how to fix. This one focuses on how to see it happen — the four layers where an attack leaves traces, plus the concrete fields, rules, and hooks you can paste into your SIEM / WAF / RASP.

1. Set the mental model first

The defining feature of gadget-free research is that it does not rely on any historical chain. Payload-signature IDS / WAF rules therefore fail. You need to shift from the byte layer to the behaviour layer. This article covers four observation points:

  1. Gateway / WAF: request semantics — not keywords, but JSON structure
  2. Application logs: what Fastjson itself throws
  3. RASP / bytecode: in-process class loading and reflection
  4. Network & host: JNDI egress, suspicious child processes, unusual ports

A hit on any layer deserves an alert; a hit on all four is almost certainly a successful attack. Fighting gadget-free is about moving from point detection to chain detection.

2. Gateway / WAF: JSON-semantic rules

Legacy regex hunting for Runtime, ProcessBuilder or ldap:// almost never catches gadget-free payloads. The new approach is to parse the JSON and look at its structure:

Core rules

  • Rule A: top-level @type — if the body is application/json and the root object contains an @type key, alert immediately. Real polymorphism should be resolved server-side.
  • Rule B: nested @type@type at any depth: run in audit mode first (avoid breaking legitimate allow-listed endpoints); after 7 days of observation, tune the block threshold.
  • Rule C: suspicious values — block outright when @type equals com.sun.rowset.JdbcRowSetImpl, org.apache.tomcat.dbcp.dbcp2.BasicDataSource, javax.naming.InitialContext, or contains ldap:// / rmi:// / dns://.
  • Rule D: obfuscated class names — mark high-risk if the @type value contains classic bypass tricks: trailing ;, [L array notation, Base64 / Unicode escapes, inner-class $.
  • Rule E: unusual JSON depth — nesting > 8 layers or > 200 keys per request is rare in legitimate traffic and common in deserialization payloads. Audit-alert.

ModSecurity-style pseudo rule (illustrative)

# Semantic intent only — follow your WAF engine's actual syntax
SecRule REQUEST_HEADERS:Content-Type "@contains application/json" \
    "id:'900001',phase:2,pass,nolog,ctx.check_fastjson=1"

SecRule REQUEST_BODY "@rx (?i)\"@type\"\s*:" \
    "id:'900002',phase:2,chain,block,\
     msg:'Fastjson autoType marker detected',\
     tag:'application-multi',tag:'language-java'"
    SecRule TX:CTX.CHECK_FASTJSON "@eq 1"

3. Application logs: Fastjson will tell you itself

When checkAutoType blocks a payload, Fastjson 1.2.83 throws com.alibaba.fastjson.JSONException — usually containing one of these strings:

  • autoType is not support
  • autoTypeSupport is disabled (safeMode active)
  • expect '{', but ... (parse failure with type reference)
  • syntax error, expect Type

Turn them into SIEM rules: same source IP, ≥ 3 of these exceptions in 5 minutes → high-severity alert + auto-add to watchlist. This is the cheapest, easiest signal to ship — many customer environments already have the logs; they just aren't rule-ified.

Halocent field note: across three real customer red-team exercises, the attackers left autoType is not support in the app log within the first 30 seconds of probing — but no one was alerting on the string, so the golden-hour was missed.

4. RASP / bytecode: the decisive layer

Even if a gadget-free payload sneaks past the WAF and past checkAutoType, producing a "side effect" still forces the JVM through a small set of APIs. Hooking those APIs yields the highest signal.

Priority RASP hook points

  1. java.lang.ClassLoader#defineClass — any defineClass triggered from a deserialization stack merits a high-severity alert.
  2. javax.naming.InitialContext#lookup / Context#lookup — capture the JNDI subject; alarm on ldap:// / rmi:// prefixes.
  3. java.lang.Runtime#exec, ProcessBuilder#start — walk the servlet thread stack; if any frame is com.alibaba.fastjson, terminate the request.
  4. ScriptEngine#eval, GroovyClassLoader#parseClass — any scripting channel.
  5. java.net.URLClassLoader construction — creating a URLClassLoader from a deserialization path is almost always malicious.

Stack-trace matching — chain, not point

Emit each hook with its call stack; alert whenever the pattern matches:

ClassLoader.defineClass
  <- java.lang.reflect.Method.invoke
  <- com.alibaba.fastjson.serializer.ObjectDeserializer...
  <- com.alibaba.fastjson.JSON.parseObject

"From JSON.parseObject straight to defineClass" is a vanishingly rare legitimate pattern. Use it as a signature — extremely low false positive, extremely high recall.

Re-usable OpenRASP recipe

  • Enable the deserialization and webshell_file_put plugins.
  • Add a custom hook in plugins/: intercept com.alibaba.fastjson.parser.deserializer.*#deserialze; if the type argument is a Class AND the current request came from an internet-facing endpoint, tag the request context.
  • Later, any defineClass / exec / lookup hitting a tagged request → terminate.

5. Network & host: last-mile correlation

Even if the first three layers miss, the attacker still needs to pull in a second-stage payload. So:

  • DNS: pipe all Java-process DNS through internal DoH; hits on known dnslog / collaborator / interact domains (*.dnslog.cn, *.ceye.io, *.oastify.com, *.interact.sh, etc.) → sub-second alert.
  • Egress: production Java services deny outbound 389 / 636 (LDAP), 1099 / 1098 (RMI), any non-allow-listed port by default.
  • Child-process alerts: any JVM spawning sh / bash / cmd / powershell / curl / wget — unless explicitly white-listed for the business — is high-severity.
  • File-write alerts: JVM writing .jsp / .class / .so in /tmp, /var/tmp, or web roots → alert and preserve for forensics.

6. Cross-layer correlation: connect the story

Each layer has some false-positive rate; the value is in the correlation. Recommended SIEM rule:

alert = 
    WAF(fastjson_autotype)                # gateway
 && APP_LOG(autoType is not support)     # application
 && RASP(defineClass from fastjson stack) # runtime
 && (Egress(LDAP/RMI) OR JVM child proc)  # host

Two layers → auto-ticket high-severity; three or more → auto-isolate the host / pod and enter incident response. This is Halocent's preferred SOC configuration — < 0.1% false-positive rate and > 95% coverage on major incidents.

7. Copy-paste 8-step detection checklist

  1. WAF: add the 5 JSON-semantic rules (top-level @type, nested @type, suspicious values, obfuscation, extreme depth).
  2. WAF: run in audit for 7 days before flipping to block.
  3. SIEM: ingest the four Fastjson exception strings (autoType is not support, autoTypeSupport is disabled, etc.).
  4. SIEM: same source IP, 3 hits in 5 minutes → high severity.
  5. RASP: add stack-match-fastjson alerts on defineClass, InitialContext#lookup, Runtime#exec.
  6. DNS: deny Java-process access to known dnslog / collaborator domains by default.
  7. Network: block outbound LDAP / RMI / non-allow-listed ports from Java processes.
  8. EDR: alert on JVM child processes and on writes to web roots.

With all eight in place, your organisation's visibility into Fastjson-class RCE moves from "invisible" to "cannot land without alerting". Halocent can turn this checklist into a product-specific rollout plan for your SOC / WAF / RASP.

← Back to News & Insights

Need a Fastjson detection-capability assessment?

Response within 1 business day; 5-day delivery: coverage assessment of your WAF / SIEM / RASP, gap list, and a 30-day remediation plan.