当前位置:首页 > 黑客技术 > 正文内容

截获TLS密钥——Windows Schannel - FreeBuf网络安全行业门户

访客4年前 (2021-04-15)黑客技术742

简介

这篇文章是研究在终端上劫持进程来截获TLS密钥以用于解密的方式,主要是使用SChannel组件的Windows应用的TLS流量,如IIS,RDP,IE以及旧版的Edge,Outlook,Powershell及其他,不包括使用OpenSSL或NNS(基本上除了IE和旧版Edge的所有浏览器都在使用)。

SChannel

SChannel也被称为Secure Channel 23,是一个windows子系统,当windows应用程序想要做任何与TLS相关的事情时,比如与远程服务器建立一个加密会话,或接受来自客户端的TLS连接,就会使用Schannel,

从体系来看,SChannel实现了Security Support Provider Interface (SSPI)接口,是微软提供的SSP包之一。SSP包还包括CredSSP、Negotiate、NTLM、Kerberos和Digest24等等。

SChannel使用示例:

HTTPS连接

由IE,Edge,powershell的发起的

由IIS web server收到的

RDP连接

客户端的mstsc.exe

服务器上的终端服务(svchost.exe中的termsrv.dll)

到LDAP服务器的动态目录的LDAPS连接

当服务器HTTPS lisener开启时的部分WinRM(PS remoting)连接,PS remoting还支持使用TLS客户端证书的SSL authentication,启用时也通过schannel实现。

之前提到过其他浏览器,如Firefox和谷歌Chrome使用其他库来处理TLS,即NSS和OpenSSL,因此它们的流量超出了本文的范围。但是NSS和OpenSSL都是开源的,都有文档记录了导出secrets的方法;对于Firefox和Chrome,密钥导出是内置的,可以通过使用环境变量激活。

TLS1.2流量解密及临时密钥

这项研究并不依赖协议的漏洞或脆弱性,而是基于完全控制建立或接受连接的应用程序或操作系统的情况下,我们能够检索出所使用的任何密钥和secrets,来获得解密TLS流量所需的信息。

关于TLS的内部工作原理1的第2.2节已经总结的很好了。因此本文不会非常详细地进行介绍。快速过一下TLS1.2连接及加密中的关键概念:

临时密钥

每当创建一个TLS会话时,都会有许多密钥与此连接相关联。一些密钥可能用于加密,另一些用于消息验证。对于不同的方向(客户端到服务器和服务器到客户端)有不同的密钥。与服务器TLS证书密钥等长期密钥相对,这些密钥称为临时密钥以强调它们是短期的。

完全正向保密

所有密码套件可以根据是否支持完全正向保密(Perfect Forward Secrecy,PFS)25来进行分类。当使用非PFS密码套件时,任何加密连接都可以使用其捕获流量和服务器TLS私钥对进行解密。相反,对于PFS密码套件,你需要相关会话的临时密钥才能解密它。

主密钥 master key

形成临时密钥的过程有多个步骤。在TLS1.2中,开始时服务器和客户端一起生产一些关键素材,称之为Pre-Master Secret,再扩充到Master Secret,然后依次生成一组用于加密和认证的密钥和IV——write keysMAC keys。MAC密钥只使用或非AEAD密码。

TLS session tickets

多个独立的TLS连接可以属于同一个TLS会话,因此无需每次都计算密钥。以前的方法是使用session ID,服务器向客户机发送session ID,然后由客户机在后续连接上使用。服务器应该存储与会话关联的密钥,因此此方法需要占用服务器上大量内存。因此后来提出了TLS session tickets(rfc5077),服务器向客户端发送一个加密的会话状态,使用只有服务器知道的密钥进行加密,然后客户端在下一个连接上发送回来,并由服务器解密。所有这意味着,尽管临时密钥本应在连接后销毁,但实际上它们可能在服务器和客户端的内存中都持久存在。有关TLS session tickets的安全性影响,请参见12

SSL keylog文件

为了解密一个TLS流量dump,需要一种方法来
对于TLS 1.2,提供此信息的标准方法是通过由OpenSSL和NSS23共同支持的ssl keylog文件,keylog文件的每一行由常量标签字符串、标识TLS会话的值和secrets的值组成。作为参考,可以在4中找到Wireshark的keylog解析例程

获取每个会话使用的secrets

将这些密钥和会话关联起来

client random 和 session id

TLS1.2的keylog文件支持会话的pre-mastermaster secrets。会话可以通过client random(在TLS握手期间由客户端发送的随机非加密值)或session id(由服务器发送的非加密值)来标识。TLS1.2的keylog文件的示例如下:

TLS1.3流量解密

上面提到的关于TLS1.2的许多内容也适用于TLS1.3。然而,secrets产生的方式有许多变化。

对于TLS1.2,我们有以下密钥生成方案:

在TLS1.2中,keylog文件格式要求你提供步骤(1)或步骤(2)的secrets。

对于TLS1.3,该方案已发展成以下版本(参见RFC844634的第93页):

TLS1.3 keylog文件还要求你提供步骤(2)的secrets。与TLS 1.2不同,每个TLS会话需要多个行,每一行提供一个特定的secrets,并通过client random将其绑定到一个TLS会话。你至少需要四个secrets:
* 客户端和服务器握手secret
* 客户端和服务器通信secret

一个keylog文件示例:

密钥隔离

Windows schannel API具有密钥隔离的概念(参见5),通过将各种机密数据存储在一个集中隔离的地方,从而使其更难以泄露。假设我们有一个进程(例如,terminal services client, mstsc)希望建立一个TLS连接,然而实际的TLS握手将在另一个进程中执行(即lsass.exe),握手期间生成的secrets(即TLS1.2的pre-master和master keys)永远不会离开lsass.exe的内存,也永远不会接触mstsc.exe。所有这些对应用程序来说都是透明的,它只使用来自schannel.dll的函数。

应用程序端的schannel .dll在幕后(参见1中的图2.6和2.7)使用ALPC连接到lsass端的schannel .dll。ALPC调用由加载到lsass.exe中的schannel .dll副本处理,然后使用一组加密API (CNG,6,主要在和中实现)来执行各种密钥相关的任务。

这种操作模式不是SChannel特有的,而是适用于所有实施SSPI的安全提供程序。当你调用37时,这个调用在LSA端的回调中处理,然后结果被传递到它在应用端上的。因此不需要在内存中保存凭证,windows应用程序也能够使用NTLM或Kerberos身份验证。

对我们来说,这意味着lsass .exe是个好地方,在这里可以提取任何启用SChannel的应用程序所使用的所有临时TLS密钥。我们需要hook密钥创建/操作路径,或者找到一种方法能够可靠地在内存中找到它们。我们还需要以某种方式将它们绑定到一个TLS会话来利用获得的密钥,最好采用Wireshark支持的方式(即session id或client random)。

目标

我们的目标是在完全控制连接的客户端或服务端上的应用程序和/或操作系统时,使用Wireshark解密SChannel TLS流量。与Jacob Kambic的论文1的问题陈述(从内存dump中提取密钥)相比,这种方法更为灵活,因为我们不仅可以使用内存扫描,还可以使用dbg和函数hook。其他关键要求如下:

不依赖会话恢复和其他机制,来防止密钥在连接关闭时被清除出内存;

尽可能不依赖于硬编码的偏移量,或其他特定于Windows和/或库的特定版本的东西;

可以从连接的客户端和服务端两端提取密钥;

在不需要管理员权限的情况下提取密钥的区域,即不触及lsass.exe的内存。类似于10中提出的方法。

获取TLS1.2密钥

对于TLS1.2,获取client random和密钥的配对,生成一个keylog行,就可以放进wireshark解密。

正常(非恢复)会话

SslGenerateMasterKey

在正常的(非恢复的)TLS1.2会话中调用的函数

参考SslGenerateMasterKey13官方文档:

如上所示,第四个参数被注释为_Out_(一种“header注释”类型14),意味着这个指针在函数调用结束后将被密钥地址填充。

获取master key

跟入这个*phMasterkey指针指向的地址会进入结构

在这个结构偏移0x04处包含一个非常重要的magic value(参见1第77页),在偏移0x10(x64情况,在x86情况下为0x0C)处包含另一个magic value为结构的指针(参见1第64-68页),实验环境内存(x64)如下

跟入pNcryptSslKey指针指向的地址000002a8`bcd81e70,进入结构,下称结构

参见1的第68页,master key本身位于SSL5结构偏移0x1C(x64,x86为0x14),大小为48 (0x30)字节:

获取client random

再回到13,可以看到关于pParameterList参数的注释:

客户端和服务端的random正是我们需要绑定密钥和会话的东西。和结构被记录在.NET框架的MS参考源文档,参阅17

跟入pParamterList指针导,在偏移0x04获得的数量,在偏移量0x08获得指向NCryptBuffer结构数组的指针:

跟入pBuffers指针

在pBuffers结构数组偏移0x04处是该缓冲区的数据类型:

BufferType=0x14=20时,为NCRYPTBUFFER_SSL_CLIENT_RANDOM

BufferType=0x15=21时,为NCRYPTBUFFER_SSL_SERVER_RANDOM

当BufferType为0x14时,在偏移0x08处是指向client random数据的指针

使用RSA握手的正常(非恢复)会话

SslImportMasterKey

上面的方式适用于使用PFS密码(即Diffie-Hellman密钥交换)进行密钥交换的场景,也适用于使用非PFS加密套件(RSA)的Windows客户端。但是当windows服务器接受非PFS加密套件的连接时并不会调用函数,用于9中的也不例外。这是因为基于RSA密钥交换的master key并不是在Diffie - Hellman交换期间计算,而是由客户机生成并发送到服务器,由服务器的公钥来加密(这也是为什么它不是前向安全性——只要有服务器私钥任何时候都能解密)。

在这种情况下,另一个函数26包含了我们要找的东西。给定一个私钥,由客户端发送master key(通过服务器的公钥加密),master key将被解密并将其写入:

获取client random

与一样,第四个参数包含了指向client random的指针,此处不再赘述

获取 master key

第三个参数包含了指master key的指针

使用TLS Session Hash的会话

当试图从的args获得client_random时,有时会发现它并没有没有在中传递。

官方文档26说

列表至少将包含包含客户端和服务端提供的random的缓冲区,但在某些情况下,它只包含类型为22和25的缓冲区。

类型22是NCRYPTBUFFER_SSL_HIGHEST_VERSION,没啥用。

类型25是NCRYPTBUFFER_SSL_SESSION_HASH。即使用session hash的情况。

Session Hash

在派生master key的过程中使用 client/server random会引发一些特定类型的滥用,因此发展出了一个名为TLS Session HashExtended Master Secret的TLS扩展(RFC 762727)。当启用这个扩展时,计算master secret将包含握手消息内容的hash(ClientHello, ServerHello),而不只是client/server random。不过Wireshark不支持使用Session Hash将密钥绑定到会话。

当然,当我们试图从服务器连接中获取密钥时,我们会得到Session Hash而不是client random。如果远程服务器支持并愿意使用,这也可用于客户端连接。因此我们需要寻找一种新的方式,在不基于现有的或TLS session id的方式来提取client random。

SslHashHandshake

当我们深入挖掘28的文档时我们会发现:

ncrypt.dll/SslHashHandshake函数是生成SSL握手hash的三个函数之一,三个函数包括:

1. 函数被调用时获得一个hash句柄

2. 函数可以被hash句柄调用任意次数,以向hash中添加数据

3. SslComputeFinishedHash函数被hash句柄调用时获得散列数据摘要

在使用RFC 7627 session hash方式时,TLS1.3和TLS1.2会调用这个函数。

第一次调用是在client hello,用msg_type==1version==0x0303表示

需要注意的是,TLS1.2和TLS1.3的版本都是0x0303,这是TLS 1.3中的向后兼容性

重点关注第三个和第四个参数

pbInput [out]
包含需要被hash的数据的缓冲区地址

cbInput [in]
pbInput 缓冲区大小(bytes)

获取client random

首先跟踪ncrypt.dll/SslHashHandshake函数,跟进第3个参数pbInput指针获取待哈希数据的缓冲区地址(以下称buffer),跟进第4个参数cbInput获取缓冲区长度

跟入buffer地址,先读入1字节格式的msg_type从第4字节开始读入2字节的version,若msg_type为1并且version为0x0303时,从第6字节开始读入32字节的client random

获取TLS1.3密钥

根据RFC 844634第92-94页,在正常(非恢复)握手期间将生成以下内容:

两个 handshake traffic secrets

两个 application traffic secrets

一个 exporter master secret

一个 resumption master secret

每个traffic secrets用于生成一个write key和IV。一个SslExpandTrafficKeys调用后,会调用两次SslExpandWriteKey,分别计算客户端和服务端的secrets。这个调用会发生两次,一次用于 handshake traffic secrets,另一次用于 application traffic secrets。

从ghidra可以发现,和两个地方都调用了。

使用ghidra反编译,该函数包含一个调用,接着调用两次:

将生成的两个密钥放到了第4个和第5个参数中。之前提到过,该函数会调用两次,第一次生成handshake traffic secrets,第二次生成application traiffic secrets。

SslExpandTrafficKeys

如图,hook函数,跟入第4、第5个参数,两个都会进入一个结构(BDDD结构),与TLS1.2中一样,包含了指向密钥结构体地址的指针

跟入偏移0x10(x64,x86中为0x0C),进入了SSL3结构体,而不是TLS1.2中的TLS5结构体。见1第73页。

SSL3结构指向RUUU结构,而RUUU结构又指向MSKY结构,而MSKY结构最终指向我们要找的secrets。

偏移0x20(x64,x86下为0x1C)包含指向RUUU Bcrypt Key结构体的指针

阅读mimikatz源代码42可以找到RUUU结构

在偏移0x10(x64,x86为0x0C)出跟入指针进入到MKSY结构

在偏移0x10处包含密钥的长度,会根据密钥算法的不同而变化,在偏移0x18处包含我们需要的密钥。

第一调用产生的是HANDSHAKE_TRAFFIC_SECRET,第二次调用产生的是TRAFFIC_SECRET_0

SslExpandExporterMasterKey

对于TLS1.3,还要额外hook。虽然目前不确定wireshark目前是否需要使用它,但是openssl的keylog函数确实把它打印到keylog中了。

跟入第4、第5个参数进入BDDD结构,剩下的步骤和一样。

到最后获得EXPORT_SECRET

参考

[1] ?Jacob M. Kambic. Cunning With CNG: Soliciting Secrets from Schannel - Whitepaper from DEFCON 24, Slides from BlackHat USA 2016, “Extracting CNG TLS/SSL artifacts from LSASS memory” by Jacob M. Kambic

[2] ?MDN: NSS Key Log Format

[3] ?OpenSSL man page: SSL_CTX_set_keylog_callback

[4] ?Wireshark source code: SSLKEYLOG parsing, wireshark/packet-tls-utils.c

[5] ?Microsoft Docs: Key Storage and Retrieval

[6] ?Microsoft Docs: Cryptography API: Next Generation

[7] ?StackExchange: Decryping TLS packets between Windows 8 apps and Azure

[8] ?StackExchange: Is it possible to decrypt an SSL connection (short of bruteforcing)?

[9] ?Choi, H., & Lee, H. (2016) Extraction of TLS master secret key in windows. 2016 International Conference on Information and Communication Technology Convergence (ICTC). The paper is available on sci-hub if you search for its DOI.

[10] ?Microsoft TechNet Forums: Obtaining SSLKEYLOGFILE-like data from Edge et al (Schannel clients)

[11] ?GitHub - NytroRST/NetRipper: Smart traffic sniffing for penetration testers

[12] ?Filippo Valsorda: We need to talk about Session Tickets

[13] ?Microsoft Docs: SslGenerateMasterKey function (Sslprovider.h)

[14] ?Microsoft Docs: Header Annotations

[15] ?GitHub - droe/sslsplit: Transparent SSL/TLS interception

[16] ?Microsoft Docs: x64 software conventions

[17] ?MS .NET Reference Source: NCryptBuffer structure

[18] ?Windows SDK: NCRYPTBUFFER_SSL_* constans in ncrypt.h

[19] ?The blog of a gypsy engineer: How does TLS 1.3 protect against downgrade attacks?

[20] ?RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2

[21] ?Frida: A world-class dynamic instrumentation framework

[22] ?Microsoft Docs: x64 stack usage

[23] ?Microsoft Docs: Secure Channel

[24] ?Microsoft Docs: SSP Packages Provided by Microsoft

[25] ?Wikipedi@: Forward Secrecy (https://en.wikipedi@.org/wiki/Forward_secrecy把@改成a)

[26] ?Microsoft Docs: SslImportMasterKey function (Sslprovider.h)

[27] ?RFC 7627: Transport Layer Security (TLS) Session Hash and Extended Master Secret Extension

[28] ?Microsoft Docs: SslHashHandshake function (Sslprovider.h)

[30] ?Microsoft: News on TLS1.3 experimental support in Windows 10

[31] ?GitHub - microsoft/msquic: Testing instructions

[32] ?IETF draft: Using TLS to Secure QUIC

[33] ?GitHub - microsoft/msquic: SCHANNEL TLS Implementation for QUIC

[34] ?RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3

[35] ?GitHub - dotnet/runtime: TLS1.3 does not work on Windows · Issue #1720

[36] ?Naughter blog: SSLWrappers + TLS v1.3 support

[37] ?Microsoft Docs: InitializeSecurityContextW function (sspi.h)

[38] ?Windows SDK: SEC_TRAFFIC_SECRETS definition in ntifs.h

[39] ?Windows SDK: SECBUFFER_TRAFFIC_SECRETS definition in sspi.h

[40] ?RFC 5705: Keying Material Exporters for Transport Layer Security (TLS)

[41] ?Peter Wu: sslkeylog.c for keylogging apps that use OpenSSL

[42] ?GitHub - gentilkiwi/mimikatz: kuhl_m_crypto_extractor.c - a TODO line which mentions MSKY magic tag)

ssl10xE40x139SslpValidateProvHandlessl20x240x30SslpValidateHashHandlessl3??< none >ssl40x180x20SslpValidateKeyPairHandlessl50x480x50SslpValidateMasterKeyHandlessl60x180x20SslpValidateEphemeralHandlessl7??< none >

扫描二维码推送至手机访问。

版权声明:本文由黑客接单发布,如需转载请注明出处。

本文链接:http://therlest.com/105876.html

分享给朋友:

“截获TLS密钥——Windows Schannel - FreeBuf网络安全行业门户” 的相关文章

天猫双十一活动什么时候开始华流

以前提到双十一那都是光棍才过的节日,而现在双十一摇身一变成了全民购物狂欢节。在双十一期间以淘宝天猫为主的购物平台都会推出各种优惠活动以及满减折扣,可以算得上是全年最便宜的时候了。那么天猫双十一活动什么时候开始呢?下面就跟百思特小编来详细了解一下2020年天猫双十一开始时间吧!...

今天的汽油单价 - 今日燃油价格最新行情

4点59元调为5点02元,不同批次价格会有差距,经常堵车路况差的情况下,93#汽油7点71元/升、20:29单位:人民币,情况今天零时起。 92号汽油,0 号柴油每升上调0点04元。更别说不同地区了,92号汽油,上调0点37行情元;93号,最高限价,决定从。 92汽油官方价6点柴油价:6点:5点90...

接单的黑客_可以找黑客黑美团吗

有在网络安全范畴中,猜测网络违法和歹意软件发展趋势好像现已成为了各大网络安全公司的传统了。 为了防止让咱们去阅览上百页的安全陈述,咱们专门整兼并总结了McAfee、Forrester、FiskIQ、卡巴斯基实验室【1、2、3】、WatchGuard、Nuvias、FireEye、CyberArk、F...

奶牛多少钱一头2021年奶牛价格,2021年奶牛市场行情

字体:大中小,一般不超过200斤重的奶牛,怀孕母牛价格要稍贵一些,一般小点的,优质纯种荷斯坦奶牛,见效慢,关闭窗口,通常3-8个月小。 月的奶牛奶牛,花色、请问一头一头半成年奶牛多少钱!但我家不像你那个样子.荷斯坦奶牛、年龄大小。 来源、厘米,他的特点是投资巨大,理性回归2005-09-1511:5...

Webshell安全检测篇

0x00 依据流量的检测办法 1.概述 笔者一直在重视webshell的安全剖析,最近就这段时刻的心得体会和咱们做个共享。 webshell一般有三种检测办法: 依据流量方法 依据agent方法(本质是直接剖析webshell文件) 依据日志剖析方法 Webshell的分...

窗帘价格算法 「窗帘怎么算米数」

我们应该了解市面上大致的窗帘行情,是体现家居生活的美观程度,窗帘成品高度+30公分,的外观,布以1:1点5来计算。计算宽幅:窗宽*倍数*单价=金额注:倍数一般指1:2或1:2点5或1。 只要把这个尺寸报给商家他就会给窗帘你,第一位算的是平面,窗帘宽度轨道价格=轨道每米的价格*窗帘宽度另外-30这样可...

评论列表

断渊饮惑
2年前 (2022-07-02)

ows服务器接受非PFS加密套件的连接时并不会调用函数,用于9中的也不例外。这是因为基于RSA密钥交换的master key并不是在Diffie - Hellman交换期间计算,而是由客户机生成并发送到服务器,由服务器的公钥来加密(这也是为什么它不是前向安全

竹祭花桑
2年前 (2022-07-02)

t Docs: x64 stack usage[23] ?Microsoft Docs: Secure Channel[24] ?Microsoft Docs: SSP Packages Provided by M

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。