最近在读有关JAVA反序列化漏洞的文章,对相关知识点进行了一些总结。
序列化:把对象转换为字节序列的过程,即把对象转换为可以存储或传输的数据的过程。例如将内存中的对象转换为二进制数据流或文件,在网络传输过程中,可以是字节或是XML等格式。
反序列化:把字节序列恢复为对象的过程,即把可以存储或传输的数据转换为对象的过程。例如将二进制数据流或文件加载到内存中还原为对象。
在Java 中如果需要将一个对象进行序列化,那么该对象所属类必须实现Serializable 接口或者Externalizable 接口。对于实现Serializable 接口的类,在序列化时将尝试自动调用writeObject()方法,在反序列化时将尝试自动调用readObject()方法。对于实现Externalizable 接口的对象中所包含的属性在序列化过程中将可以有选择性将指定的属性进行序列化,其序列化与反序列化时将自动调用writeExternal()方法和readExternal()方法。
反序列化漏洞的触发需要一个魔术方法(在发生特定事件或场景时被自动调用的函数,如上面的readobject())以及一个安全敏感的站点(发生危险操作的地方,可能就是一个方法)。这个安全站点要可以通过魔方方法触发,即魔方方法通过一系列的函数调用,调用到安全敏感的站点。若程序中存在这样一条从魔方方法到安全敏感站点的函数调用链,那么攻击者就可以精心设计一个对象来触发反序列化漏洞,导致安全问题。
总的来说,反序列化漏洞的根本原因是控制和数据流可以被攻击者操纵来使恶意反序列化对象能够达到和影响的安全性敏感。而且作为一种特殊的web 安全漏洞,反序列化漏洞具有入口点较为常见、攻击面较大攻击路径较多、涉及代码量较大的特点。
下面有一个例子:
readObject 方法中调用hash(key),然后hash方法中调用key.hashCode(),攻击者可以令key 为任意类的实例。若令key 值为类java.net.URL 的实例,则此时将调用URL.hashCode()。
hashCode 方法将调用handler.hashCode(this),其中handler 的默认类型为URLStreamHandler,即调用URLStreamHandler.hashCode 方法,在URLStreamHandler.hashCode 中将进一步调用getHostAddress(u),此时变量u 即为传递进来的可用key 值,最终将触发网络请求。
污点分析技术
定义:污点分析可以抽象成一个三元组<sources,sinks,processor>
的形式,其中
- source 即污点源,代表直接引入不受信任的数据或者机密数据到系统中
- sink 即污点汇聚点,代表直接产生安全敏感操作(违反数据完整性)或者泄露隐私数据到外界(违反数据保密性)
- processor 即数据流处理,代表整个数据传输和处理的过程
污染源一般为外来数据入口,即可控输入在程序中最先出现的地方,污染汇聚点一般为危险函数操作,如系统命令执行函数,数据流处理即污染在程序信息流中的传播规则。污点分析技术的工作原理就是分析程序信息流,并根据预先定义的污染传播规则,判断污染是否能从污染源传递到污染汇聚点。
污点分析技术可以分为静态污点分析和动态污点分析两种方法。静态污点分析是通过分析源码或字节码指令之间的逻辑路径,来识别潜在的污点传播路径。而动态污点分析则是通过程序插装技术,在运行时标记数据并跟踪其传播。
还可以按照分析过程中关注的程序依赖关系的不同, 可以将污点传播分析分为显示流分析和隐式流分析。
显示流分析
void foo(){
int a = source(), //污点源
int b = source(); //污点源
int x,y;
x = a * 2;
y = b + 4;
sink(x); //污点汇聚点
sink(y); //污点汇聚点
}
在上面这段代码中,a和b被污点源函数source标记为污点源,在第5、6行的对x、y赋值的过程中,其数据内容直接依赖于变量a、b,由于x,y在第7、8行到达污染汇聚点,我们就可以得出结论,例如上面代码存在的信息泄露问题。
隐式流分析
void foo(){
string X = source(); //污点源
string Y = new string();
for(int i = 0;i < X.length();i++){
int x = (int) X.charAt(i);
int y = 0;
for(int j = 0;j < x;j++){
y = y + 1;
}
Y = Y + (char) y;
}
sink(Y); //污点汇聚点
}
在上图所示的代码中,变量 X 是被污点标记的字符串类型变量,变量 Y 和变量 X 之间并没有直接或间接的数据依赖关系,但 X 上的污点标记可以经过控制依赖隐式地传播到 Y。
由第 4 行的循环条件控制的外层循环顺序地取出 X 中的每一个字符,转化成整型后赋给变量 x,再由第 7 行的循环条件控制的内层循环以累加的方式将 x 的值赋给 y,内层循环执行完毕后,x == y。最后由外层循环将 y 逐一传给 Y。
最终,第 12 行的 Y 值和 X 值相同,程序存在信息泄漏问题。
污点传播分析涉及追踪污点数据在程序执行过程中的路径,由于Java的特性,污点数据可能会经历多种操作,如集合封装、类型转换、数组元素赋值、方法调用等。在静态分析中,这些操作可能导致数据的中断或净化,因此需要考虑数据在程序执行和交互中的状态变化。最终,污点分析的目标是确定污点数据是否能够到达污点汇聚点,如命令执行或文件读写等危险操作。