DH密钥交换在实践中的安全问题

本文提出了logjam,CVE-2015-4000,告诫我们不要兼容因为安全问题而被抛弃的旧特性。
在这里插入图片描述
主要内容来自论文和网络,本文为内容摘要和背景知识(当然,也算是翻译)。
forward secrecy 前向安全性:长期使用的主密钥泄漏不会导致过去的会话密钥泄漏
攻击逻辑主要分为两步,第一步是利用CVE2015 logjam将密码降级到512位;第二步是使用NFS,利用预计算的结果对DH进行快速求解。
此外,本文还提出结论,768位可以被academic attacker破解,1024位可以被state

1.DH密钥交换

1.1 原根

如果a是素数p的一个原根,那么数值 a mod p,a2 mod p,…,ap-1 mod p 是各不相同的整数,并且以某种排列方式组成了从1到p-1的所有整数。对于一个整数b和素数p的一个原根a,可以找到惟一的指数i,使得 b = ai mod p 其中0 ≤ i ≤ (p-1)。

1.2 算法描述

1,有两个全局公开的参数,一个素数q和一个整数a,a是q的一个原根.
2,用户A和用户B分别选择小于q的秘密随机数XA,XB作为私钥
3,用户A和用户B分别计算公钥YA=a ^ XA mod q, YB=b ^ XB mod q,并告知对方
4,用户A和用户B分别计算YB ^XA mod q 和 YA ^ XB mod q,作为共享密钥

1.3 最有效的求解方法

对于素数域实现的DH算法(现在ECDHE,也就是椭圆曲线实现的DH密钥交换更加流行了,但不是本文讨论的内容),最有效的求解方法是number field sieve,NFS,也就是下图描述的算法。
如果攻击者针对p进行预计算,会显著降低问题求解的难度。可以看出,前三步只需要p,y和g是预计算之后才加入的。
在这里插入图片描述
上图即NFS算法,文章对polynomial selection, sieving, linear algebra, descent都做了讲解。
NFS算法有很多参数,通过合理的设置与取舍,能让求解最快。比如,sieving多花些时间,能减少linear algebra的工作量;precomputation多花些时间,就能减少descent的工作量。

2.DH与TLS

DH是TLS支持的密钥交换方法之一。大约有三分之二的常用https网站支持,一般使用1024位的p。但也有部分常用站点(百分之8.4)支持上古版本export-grade(512位的p)。
这百分之8.4中,还有百分之92.3使用了两个常用的p(原文table 1)。文章的攻击几乎可以搞定这百分之92.3。
这里的trick在于,服务器其实知道dhe_export已经没有多少client在用,只是为了兼容支持了dhe_export,只要client不用dhe_export,就是安全的。服务器只管兼容,安全责任甩给了client,这是不恰当的。

在这里插入图片描述
图中,cr和sr是随机数,certs是服务器证书,后面是用签名密钥签名后的(cr,sr,512位的p,g,gb)。

攻击的难点是,
中间人能近乎实时计算出离散对数(有的服务器会复用gb,与服务器实现和用户配置有关);
中间人能延后握手的完成,以便为计算提供时间(跟不同客户端的实现有关)。

即使来不及计算,最终因为握手超时而被迫断开,考虑到TLS false start(客户端在握手结束之前就发送应用数据,此举是为了减少延迟),中间人至少可以截获这一段报文。而这一段报文往往会有密码和cookie等信息(因为是连接刚建立发送的第一批信息)。

攻击的防范是,
客户端设置更大的最小长度(比如要求严格大于512);
服务端在Figure 2中第三行的签名信息中加入“加密套件”字段。

除了TLS,还应关切IKE和SSH。DH的应用很广泛。

3.作者建议

切换到椭圆曲线DH,即ECDH
客户端提至1024及以上,服务器使用2048,禁用DHE_EXPORT
如有可能,使用新的群

4.我对漏洞利用可行性的调研

第一种思路,是看客户端对DH的位数是否有要求
https://firefox-source-docs.mozilla.org/contributing/directory_structure.html 查看firefox源码目录结构
https://searchfox.org/mozilla-central/source firefox源码
https://gitee.com/mirrors/chromium gitee上chromium的镜像
https://opensource.com/article/19/7/open-source-browsers 其它开源浏览器
git clone https://github.com/curl/curl.git curl源码

第二种思路,是模仿作者对https网站进行扫描(通过自己写的客户端),以此判断服务端是否支持DHE_EXPORT。
curl有一个功能,可以Store the HTTP headers in a separate file (headers.txt in the example)

curl --dump-header headers.txt curl.se

通过读curl的readme,发现了一些有趣的功能,比如可以提交表单;
可以指定referer字段;可以伪装成某个浏览器;可以伪造cookie;可以自定义包的header(以及指定if-modified-since的时间);也可以发起telnet请求。
为了访问一些老网站,curl也可以显式指定旧版,如ssl3(参数为-3)、ssl2(参数为-2)和tls1(参数为-1)。

 curl -2 https://secure.site.com/

https://zhuanlan.zhihu.com/p/142157217 对模板包进行十六进制修改,伪造数据包的通用方法
这篇文章提供了一些启发,写客户端的时候可能需要通过抓包来获取模板,基于这个模板修改请求的域名。
python提供pycurl库。
curl的时候要注意,显式指定https协议,否则是http流量。

第三种思路,是看TLS1.3(彼时2015年还未推出)是否已经从根本上解决了logjam,如果解决了,TLS1.3的普及程度如何?
https://datatracker.ietf.org/doc/rfc8446/ ietf对tls1.3的文档,
https://www.rfc-editor.org/rfc/pdfrfc/rfc7919.txt.pdf 从RFC7919可以看出tls1.3标准下,基于有限域的DH最小位数是2048,因此logjam攻击无法进行。
下图援引自:http://blog.itpub.net/31559359/viewspace-2286705/
在这里插入图片描述
在TLS 1.2中,g和p的值由双方自己生成。TLS 1.3则定义了几组g、p对,双方只需要选择想要使用的DH组即可。使用确定的参数值保证了DH密钥协商过程具有足够的安全性。(https://blog.csdn.net/andylau00j/article/details/79269499)
在https://www.ssllabs.com可以检查客户端和服务器对tls版本的支持(包括了上述的思路一和思路二),截图示例(某网站服务器支持的所有加密套件):
在这里插入图片描述
从这个网站上看出,即便是安全性评级A+的网站,也不会只支持tls1.3,一般是同时支持tls1.3和tls1.2(或者只支持tls1.2)。所以logjam应该还有利用空间。当然,仅根据此网站的A+评级标准就得出结论,这并不严谨。还是需要通过思路一和思路二,做数据统计后再得出结论。

第四种思路,就是直接调用现成的漏洞检测/漏洞扫描。实际上,上面提到的SSLlab,就提供api。
以下代码可以批量扫描域名,查看tls版本支持和是否有logjam漏洞。
域名列表文件名为domainlist,可以花钱去alexa上找,也可以到http://stuffgate.com/stuff/website上找。

import requests
import time
import sys
import logging

API = 'https://api.ssllabs.com/api/v3/'

def requestAPI(path, payload={}):
    '''This is a helper method that takes the path to the relevant
        API call and the user-defined payload and requests the
        data/server test from Qualys SSL Labs.

        Returns JSON formatted data'''

    url = API + path

    try:
        response = requests.get(url, params=payload)
    except requests.exception.RequestException:
        logging.exception('Request failed.')
        sys.exit(1)

    data = response.json()
    return data


def newScan(host, publish='off', startNew='on', all='done', ignoreMismatch='on'):
    path = 'analyze'
    payload = {
                'host': host,
                'publish': publish,
                'startNew': startNew,
                'all': all,
                'ignoreMismatch': ignoreMismatch
              }
    results = requestAPI(path, payload)

    payload.pop('startNew')

    while results['status'] != 'READY' and results['status'] != 'ERROR':
        time.sleep(30)
        results = requestAPI(path, payload)

    return results

with open('domainlist','r') as f:
	for line in f:
		results=newScan(line)
		print(line,results['endpoints'][0]['details']['protocols'],results['endpoints'][0]['details']['logjam'])

运行效果如下图:
在这里插入图片描述
布尔值就表示是否具有logjam漏洞。
这个方法唯一的问题是,api的功能太多,会做很多很多检测,而我只用了返回结果中很小一部分,这导致效率低下。一个网站大约需要三分钟才能检测完毕,对于同域名多ip的情况会更慢。如果像论文作者一样对前1000000进行了检测,那就需要六年才能检测完毕。不过这个api非常强大,在其它研究中肯定也能提供方便。如果想获取其它信息,比如加密套件信息,可以先clone https://github.com/ssllabs/ssllabs-scan/,试用一下,对返回的json进行格式化(比如oschina的在线格式化工具),看看自己想要的字段在什么位置即可。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值