0x00 first
前几天joomla爆出个反序列化漏洞,原因是因为对序列化后的字符进行过滤,导致用户可控字符溢出,从而控制序列化内容,配合对象注入导致RCE。刚好今天刷CTF题时遇到了一个类似的场景,感觉很有意思,故有本文。
0x01 我打我自己之---序列化问题
关于序列化是什么就不再赘述了,这里主要讲几个跟安全相关的几个点。
看一个简单的序列化
<?php
$kk = "123";
$kk_seri = serialize($kk); //s:3:"123";
echo unserialize($kk_seri); //123
$not_kk_seri = 's:4:"123""';
echo unserialize($not_kk_seri); //123"
从上例可以看到,序列化后的字符串以"作为分隔符,但是注入"并没有导致后面的内容逃逸。这是因为反序列化时,反序列化引擎是根据长度来判断的。
也正是因为这一点,如果程序在对序列化之后的字符串进行过滤转义导致字符串内容变长/变短时,就会导致反序列化无法得到正常结果。看一个例子
<?php
$username = $_GET['username'];
$sign = "hi guys";
$user = array($username, $sign);
$seri = bad_str(serialize($user));
echo $seri;
// echo "<br>";
$user=unserialize($seri);
echo $user[0];
echo "<br>";
echo "<br>";
echo $user[1];
function bad_str($string){
return preg_replace('/\'/', 'no', $string);
}
先对一个数组进行序列化,然后把结果传入bad_str()函数中进行安全过滤,将单引号转换成no,最后反序列化得到的结果并输出。看一下正常的输出:
用户ka1n4t的个性签名很友好。如果在用户名处加上单引号,则会被程序转义成no,由于长度错误导致反序列化时出错。
那么通过这个错误能干啥呢?我们可以改写可控处之后的所有字符,从而控制这个用户的个性签名。我们需要先把我们想注入的数据写好,然后再考虑长度溢出的问题。比如我们把他的个性签名改成no hi,长度为5,在本程序中序列化的结果应该是i:1;s:5:"no hi";,再跟前面的username的双引号以及后面的结束花括号闭合,变成";i:1;s:5:"no hi";}。见下图
我们要让'经过bad_str()函数转义成no之后多出来的长度刚好对齐到我们上面构造的payload。由于上面的payload长度是19,因此我们只要在payload前输入19个',经过bad_str()转义后刚好多出了19个字符。
尝试payload:ka1n4t'''''''''''''''''''";i:1;s:5:"no hi";}
成功注入序列化字符。前几天的joomla rce原理也正是如此。下面通过一道CTF来看一下实战场景。
0x02 [0CTF 2016] piapiapia
首页一个登录框,别的嘛都没有
www.zip源码泄露,可直接下载源码。
flag在config.php中