利用DNS缓存和TLS协议将受限SSRF变为通用SSRF
本文首发于先知社区
前言
这是今年BlackHat上的一个议题:When TLS Hacks You,作者是latacora的Joshua Maddux
议题提出了一个新的ssrf攻击思路,利用DNS重绑定技术和https的优化算法(TLS Session resumption)的缺陷,将受限的SSRF变为通用的SSRF。攻击方法与之前的SNI injection类似,但是这次利用的是TLS的一种特性,而不是在特定实现中的bug。
本文是对When TLS Hacks You这一议题的一些简单总结和分析,如有错误或不当之处请大佬们多多包涵。
背景知识
SSRF
原理
其形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,但又没有对目标地址做严格过滤与限制,导致攻击者可以传入任意的地址来让后端服务器对其发起请求,并返回对该目标地址请求的数据。
危害
- 内网、本地端口扫描,获取开放端口信息
- 主机信息收集,web应用指纹识别,获取服务banner信息
- 根据识别出的应用针对性的发送payload攻击,例如struts2
- 攻击内网和本地的应用程序及服务。
- 穿越防火墙
- 利用file协议读取本地文件,比如
file:///etc/passwd
常用协议
| 协议名称 | 简介 |
|---|---|
| Gopher协议 | 攻击内部应用的主力军 |
| Dict协议 | 端口探测,版本信息收集 |
| ftp协议 | 探测是否存在ftp |
| http协议 | 探测是否存在ssrf |
| file协议 | 读取本地文件 |

注:jdk1.7后java不再支持gopher
防御手段
- 禁止跳转
- 过滤返回信息
- 禁用不需要的协议
- 设置URL白名单或者限制内网IP
- 限制请求的端口为http常用的端口
- 统一错误信息
在请求资源前先访问DNS服务器判断是否为内网IP

DNS rebinding
针对上图防御手段的一种绕过
TTL
TTL是英语Time-To-Live的简称,意思为一条域名解析记录在DNS服务器中的存留时间。当各地的DNS服务器接受到解析请求时,就会向域名指定的NS服务器发出解析请求从而获得解析记录;在获得这个记录之后,记录会在DNS服务器中保存一段时间,这段时间内如果再接到这个域名的解析请求,DNS服务器将不再向NS服务器发出请求,而是直接返回刚才获得的记录;而这个记录在DNS服务器上保留的时间,就是TTL值。
它表示DNS记录在DNS服务器上缓存的时间,数值越小,修改记录各地生效的时间越快。
DNS解析
- DNS区域是一个层次结构的空间, 根域名服务器->子域名服务器->二代子域名服务器
- DNS查询方式: 递归和迭代
递归

迭代

解析流程

- 检查浏览器缓存中是否缓存过该域名对应的IP地址
- 如果在浏览器缓存中没有找到IP,那么将继续查找本机系统(如HOSTS文件)是否缓存过IP
- 向本地域名解析服务系统(路由器或者内网DNS服务)发起域名解析的请求
- 开始递归查询运营商dns -> 根域名服务器 -> 顶级域名(gTLD)服务器 -> 我们设置NS域名服务器。(这一步很重要,我们可以递归向下设置TTL的值)
- NS返回IP地址给本地服务器,本地服务器缓存解析结果(TTL)
- 解析结果返回给用户,建立TCP通信
DNS重绑定
当我们发起域名解析请求的时候,第一次访问会返回一个ip地址A,但是当我们发起第二次域名解析请求的时候,却会返回一个不同于A的ip地址B。

攻击思路是基于这种SSRF防御思路的基础上的,检查逻辑是第一次DNS查询请求确定host是不是内网IP,第二次请求的时候存在一个小间隔,导致了解析的差异性。
尝试
如下图设置好域名的A记录及NS记录,指定DNS服务器为自己搭建的

在vps上运行代码启动DNS服务(嫖的大佬的代码实现)
# -*- coding:utf-8 -*-
from twisted.internet import reactor, defer
from twisted.names import client, dns, error, server
record={}
class DynamicResolver(object):
def _doDynamicResponse(self, query):
name = query.name.name
if name not in record or record[name]<1:
ip="106.56.229.29" #这个ip只要是外网ip就行
else:
ip="127.0.0.1"
if name not in record:
record[name]=0
record[name]+=1
print name+" ===> "+ip
answer = dns.RRHeader(
name=name,
type=dns.A,
cls=dns.IN,
ttl=0, # 这里设置DNS TTL为 0
payload=dns.Record_A(address=b'%s'%ip,ttl=0)
)
answers = [answer]
authority = []
additional = []
return answers, authority, additional
def query(self, query, timeout=None):
return defer.succeed(self._doDynamicResponse(query))
def main():
factory = server.DNSServerFactory(
clients=[DynamicResolver(), client.Resolver(resolv='/etc/resolv.conf')]
)
protocol = dns.DNSDatagramProtocol(controller=factory)
reactor.listenUDP(53, protocol)
reactor.run()
if __name__ == '__main__':
raise SystemExit(main())
可以看到代码用twisted实现了dns服务,并且设置了TTL为0
效果如下


TLS session resumption
TLS shake
一个完整的 TLS 握手需要两次
- Client 发送 ClientHello;Server 回复 ServerHello
- Client 回复最终确定的 Key,Finished;Server 回复 Finished
- 握手完毕,Client 发送加密后的 HTTP 请求;Server 回复加密后的 HTTP 响应

这一过程的花费是 2RTT(Round-Trip-Time),为了减少这一开销,可以用TLS session resumpition将密钥缓存起来,下次建立链接时直接使用。
| 优化方案 | 原理 |
|---|---|
| session id | 服务端记住会话状态,客户端发带session id的client hello,服务端返回之前存储的SSL会话 |
| session ticket | 客户端记住会话状态,服务端记住用于加密返回给客户端的ticket的密钥 |
| PSK | 客户端和服务器第一次建立会话时,会生成一个PSK(pre-shared key)。服务器会用ticket key去加密 PSK,作为Session Ticket返回 |
session id 的相关数据是存放在 server 端,session ticket 是存放在 client 端, 在这个攻击手法中 session id只能存放 32 byte 的 payload,session ticket 则能放更多字节的 payload。
https协议的实现(CURL)

在curl的实现代码中只检查了域名、端口和协议。而没有检查IP,因此可以用DNS重绑定的手段。
攻击方式
将上述三者结合,利用DNS缓存和TLS协议将受限SSRF变为通用SSRF。
实际漏洞案例
- Youtrack — CVE-2019-12852JetBrains YouTrack 服务的SSRF
- Nextcloud — 一个分享功能造成的SSRF,使用TLS重绑定攻击本地的memcached
攻击面

此种攻击手法需要三个条件,大部分受限的SSRF,带外通信的TLS session,本地端口上运行的应用。
SSRF攻击点
- OIDC discovery(sometimes)
- Webpush
- Webmention
- Apple Pay Web
- In browsers, just phishing people (Then we call it CSRF)
- Wificaptive portals
- SSDP
- SVG conversion
- URL-based XXE
- Scraping
- Webhooks
- PDF renderers with images enabled
TLS session缓存情况

易受攻击的内网应用

攻击流程
Demo:Phishing->CSRF->RCE
作者给了一个Demo。假设受害者是一个使用django.core.cache的项目的开发者,并且使用了memcached。受害者在Chrome等易受影响的浏览器中浏览电子邮件。受害者有一定安全意识,不会下载邮件中的附件。

攻击者会制作一封钓鱼邮件

邮件中的图片标签指向攻击者准备好的网站

然后弹计算器
整个攻击流程如图所示

- 攻击者制作钓鱼邮件,内容标签会向
https://ssltest.jmaddux.com:11211(攻击者准备的网站)发起请求 - 受害者打开邮件,内容开始加载并请求域名
- 受害者客户端向
ssltest.jmaddux.com的NS记录指定的DNS服务器请求DNS解析,DNS服务由攻击者搭建的DNS Server提供 - DNS服务器返回正常对应的TLS Server地址,并且设置TTL为0
- 客户端发送Client Hello
- 服务端返回Server Hello,并在包中设置payload(添加在
session id/session ticket/psk字段中) - 进行后续的TLS握手
- 握手完成后进行http通信时,网站返回301跳转到
https://ssltest.jmaddux.com:11211 - 由于之前设置TTL为0,客户端再次向DNS服务器询问网站IP地址
- 此时DNS服务器返回
127.0.0.1 - 由于TLS会话重用的优化算法,客户端会读取带有payload的SSL会话缓存访问
127.0.0.1:11211 - payload加载完成RCE
未来工作
作者在讲述未来工作时提出了要建设更好的测试基础设施

- Alternating DNS Server:实现DNS重绑定
- Custom TLS:提供https服务,并传输payload
- Just netcat:监控受害者与Custom TLS的交互流量,判断攻击状态
github项目:https://github.com/jmdx/TLS-poison
防御手段
作者提出了三种防御手段
改变缓存的key值
- 现在是(
hostname,port),修改为(hostname,port,ip_addr)更好 - 对于大型TLS部署的问题
- 可以修改为(
hostname,port,addr_type(ip_addr)) - 类似于[CORS and RFC1918](https://wicg.github.io/cors rfc1918/)
- 可以修改为(
- 现在是(
禁用带外通信时的TLS session resumption
配置
libcurl: CURLOPT_SSL_SESSIONID_CACHE=false
firefox: security.ssl.disable_session_identifiers=true
Tor browser: disabled by default
Java, Nodejs, Chrome, others: no option
- WEB APP
- web app不能禁止TLS session resumption
- 关注类似 webhooks, apple pay 的应用
- 对出站请求设置代理进行监控(比如smokescreen工具)
- 阻止未进行身份校验的内部TCP内容运行,特别是带换行符的内容
其实从其他方面也能防御,比如杜绝DNS重绑定,第一次解析后直接使用解析返回的ip替换域名访问url
总结
这个议题技术覆盖比较全面,攻击手法也很新颖,作者在介绍的过程中也提出了对安全与性能之间平衡的思考:https本来是防止中间人攻击提出的安全协议,却因为对此的优化算法使其变得易受攻击。安全开销与时间开销如何取舍?
无论是议题本身还是作者挖掘漏洞的方法,思考问题的全面性,都有很多值得我们学习的地方。
作者最后也提出了一些总结:
- 过去可能不太重视https在SSRF中的应用,这个攻击方式证明TLS对SSRF来说是有用的
- 随时关注了解最新的技术手段对于打破常规是很有帮助的
- 我们需要认真考虑TLS会话重用的利弊

参考
https://github.com/jmdx/TLS-poison
https://portswigger.net/daily-swig/when-tls-hacks-you-security-friend-becomes-a-foe
https://securityboulevard.com/2020/08/def-con-safe-mode-joshua-madduxs-when-tls-hacks-you/
https://defcon.org/html/defcon-safemode/dc-safemode-speakers.html#Maddux
https://xz.aliyun.com/t/7495
https://wiki.jikexueyuan.com/project/openresty/ssl/session_resumption.html
https://mp.weixin.qq.com/s/GT3Wlu_2-Ycf_nhWz_z9Vw
https://mp.weixin.qq.com/s/-NABL-xz1Allxr6SKGiYcQ
利用DNS缓存和TLS协议将受限SSRF变为通用SSRF的更多相关文章
- [转载] TLS协议分析 与 现代加密通信协议设计
https://blog.helong.info/blog/2015/09/06/tls-protocol-analysis-and-crypto-protocol-design/?from=time ...
- TLS协议分析
TLS协议分析 本文目标: 学习鉴赏TLS协议的设计,透彻理解原理和重点细节 跟进一下密码学应用领域的历史和进展 整理现代加密通信协议设计的一般思路 本文有门槛,读者需要对现代密码学有清晰而系统的理解 ...
- 实验六 TLS协议报文解析
一.实验目的 1.访问一个https://....的网站,捕TLS包并分析报文序列. 2.分析连接建立的完整过程,如:TCP三次握手.SSL安全连接,使用TLS协议连接.协商过程,加密传送的状态.TC ...
- HTTPS协议,TLS协议
一.HTTPS 协议 HTTPS协议其实就是HTTP over TSL,TSL(Transport Layer Security) 传输层安全协议是https协议的核心. TSL可以理解为SSL (S ...
- HTTPS协议、TLS协议、证书认证过程解析
一.HTTPS 协议 HTTPS协议其实就是HTTP over TSL,TSL(Transport Layer Security) 传输层安全协议是https协议的核心. TSL可以理解为SSL (S ...
- sqlmap利用DNS进行oob(out of band)注入(转)
0x00 起因 实际案子的时候遇到了一个注入,过狗可以使用sqlmap,但是是基于时间的注入和限制频率需要使用--delay参数,本来就是延时再加上--delay等的心力憔悴.所有有了下面介绍使用 ...
- DNS 缓存投毒
原文:[DNS Cache Poisoning]( https://medium.com/iocscan/dns-cache-poisoning-bea939b5afaf) 译者:neal1991 w ...
- 在阿里云托管kubernetes上利用 cert-manager 自动签发 TLS 证书[无坑版]
前言 排错的过程是痛苦的也是有趣的. 运维乃至IT,排错能力是拉开人与人之间的重要差距. 本篇会记录我的排错之旅. 由来 现如今我司所有业务都运行在阿里云托管kubernetes环境上,因为前端需要对 ...
- SSL/TLS协议详解(下)——TLS握手协议
本文转载自SSL/TLS协议详解(下)--TLS握手协议 导语 在博客系列的第2部分中,对证书颁发机构进行了深入的讨论.在这篇文章中,将会探索整个SSL/TLS握手过程,在此之前,先简述下最后这块内容 ...
随机推荐
- whistle浏览器抓包(以火狐浏览器为例)
环境:whistle:1.14.6 whistle浏览器抓包 以火狐浏览器为例 1.启动whistle 使用w2 start启动whistle. 退出cmd后,whistle自动关闭了,所以每次使用w ...
- vue项目中的element-ui地区级联选择器加详细地址push到对象中不显示的问题
想要实现级联选择器el-cascader和输入框el-input共同组成的详细地址,添加数据时弹出el-drawer嵌套el-form弹窗,然后在el-form添加数据提交后push到el-table ...
- shiro的使用与JWT整合
一.shiro入门 两大框架对比:安全框架Shiro和SpringSecurity的比较 了解shiro 什么是Shiro Apache Shiro是一个Java的安全(权限)框架.| Shiro可以 ...
- Redux使用指南
Redux使用指南 00-简介 本文主要是用来记录Redux结合React的使用过程,帮助大家在使用Redux的时候,能够更好的理解Redux,从而更好地使用它 01-为什么需要Redux JavaS ...
- Java实现四大基本排序算法和二分查找
Java 基本排序算法 二分查找法 二分查找也称为折半查找,是指当每次查询时,将数据分为前后两部分,再用中值和待搜索的值进行比较,如果搜索的值大于中值,则使用同样的方式(二分法)向后搜索,反之则向前搜 ...
- BootstrapBlazor 模板安装
原文地址:https://www.cnblogs.com/ysmc/p/15400270.html Bootstrap Blazor Project Template 为方便大家的使用,Bootstr ...
- C++类结构体与json相互转换
1. 背景与需求 之前写C#的时候,解析json字符串一般使用的是开源的类库Newtonsoft.Json,方法十分简洁,比如: class Project { public string Input ...
- 找出某名珍贵药材的生长区域(ArcPy实现)
一.背景 某种珍贵药材生长于山区,通过研究了解到这种药材生长具有严格的生长条件.为了能更好地保护该药材的生长环境,现在需要使用GIS空间分析方法,将药材适合生长区域找出来,以便为该物种保护提供依据. ...
- 安装早期老版本 Visual Studio
安装早期老版本 Visual Studio https://visualstudio.microsoft.com/zh-hans/vs/older-downloads/
- T-SQL——关于XML类型
目录 0. 将结果集转化为XML格式 1. 列值拼接为字符串 2. 字符串转换为列值 3. 一些说明 参考 志铭-2021年10月23日 10:43:21 0. 将结果集转化为XML格式 测试数据 I ...