Java反序列化漏洞之Javassist(8)
2023-06-15 17:10:48 # Web Security # Java Deserialization

前言

Javassist是一个可以动态生成Java字节码(.class)的库,它可以在运行的时候生成新的类。有时候,我们需要在所有class都被编译完后,运行时再修改或新建一个class文件,Javassist可以帮助我们达到这个目的。

Javassist基本元素

CtClass - Compile Time Class - 即编译时的Class,每个需要修改编辑的class都对应一个CtClass instance

ClassPool - 一个存储CtClass对象的容器

CtField - Java中的field

CtMethod - Java中的method

简单演示

导入依赖

方法一:pom.xml

1
2
3
4
5
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
</dependency>

方法二:导入jar包

可在网上下载jar包,导入module,library

创建Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import javassist.*;

import java.io.IOException;

public class javassistTest {
public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {

/*创建Class*/
//需要创建的class对应一个CtClass, ClassPool是一个容器,包含了各种CtClass
ClassPool cp = ClassPool.getDefault();//获取一个默认的ClassPool
CtClass test = cp.makeClass("Evil");//用这个ClassPool来创建一个CtClass,名字为Evil

/*添加Field*/
CtField name = new CtField(cp.get("java.lang.String"),"name",test);//create a String-type field called name for the class test
name.setModifiers(Modifier.PRIVATE);//private attribute
test.addField(name,CtField.Initializer.constant("Mark"));//给test class里的name字段初始化为Mark

/*添加constructor*/
CtConstructor ctConstructor = new CtConstructor(new CtClass[]{},test);//给Test Class创建一个无参constructor
ctConstructor.setBody("{name=\"Jack\";}");
test.addConstructor(ctConstructor);
//有参构造函数
CtConstructor ctConstructor1 = new CtConstructor(new CtClass[]{cp.get("java.lang.String")},test);
ctConstructor1.setBody("{$0.name=$1;}");//this.name = name(第一个parameter)
test.addConstructor(ctConstructor1);

/*添加method*/
CtMethod printName = new CtMethod(CtClass.voidType,"printName",new CtClass[]{},test);
printName.setModifiers(Modifier.PUBLIC);
printName.setBody("{System.out.println($0.name);}");
printName.insertBefore("System.out.println(\"before:\");");//在方法体前面加入(注意必须有了方法体才能插入)
printName.insertAfter("System.out.println(\"after:\");");//在方法体后面加入
test.addMethod(printName);

/*写出Class到本地*/
test.writeFile();
test.detach();

}
}

结果

image-20211124203629163

一些特殊参数

标识符 作用
0、1、$2、 3 、 3、 3、… this和方法参数(1-N是方法参数的顺序,如第一个parameter)
$args 方法参数数组,类型为Object[]
$$ 所有方法参数,例如:m($$)相当于m(1,1,2,…)
$cflow(…) control flow 变量
$r 返回结果的类型,在强制转换表达式中使用。
$w 包装器类型,在强制转换表达式中使用。
$_ 返回的结果值
$sig 类型为java.lang.Class的参数类型对象数组
$type 类型为java.lang.Class的返回值类型
$class 类型为java.lang.Class的正在修改的类

Reference

Java字节码编程之非常好用的javassist