Red Hat JBoss Application Server 是一款基于JavaEE的开源应用服务器。JBoss AS 4.x及之前版本中,JbossMQ实现过程的JMS over HTTP Invocation Layer的HTTPServerILServlet.java文件存在反序列化漏洞,远程攻击者可借助特制的序列化数据利用该漏洞执行任意代码。
因为没有鉴权,攻击者能调用这个接口;
而这个接口内部又错误地把用户输入当成"可执行对象",
所以最终导致了代码执行。
|----------|----------------|
| 漏洞 | 本质人话 |
| 任意文件读取 | 不该给你看的文件,给你看了 |
| 未授权访问 | 不该你用的功能,你能用 |
| 反序列化 RCE | 不该执行你给的东西,却执行了 |
CVE-2017-7504 = 未授权 + 反序列化 = RCE
首先通过未授权,我们可以使用这个接口,而这个接口又有反序列化功能,我们将命令藏在其中导致反序列化的时候可以执行这个命令
public class HttpInvokerServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { InputStream is = request.getInputStream(); // ❌ 直接反序列化用户输入 ObjectInputStream ois = new ObjectInputStream(is); try { Object obj = ois.readObject(); // ← 漏洞点 process(obj); } catch (Exception e) { e.printStackTrace(); } }
}
chatgpt模拟的伪代码
对于用户输入的数据会直接使用readObject进行反序列化
到底是如何夹带命令的,下边举例一个序列化之前的代码
public class EvilObject implements Serializable {
private void readObject(ObjectInputStream in) throws Exception { in.defaultReadObject(); // 反序列化瞬间执行 Runtime.getRuntime().exec("calc"); }
}
攻击者会将这整个类都序列化,等到反序列化时,会直接还原出一个对象来直接进行执行
readObject() 就是 Java 反序列化过程中最关键、最危险的那个函数。
攻击者会将这整个类都序列化,等到反序列化是,会直接还原出一个类来直接进行执行(这是我之前的观点,但是并不是特别正确)攻击者不是构造一个类,而是通过一些方式利用java已经存在的类
✅ 正确理解
你家里本来就有刀、火、汽油
我只是教你:
先点火 → 再倒油 → 再扔刀
你照着做,出事了
👉 东西都是你家的,我只是安排顺序
反序列化攻击 = 不发新代码,
而是让服务器用"它自己已有的代码"把自己打死
JBoss 在反序列化对象时,会自动触发一连串对象方法调用;
我构造一个"层层嵌套的对象结构",
让 JVM 在反序列化过程中一层一层调用,
最终调用到 Runtime.exec() 执行命令。
想象你给 JBoss 寄了一个"套娃"
盒子 A └── 盒子 B └── 盒子 C └── 盒子 D(写着:执行命令)
JBoss 反序列化时会做什么?
- 打开 A(调用 A 的方法)
- A 里面要用 B → 打开 B
- B 里面要用 C → 打开 C
- C 里面要用 D → 打开 D
- D 的方法里:💥 Runtime.exec()
👉 你不是让它"解密"
👉 是让它 按规则自己拆盒子
为什么叫 gadget「链」?
因为它真的就是一条链:
readObject()
↓
hashCode()
↓
get()
↓
transform()
↓
invoke()
↓
exec()
这里博主使用ysoserial工具生成这个二进制数据然后放入脚本进行请求
import requests url = "http://192.168.68.129:8080/invoker/JMXInvokerServlet" with open(r"E:\HTML\pythonscript\JBoss\passwd1.bin", "rb") as f: payload = f.read() headers = { "Content-Type": "application/x-java-serialized-object" } r = requests.post(url, data=payload, headers=headers, timeout=5) print(r.content)
不过报错了,通过chatgpt的指导发现了问题
JBoss只接收MarshalledInvocation 这种"JBoss 远程调用请求包"
发送的最外层对象,必须是 MarshalledInvocation 这种"JBoss 远程调用请求包"
我直接将这个MarshalledInvocation当中的内容发过去了怪不得报错
不过由于我这里并没有jboss相关配置所以就不再进行演示漏洞利用了