本文首发于先知社区

前言

这是今年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. Redis核心原理与实践--散列类型与字典结构实现原理

    Redis散列类型可以存储一组无序的键值对,它特别适用于存储一个对象数据. > HSET fruit name apple price 7.6 origin china 3 > HGET ...

  2. 使用AC自动机解决文章匹配多个候选词问题

    解决的问题 KMP算法用于单个字符串匹配,AC自动机用于文章中匹配多个候选词. 流程 第一步,先将候选词先建立前缀树. 第二步,以宽度优先遍历的方式把前缀树的每个节点设置fail指针, 头节点的fai ...

  3. 深度学习--GAN学习笔记

    生成模型 WGAN Blog GAN 推荐学习网站 生成模型 什么是生成模型? GMM: 用来做聚类,(非监督学习) NB(朴素贝叶斯):(监督学习,可以用来做垃圾邮件分类) Logistics 回归 ...

  4. IPtable防火墙概念介绍

    1.iptables安全优化 1.不配外网,做代理转发或者防火墙映射 2.并发过大,不建议开启防火墙 2.防火墙的工作流程: 按照配置规则的顺序自上而下,从前到后进行过滤 如果匹配上新规则,表明是阻止 ...

  5. bzoj1503 郁闷的出纳员(平衡树,思维)

    题目大意: 现在有n个操作和一个最低限度m \(I\)命令\(I\ k\)新建一个工资档案,初始工资为k. \(A\)命令$A\ k $把每位员工的工资加上k \(S\)命令$S\ k $把每位员工的 ...

  6. Java(19)接口知识及综合案例

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201629.html 博客主页:https://www.cnblogs.com/testero ...

  7. JavaScript 数组 常用方法(二)

    写在前面:续接上篇 JavaScript 数组 常用方法 数组常用方法第二弹来了: some && every 描述: every()与some()方法都是JS中数组的迭代方法. so ...

  8. 【UE4 C++】UGameplayStatics 源代码

    // Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" # ...

  9. [no code][scrum meeting] Beta 12

    $( "#cnblogs_post_body" ).catalog() 例会时间:5月27日11:30,主持者:乔玺华 一.工作汇报 人员 昨日完成任务 明日要完成的任务 乔玺华 ...

  10. 基于RequestBodyAdvice和ResponseBodyAdvice来实现spring中参数的加密和解密

    在日常开发中,有时候我们经常需要和第三方接口打交道,有时候是我们调用别人的第三方接口,有时候是别人在调用我们的第三方接口,那么为了调用接口的安全性,一般都会对传输的数据进行加密操作,如果每个接口都由我 ...