PHP反序列化漏洞
序列化与反序列化
seriallization 序列化 : 将对象转化为便于传输的格式, 常见的序列化格式:二进制格式,字节数组,json字符串,xml字符串。
deseriallization 反序列化:将序列化的数据恢复为对象的过程。
PHP反序列化
serialize(); 将对象序列化成字符串
unserialize(); 将字符串反序列化回对象
序列化
对象转换成字符串
方便传输
创建类
class Stu{
public $name;
public $age;
public $sex;
public $score;
}
创建对象(序列化)
$stu1 = new Stu();
$stu1->name = "xiu";
$stu1->age = 18;
$stu1->sex = true;
var_dump($stu1);
echo "<hr />";
echo serialize($stu1);
反序列化
字符串转换成对象
O:object
反序列化漏洞
以 __ 开头的函数,是PHP 中的魔术方法。
类中的魔术方法,在特定情况下会自动调用。即使魔术方法在类中没有被定义,也是真实存在的。
两个下划线
__construct() 在创建对象时自动调用
__destruct() 在销毁对象时自动调用
__wakeup() unserialize()时会自动调用这个函数
__sleep() serialize()时会自动调用这个函数
例子
<?php
class animal{
public $name;
public $age;
public function __sleep(){
if(@$_GET['cmd']=="xiu"){
system('calc');
}
}
}
$an1=new animal;
$an1->name="dog";
$an1->age=3;
//var_dump($an1);
@serialize($an1);
?>
序列化和反序列化的作用
保证数据在互联网上完整高效的传输
什么是反序列化漏洞?
序列化和反序列化本身是为了保证数据在网络上完整高效的传输,但是由于反序列化过程中,某些函数会被自动调用,这个函数满足一定的条件前提下,去实现一种链式调用,最终调用到存在任意代码执行或者任意命令执行的恶意的函数的地方。
php反序列化漏洞
是由于他的魔术方法自动调用造成了一个链式的利用
java反序列化漏洞
是由于子类再重写父类的时候,造成了代码链式调用
修改序列化后的数据,目的是什么?
为了满足一定的条件以后实现链式调用
JAVA反序列化漏洞
idea
类继承
子类自动继承了父类的所有公共成员属性和方法,主要是避免重复编写类似的代码。在Java中,一个类可以通过关键字extends继承自另一个类,成为其子类。被继承类称为父类。
public class Person {
public int age;
public String name;
public void talk(){
System.out.println("Person 说话了");
}
}
定义一个类Person,里面添加了属性
public :的意思是所有的类可以访问它
整数型age年龄
字符串name姓名
给它定义一个talk方法,实现输出一行字符
public class Student extends Person{
定义一个类Student这个类继承于Person这个类
extends用于声明一个类指定他的父类
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.talk();
}
}
定义一个类Test,
创建了一个名为stu1的student对象
stu1.看对象有哪些属性,然后stu1调用了talk方法
类重写
重写是指子类中定义一个与父类中名称相同、但行为不同的方法的过程,也称为方法覆盖。重写的方法必须具有与父类方法相同的名称、参数列表和返回类型,且不能缩小或增加其访问权限。子类重写一个某个行为是为了实现自己特定的需求,即子类本着"用一种特殊的方式处理方法中的代码"的原则对父类的方法进行修改,以便更好地适应于子类自身的特殊要求
public class Person {
public int age;
public String name;
public void talk(){
System.out.println("Person 说话了");
}
}
定义一个类Person,里面添加了属性
public :的意思是所有的类可以访问它
整数型age年龄
字符串name姓名
给它定义一个talk方法,实现输出一行字符
public class Student extends Person{
public int score;
public void talk(){
System.out.println("Student 说话了");
}
}
定义一个类Person,里面添加了属性
public :的意思是所有的类可以访问它
整数型score分数
给它定义一个talk方法,实现输出一行字符
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.talk();
}
}
定义一个类Test,创建了一个名为stu1的student对象
stu1.看一样对象有哪些属性,调用了talk方法
数据前五个字节
rO0AB java序列化base64编码数据
aced 16进制java序列化序列化:
ObjectOutputStream --> writeObject()
反序列化:
ObjectInputStream --> readObject()
反序列化漏洞
编写JAVA反序列化的代码实现序列化与反序列化
定义了一个
person
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
public class Person implements Serializable {
public int age;
public String name;
}
定义一个Person的类,实现了Serializable的接口
里面有两个属性一个年龄一个姓名
定义了一个
Test
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Person p=new Person();
p.age=18;
p.name="xiu";
serialize(p,"xiu.bin");
System.out.println("反序列化结果:" + deserialize("xiu.bin"));
}
//serialize接受两个参数,一个对象,一个文件路径,把序列化后的obj对象,储存到filePath指定的文件路径里
public static void serialize(Object obj, String filePath) throws IOException {
try (FileOutputStream fileOut = new FileOutputStream(filePath);
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut)) {
objectOut.writeObject(obj);
}
}
//给deserialize一个文件路径,该函数会把这个文件的内容反序列化回对象。
public static Object deserialize(String filePath) throws IOException, ClassNotFoundException {
try (FileInputStream fileIn = new FileInputStream(filePath);
ObjectInputStream objectIn = new ObjectInputStream(fileIn)) {
return objectIn.readObject();
}
}
}
创建一个Person类和对象p,给对象设置属性,调用serialize方法将该对象序列化到指定的文件路径"xiu.bin"中。接着,调用deserialize方法,从刚才序列化的文件中读取数据,并将其反序列化为对象,并输出反序列化后的结果。
反序列化漏洞
重写readObject方法调用计算器,实现反序列化漏洞的原理
定义了一个
person
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
public class Person implements Serializable {
public int age;
public String name;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
Runtime.getRuntime().exec("calc");
// 默认的反序列化操作
in.defaultReadObject();
}
}
定义一个Person的类,实现了Serializable的接口,标识一个类可以被序列化(Serialized)和反序列化(Deserialized)
里面有两个属性一个年龄一个姓名
定义了一个ObjectInputStream的变量,变量里面包含readobject的方法,用于对象的反序列化
Runtime.getRuntime().exec("calc");会在winodws中启动计算机程序
定义了一个
Test
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Person p=new Person();
p.age=18;
p.name="xiu";
serialize(p,"xiu.bin");
System.out.println("反序列化结果:" + deserialize("xiu.bin"));
}
//serialize接受两个参数,一个对象,一个文件路径,把序列化后的obj对象,储存到filePath指定的文件路径里
public static void serialize(Object obj, String filePath) throws IOException {
try (FileOutputStream fileOut = new FileOutputStream(filePath);
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut)) {
objectOut.writeObject(obj);
}
}
//给deserialize一个文件路径,该函数会把这个文件的内容反序列化回对象。
public static Object deserialize(String filePath) throws IOException, ClassNotFoundException {
try (FileInputStream fileIn = new FileInputStream(filePath);
ObjectInputStream objectIn = new ObjectInputStream(fileIn)) {
return objectIn.readObject();
}
}
}
创建一个Person类和对象p,给对象设置属性,调用serialize方法将该对象序列化到指定的文件路径"xiu.bin"中。接着,调用deserialize方法,从刚才序列化的文件中读取数据,并将其反序列化为对象,并输出反序列化后的结果。
创建一个Person类和对象p,给对象设置属性,调用serialize方法将该对象序列化到指定的文件路径"xiu.bin"中。接着,调用deserialize方法,从刚才序列化的文件中读取数据,并将其反序列化为对象,并输出反序列化后的结果。
什么是反序列化漏洞
PHP的反序列化和java的反序列化是两种不同的类型,序列化和反序列化本身没有漏洞点,只是为了实现数据的完整高效的传输,
PHP反序列漏洞是由于类里面的魔术方法调用了某个函数,该危险函数又调用了别的函数,最终执行到了危险函数的位置
JAVA反序列化漏洞是由于开发者重写了readObject方法,该readObject方法方法调用了别的方法,最终执行到了例如Transfrom方法的危险方法