1.反序列化基础利用
2.pop链
POP链: POP(面向属性编程)链是指从现有运行环境中寻找一系列的代码或指令调用,然后根据需求构造出一组连续的调用链。
反序列化利用就是要找到合适的POP链。其实就是构造一条符合原代码需求的链条,去找到可以控制的属性或方法,从而构造POP链达到攻击的目的。
寻找POP链的思路:
A.寻找unserialize0函数的参数是否可控;
B.寻找反序列化想要执行的目标函数,重点寻找魔术方法(比如 wakeup()和 destruct())
C.一层一层地研究目标在魔术方法中使用的属性和调用的方法,看看其中是否有我们可控的属性和方法
D.根据我们要控制的属性,构造序列化数据,发起攻击
解题思路:
A.构造利用链,就要找到头和尾。再想办法把头和尾连接起来。
B.$sid和$config是用户输入可以控制的,这是利用链的头部。
C.最终目的是读取flag.php文件,就要从源代码中需要可以读文件或者执行系统命令的地方。Read->get_file和Show->show可以读取文件,但是Show->show函数不允许出现flag。因此,Read->get_file就是POP链的尾部,
D.如何触发Read->get_file呢?搜索get_file发现,Show-> tostring中存在代码:$content=$this->class1->get_file($this->var);那么只需要让$this->class1=new Read;$this->var='flag.php'即可触发get_file,得到flag.php
E.那么如何触发Show->tostring呢?本题存在手动触发函数的命令$config->$sid;,参数是用户控制的(POP链的头部),因此可以令:$config=new Show;$sid='__toString';这样就完成了pop链的构造
解法一:
解法二:
由于_tostring是魔术方法,还可以自动触发,触发条件为“把对象当成字符串使用”,那么就需要寻找使用字符串的地方,传入对象,就可以触发_tostring了。本题中preg_match函数的参数就是字符串,因此需要
$this->source=show;//this就是当前的类,因此本题要生成两个show对象,其中一个Show对象的source属性值为另一个show对象
再利用$config->$sid触发Show->Change或者Show->show方法即可。
3.畸形序列化字符串
(1)认识畸形序列化字符串
畸形序列化字符串就是故意修改序列化数据,使其与标准序列化数据存在个别字符的差异,达到绕过一些安全函数的目的。
应用领域:
a.绕过 wakeup( )
b.快速析构(fast destruct):绕过过滤函数,提前执行_destruct
(2)绕过_wakeup
由于使用unserialize( )函数后会立即触发_wakeup,为了绕过_wakeup中的安全机制,可以用修改属性数量的方式绕过wakeup方法。受影响版本:
php5.0.0~ php5.6.25
php7.0.0 ~ php7.0.10
绕过方法:
反序列化时,修改对象的属性数量,将原数量+n,那么_wakeup方法将不再调用。比如:
//标准序列化数据
0:3:"BUU":2:{s:7:"correct";N;s:5:"input";R:2;}
//修改为:
0:3:"BUU":3:{s:7:"correct";N;s:5:"input";R:2;}
(3)快速析构
快速析构的原理:当php接收到畸形序列化字符串时,PHP由于其容错机制,依然可以反序列化成功。但是,由于你给的是一个畸形的序列化字符串,总之他是不标准的,所以PHP对这个畸形序列化字符串得到的对象不放心,于是PHP就要赶紧把它清理掉,那么就触发了他的析构方法(_destruct( ))。
应用场景:某些题目需要利用_destruct才能获取flag,但是_destruct是在对象被销毁时才触发(执行顺序太靠后),_destruct之前会执行过滤函数,为了绕过这些过滤函数,就需要提前触发_destruct方法
畸形字符串的构造方法:
A.改掉属性的个数
B.删掉结尾的 }
(4)例题
解题思路:
A.明确POP的起点:unserialize($ GET['poc'])
B.明确POP的终点:Demo2-> tostring()
C.怎样连接起点和终点?
DemoX->_destruct( )//不能执行DemoX->wakeup( )
DemoX->_tostring( )
Demo2->_tostring( )
D.怎样执行绕过DemoX->_wakeup( )?先生成正常的序列化数据,再改变属性个数。
E.通过对比,定位到属性个数为2的数据,然后修改为3,得到payload:
O%3A5%3A%22DemoX%22%3A3%3A%7Bs%3A7%3A%22%00%2A%00user%22%3BO%3A5%3A%22Demo2%22%3A1%3A%7Bs%3A13%3A%22%00Demo2%00fffl4g%22%3Bs%3A8%3A%22flag.php%22%3B%7Ds%3A6%3A%22%00%2A%00sex%22%3Bs%3A3%3A%22xxx%22%3B%7D
检查页面源代码得:
4.指针问题
解题思路:
A.构造POP链,就要找到头和尾,再想办法把头和尾连接起来
B.$p是用户输入的,是可控的,这是POP链的头部
C.最终目的是要读取flag.php,就要从源代码中找到可以读文件或者执行系统命令的地方。通读后可知Alize->getFlag( )可以读取文件。
echo @highlight_file($this->f,true);
那么,只需要令
$this->f='flag.php';
$this->t1 === $this->t2:
因此 Alize->getFlag( )就是POP链的尾部。
D.如何触发Alize->getFlag( )呢?搜索 getFlag,发现 Seri->_destruct( )中存在代码$this->alize->getFlag();
那么,只需要令
$this->alize=new Alize;
这样就完成了POP链的构造。