本文首发于先知社区

前言

这是今年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

原理

其形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,但又没有对目标地址做严格过滤与限制,导致攻击者可以传入任意的地址来让后端服务器对其发起请求,并返回对该目标地址请求的数据。

危害

  1. 内网、本地端口扫描,获取开放端口信息
  2. 主机信息收集,web应用指纹识别,获取服务banner信息
  3. 根据识别出的应用针对性的发送payload攻击,例如struts2
  4. 攻击内网和本地的应用程序及服务。
  5. 穿越防火墙
  6. 利用file协议读取本地文件,比如file:///etc/passwd

常用协议

协议名称 简介
Gopher协议 攻击内部应用的主力军
Dict协议 端口探测,版本信息收集
ftp协议 探测是否存在ftp
http协议 探测是否存在ssrf
file协议 读取本地文件



注:jdk1.7后java不再支持gopher

防御手段

  1. 禁止跳转
  2. 过滤返回信息
  3. 禁用不需要的协议
  4. 设置URL白名单或者限制内网IP
  5. 限制请求的端口为http常用的端口
  6. 统一错误信息

在请求资源前先访问DNS服务器判断是否为内网IP

DNS rebinding

针对上图防御手段的一种绕过

TTL

TTL是英语Time-To-Live的简称,意思为一条域名解析记录在DNS服务器中的存留时间。当各地的DNS服务器接受到解析请求时,就会向域名指定的NS服务器发出解析请求从而获得解析记录;在获得这个记录之后,记录会在DNS服务器中保存一段时间,这段时间内如果再接到这个域名的解析请求,DNS服务器将不再向NS服务器发出请求,而是直接返回刚才获得的记录;而这个记录在DNS服务器上保留的时间,就是TTL值。

它表示DNS记录在DNS服务器上缓存的时间,数值越小,修改记录各地生效的时间越快。

DNS解析

  1. DNS区域是一个层次结构的空间, 根域名服务器->子域名服务器->二代子域名服务器
  2. DNS查询方式: 递归和迭代
递归

迭代

解析流程

  1. 检查浏览器缓存中是否缓存过该域名对应的IP地址
  2. 如果在浏览器缓存中没有找到IP,那么将继续查找本机系统(如HOSTS文件)是否缓存过IP
  3. 向本地域名解析服务系统(路由器或者内网DNS服务)发起域名解析的请求
  4. 开始递归查询运营商dns -> 根域名服务器 -> 顶级域名(gTLD)服务器 -> 我们设置NS域名服务器。(这一步很重要,我们可以递归向下设置TTL的值)
  5. NS返回IP地址给本地服务器,本地服务器缓存解析结果(TTL)
  6. 解析结果返回给用户,建立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 握手需要两次

  1. Client 发送 ClientHello;Server 回复 ServerHello
  2. Client 回复最终确定的 Key,Finished;Server 回复 Finished
  3. 握手完毕,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。

实际漏洞案例

  1. Youtrack — CVE-2019-12852JetBrains YouTrack 服务的SSRF
  2. 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等易受影响的浏览器中浏览电子邮件。受害者有一定安全意识,不会下载邮件中的附件。

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

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

然后弹计算器

整个攻击流程如图所示

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

未来工作

作者在讲述未来工作时提出了要建设更好的测试基础设施

  • Alternating DNS Server:实现DNS重绑定
  • Custom TLS:提供https服务,并传输payload
  • Just netcat:监控受害者与Custom TLS的交互流量,判断攻击状态

github项目:https://github.com/jmdx/TLS-poison

防御手段

作者提出了三种防御手段

  1. 改变缓存的key值

    • 现在是(hostname,port),修改为(hostname,port,ip_addr)更好
    • 对于大型TLS部署的问题
  2. 禁用带外通信时的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
  1. 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的更多相关文章

  1. [转载] TLS协议分析 与 现代加密通信协议设计

    https://blog.helong.info/blog/2015/09/06/tls-protocol-analysis-and-crypto-protocol-design/?from=time ...

  2. TLS协议分析

    TLS协议分析 本文目标: 学习鉴赏TLS协议的设计,透彻理解原理和重点细节 跟进一下密码学应用领域的历史和进展 整理现代加密通信协议设计的一般思路 本文有门槛,读者需要对现代密码学有清晰而系统的理解 ...

  3. 实验六 TLS协议报文解析

    一.实验目的 1.访问一个https://....的网站,捕TLS包并分析报文序列. 2.分析连接建立的完整过程,如:TCP三次握手.SSL安全连接,使用TLS协议连接.协商过程,加密传送的状态.TC ...

  4. HTTPS协议,TLS协议

    一.HTTPS 协议 HTTPS协议其实就是HTTP over TSL,TSL(Transport Layer Security) 传输层安全协议是https协议的核心. TSL可以理解为SSL (S ...

  5. HTTPS协议、TLS协议、证书认证过程解析

    一.HTTPS 协议 HTTPS协议其实就是HTTP over TSL,TSL(Transport Layer Security) 传输层安全协议是https协议的核心. TSL可以理解为SSL (S ...

  6. sqlmap利用DNS进行oob(out of band)注入(转)

      0x00 起因 实际案子的时候遇到了一个注入,过狗可以使用sqlmap,但是是基于时间的注入和限制频率需要使用--delay参数,本来就是延时再加上--delay等的心力憔悴.所有有了下面介绍使用 ...

  7. DNS 缓存投毒

    原文:[DNS Cache Poisoning]( https://medium.com/iocscan/dns-cache-poisoning-bea939b5afaf) 译者:neal1991 w ...

  8. 在阿里云托管kubernetes上利用 cert-manager 自动签发 TLS 证书[无坑版]

    前言 排错的过程是痛苦的也是有趣的. 运维乃至IT,排错能力是拉开人与人之间的重要差距. 本篇会记录我的排错之旅. 由来 现如今我司所有业务都运行在阿里云托管kubernetes环境上,因为前端需要对 ...

  9. SSL/TLS协议详解(下)——TLS握手协议

    本文转载自SSL/TLS协议详解(下)--TLS握手协议 导语 在博客系列的第2部分中,对证书颁发机构进行了深入的讨论.在这篇文章中,将会探索整个SSL/TLS握手过程,在此之前,先简述下最后这块内容 ...

随机推荐

  1. LR录制附件上传后,回放报错

    使用LR录制附件上传后,点击回放,发现报错:没有找到上传的文件 Could not obtain information about submitted file "C:\Users\Adm ...

  2. 定要过python二级 选择题第四套

    1. 2. 3. 4. 5. 6. python用于人工智能 7. 8. 9. 10. 11. 12. 13. 14. 15. 16.

  3. Matrix Analysis and Application

    Chap 1: Linear Equations and Matrix Linear equations Gaussian elimination Pivot; Triangularize; Back ...

  4. 阿里:MySQL数据库规范

    阿里:MySQL数据库规范 简介:基于阿里数据库设计规范扩展而来 设计规范 1.[推荐]字段允许适当冗余,以提高查询性能,但必须考虑数据一致.冗余字段应遵循: 不是频繁修改的字段. 不是 varcha ...

  5. 解决 Delegate IDE build/run actions to Maven 编译两次的问题

    起因:我的电脑炸了,吸取教训,以后重要的东西千万不要存在C盘,特别是我们 IT 行业的,代码和文档都是一点一点积累的经验.突然没了,总感觉少了点啥,平时我的代码都是放在D盘,但是很多文档放在C盘,导致 ...

  6. Redis5种常用数据类型的使用以及内部编码

    String 字符串类型是redis的最基本类型,首先无论值是什么数据类型,其键都是字符串,且其他数据类型的数据结构都是在字符串的基础上搭建的,相信读者能够体会到字符串在redis的地位是有多么的重要 ...

  7. gRPC,爆赞

    原文链接: gRPC,爆赞 gRPC 这项技术真是太棒了,接口约束严格,性能还高,在 k8s 和很多微服务框架中都有应用. 作为一名程序员,学就对了. 之前用 Python 写过一些 gRPC 服务, ...

  8. css3新增属性-background背景

    css3新增属性 边框属性 背景属性 文字属性 颜色属性 背景属性 属性 说明 background-image 添加背景图片 background-size 指定背景图像的大小 background ...

  9. L1-023 输出GPLT (20 分) java题解 GPLT天梯赛防坑技巧

    上题目先 给定一个长度不超过10000的.仅由英文字母构成的字符串.请将字符重新调整顺序,按GPLTGPLT....这样的顺序输出,并忽略其它字符.当然,四种字符(不区分大小写)的个数不一定是一样多的 ...

  10. 笨方法学python中执行argv提示ValueError: not enough values to unpack (expected 4, got 1)

    解决方法:选择Terminal中输入执行ex13.py 1 2 3 执行结果如下图