本文首发于先知社区

前言

这是今年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. c++ 的学习 第3集-默认参数

    1.默认参数的意思就是  予以形参默认值 2. C++允许函数设置默认参数,在调用时可以根据情况省略实参.规则如下: 默认参数只能按照右到左的顺序 如果函数同时有声明.实现,默认参数只能放在函数声 ...

  2. Django整理(四) - URL配置

    1. URL配置 一.需求 1. 需求:在浏览器访问URL地址 http://127.0.0.1:8000/users/index 时,显示hello django信息 2. 实现 i. 需要编写一个 ...

  3. Centos7最小安装后快速初始化脚本

    功能说明 服务器通常使用最小化安装操作系统,使用该脚本可快速初始化一些基本配置,包括以下: 1.ssh修改默认端口 2.ssh禁止root登陆 3.selinux及firewalld禁用 4.hist ...

  4. bzoj3073Journeys(线段树优化最短路)

    这里还是一道涉及到区间连边的问题. 如果暴力去做,那么就会爆炸 那么这时候就需要线段树来优化了. 因为是双向边 所以需要两颗线段树来分别对应入边和出边 QwQ然后做就好了咯 不过需要注意的是,这个边数 ...

  5. 创建线程的4种方法 and 线程的生命周期

    线程的启动和运行 方法一:使用start()方法:用来启动一个线程,当调用start方法后,JVM会开启一个新线程执行用户定义的线程代码逻辑. 方法二:使用run()方法:作为线程代码逻辑的入口方法. ...

  6. GoLang设计模式10 - 中介者模式

    中介者模式是一种行为型设计模式.在中介者模式中创建了一个中介对象来负责不同类间的通信.因为这些类不需要直接交互,所以也就能避免它们之间的直接依赖,实现解耦的效果. 中介者模式的一个典型案例是老式小火车 ...

  7. Vuls 漏洞扫描工具部署及效果展示

    Vuls 漏洞扫描工具部署及效果展示 介绍 Vuls根据NVD,OVAL等数据对主流Linux系统进行扫描,并具有完善的报告. 支持系统 Distribution Release Alpine 3.3 ...

  8. ToString()字符串转换你用正确了吗?

    前言 在开发中,ToString()这个方法太方便了,以致于误解大家转换时都是直接Object.ToString()直接转换, 其实不然, 一般都是转之前先判断是否为null后再进行转换,否则会直接报 ...

  9. GIS应用|快速开发REST数据服务

    随着计算机的快速发展,GIS已经在各大领域得到应用,和我们的生活息息相关, 但是基于GIS几大厂商搭建服务,都会有一定的门槛,尤其是需要server,成本高,难度大,这里介绍一种在线GIS云平台,帮你 ...

  10. Java正则中"\\\\"表示普通反斜杠

    Java中"\"用于转义字符,"\\"表示普通无转义功能的反斜杠. 如果将字符串当做正则表达式来解析,那么"\\"也有了特殊意义,它与其后的 ...