滥用User DPAPI进行攻击的操作指南
在之前我已经讨论过一些有关DPAPI(数据保护应用编程接口)的内容,其中包括KeePass如何在 “Windows User Account”的key参数选项中使用DPAPI。最近我进行了一些有趣的工作,这些工作Benjamin Delpy已经进行过,我想在此记录一些有关结合Mimikatz滥用DPAPI的方法。
注:本文关注对用户DPAPI的滥用,但有时也会涉及对机器DPAPI key的滥用。如果在之后我把滥用机器DPAPI搞清楚了,会随后发表一篇文章。
另注:我不是最初提出这些滥用的人,也没有写一些工具来实际滥用它们。这些思想都来自Benjamin和其它本文引用的人。我只是简单地整理各种滥用样例、语法,形成一个操作指南。
DPAPI速成课
我没有在文章中包含很多DPAPI背景知识,其它文章已经介绍地很好了:
Benjamin的wiki
https://github.com/gentilkiwi/mimikatz/wiki/module-~-dpapi,
https://github.com/gentilkiwi/mimikatz/wiki/howto-~-credential-manager-saved-credentials
https://github.com/gentilkiwi/mimikatz/wiki/howto-~-decrypt-EFS-files ,还有其它各种DPAPI相关的tweet。
Bartosz Inglot在OPCDE 2017的演讲“DPAPI的黑盒”
Black Hat Europe 2017上Paula J的报告“DPAPI and DPAPI-NG”
“DPAPI在渗透测试和密码破解中的利用”,作者Jean-Christophe Delaunay
“给我密码我将控制整个世界”,作者Francesco Picasso,还有他的演讲“ReVaulting”
Itai Grady的“在域环境保护浏览器的隐私”演讲
Jean-Michel Picod和Elie Bursztein的“解密DPAPI数据”
@_rastamouse关于跨网段的优秀文章,里面有一节讲使用Mimikatz解密DPAPI加密的RDP证书blob。
我确实丢掉了一些有趣的内容,但上面的资料是我了解DPAPI如何工作以及有哪些潜在滥用情况所阅读的资料。
DPAPI提供了一个简单的API集合,使用与用户绑定或与系统绑定的隐含key来透明地加密(CryptProtectData())和解密(CryptUnprotectData())数据blob。这使得应用程序保护用户数据时不用担心key管理等工作。
有许多事情要用到DPAPI,本文我只关注Chrome的Cookies和登录数据、Windows证书管理器(如保存IE或Edge登录密码和文件共享(RDP)密码)、远程桌面连接管理器的.rdg文件。
在顶层从用户角度看,用户的密码被用于产生一组用户特有的“Master Key”。
这些Key的位置在C:\Users\<USER>\AppData\Roaming\Microsoft\Protect\<SID>\<GUID>,<SID>是用户的安全描述符,<GUID>是Master Key的名字。
一个用户可以有多个Master Key。Master Key需要使用用户的密码或域备份key(见第四部分,Chrome)来解密,解密后的Master Key用于解密DPAPI blob。
所以,如果我们试图解密某个用户的被加密的DPAPI blob(如Chrome cookie值),我们需要关注该用户的Master Key。
Chrome
Chrome使用DPAPI保存两块我们感兴趣的信息:cookie值和登录数据:
Cookie文件的位置:
%localappdata%\Google\Chrome\User Data\Default\Cookies
登录数据的位置:
%localappdata%\Google\Chrome\User Data\Default\Login Data
%localappdata%在大多数系统对应于“C:\Users\<USER>\AppData\Local”。同时,这一节的所有Mimikatz命令对Cookie文件和登录数据文件都有效。
Chrome在一个SQLite数据库中存储cookies,存储的cookie值被加密为DPAPI blob来进行保护。幸运的是,Benjamin在Mimikatz中实现了Chrome的SQLite数据库解析。要列出当前用户的有效cookie值,使用下面Mimikatz命令:
mimikatz dpapi::chrome /in:”%localappdata%\Google\Chrome\User Data\Default\Cookies”
然而,cookie的值被DPAPI使用用户的master key加密过,master key则被用户的密码保护(或域备份key)。在某些情况下我们能够获得这些cookie值(或登录数据):
情况一:在目标用户上下文执行代码
这是最简单的情况。如果你想在用户上下文执行Beacon、Mimikatz或其它可执行代码,只需在dpapi::chrome命令中增加/unprotect标志:
该命令只是通知Mimikatz使用CryptUnprotectData API来解密我们想要的cookie值。如果我们在用户上下文执行该命令,将默认使用他们的master key执行请求的解密操作。
注:如果在Chrome使用该代码,有时会遇到打开Cookies数据库失败的问题。这时,只需复制Cookie或登录数据文件到当前的操作目录并使用新路径运行dpapi::chrome命令即可。
情况二:以管理员权限访问目标机器,且目标用户当前已登录
如果你不想在另一个用户的上下文注入一个Beacon,或者你登录了一个当前已有多个用户登录的系统,你可以选择做一些事。
如果你对属于另一个用户的数据库执行/unprotect操作,调用CryptUnprotectData()进行解密将得到一个错误。较新版本的Mimikatz能识别出解密所需的master key的GUID(在Cobalt Strike更新Mimikatz,就会在输出中看到),形如:needed masker key is {b8854128-023c-433d-aac9-232b4bca414c}。
我们可以看到,这个master key是harmj0y的Chrome Cookies目录的位置。我们同样可以通过列出用户目录(C:\Users\<USER>\AppData\Roaming\Microsoft\Protect\<SID>\<GUID>)内的所有makter key的GUID来得到用户的所有master key,以此来得到所需master key的GUID。如何对每个用户进行该操作,见Seatbelt节。
我们需要想办法获取harmj0y的master key。一个选择是运行sekurlsa::dpapi从内存提取所有系统内当前登录用户的DPAPI key(有时也在sekurlsa::msv命令的输出中显示)。
注:如果你没有通过Beacon使用Mimikatz,你可以利用Mimikatz的DPAPI缓存(详见文章最后的缓存节)。因为Beacon的工作架构,每一个Mimikatz命令会在一个新进程中运行,所以各个Minikatz命令间不会保存状态。通过GUI发出多个mimikatz命令可以解决该问题,发多个命令也可以通过Aggressor脚本实现。
比较GUID {b8854128-023c-433d-aac9-232b4bca414c}与提取的DPAPI key可知,我们需要的sha1 master key是f35cfc2b44aedd7…(使用完整版本或sha1版本的master key都可以)。可以在命令中通过参数手动指定dpapi的Chrome模块的解密目标:
beacon> mimikatz dpapi::chrome /in:”C:\Users\harmj0y\AppData\Local\Google\Chrome\User Data\Default\Cookies” /masterkey:f35cfc2b44aedd7… :
情况三:以管理员权限访问目标机器,且目标用户未登录
如果目标用户当前未登录到系统,你就需要知道他的明文密码或者密码的NTLM hash值。如果你知道明文密码,可以使用spawnas或者runas来产生一个以特定用户身份运行的新代理,然后在目标用户上下文运行:
beacon> mimikatz dpapi::chrome /in:”%localappdata%\Google\Chrome\User Data\Default\Cookies” /unprotect
或者,你也可以运行(在最近版本的操作系统):
dpapi::masterkey /in: /sid:<USER_SID> /password:<USER_PLAINTEXT> /protected
如果你只有用户的hash,可以使用Mimikatz的sekurlsa::pth来产生新进程(或使用Beacon的path封装来获取模拟token)。然而,当Mimikatz在新创建的登录会话中以登录类型9使用证书时(如NewCredentials/netonly),这些凭证在本地主机无法使用(也就还是无法得到目标用户上下文的进程),所以使用/unprotect将以相同的错误NTE_BAD_KEY_STATE失败。
然而,如果在网络使用这些凭证,并且要获取的key是属于当前用户的,我们可以使用Mimikatz来利用MS-BKRP(BackupKey远程协议)获取需要的key。Benjamin在他的Wik里详细描述了这个过程(在他文章“Credential Manager and Windows Vaults”节的最后也有更多细节)。实现这个RPC调用的代码是kull_m_rpc_bkrp.c。我们需要做的是指定makter key位置并应用/rpc标志:
beacon> mimikatz @dpapi::masterkey /in:”C:\Users\dfm.a\AppData\Roaming\Microsoft\Protect\S-1-5-21-883232822-274137685-4173207997-1110\ca748af3-8b95-40ae-8134-cb9534762688″ /rpc
注:模块前面必须有@前缀,这让Beacon强制Mimikatz对新产生的Mimikatz使用模拟线程token。到这里,我们就可以利用这个mater key解密我们指定的blob(语法见情况二)
情况四:提升域访问权限(即DPAPI上帝模式)
这是最有趣的情况。
一个可选的方法是DCSync目标用户的hash并重复情况三的方法。但还有更好的方法。
域用户的master key被一个域范围的备份DPAPI key保护着。这个key被 /rpc命令用于解密每个域用户的master key,这是架构中的专门设计。那为什么不只使用这个备份key?(假设有域管理员或类似的权限):
语法是:lsadump::backupkeys /system:<DOMAIN CONTROLLER> /export。这个.pvk后缀的特权key可以解密任何一个域用户的master key,而且这个备份key不会变化。
所以,我们下载harmj0y的master key文件(b8854128-023c-433d-aac9-232b4bca414c)和Chrome的cookies数据库,还有.pvk后缀的私有key。
旁注:获取备份key
当MS-BKRP的新版本开始支持基于RPC远程获取备份key(详见3.1.4.1.3节 BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID)。
Mimikatz也实现了这个RPC调用,lsadump::backupkeys方法使用LsaOpenPolicy/LsaRetrievePrivateData API(代替MS-BKRP)获取G$BCKUPKEY_PREFERRED LSA secret值。
我想更好地理解这个逻辑,所以我将Benjamin的远程备份key获取逻辑用C#重新实现了。项目上传到了GhostPark仓库。 默认会从当前的域控获取DPAPI备份key并输出为base64串,但该输出行为也可以修改:
一旦你获得了一个用户的master key或域备份key,你就不用在目标主机执行解密命令。你可以下载任何用户的master key文件(详细见后面的Seatbelt节)和DPAPI容器(如Cookies)。此时你可以选择:
用域备份key解密用户的master key(只有用这个key解密目标blobs)
从内存提取master key并直接使用
那么这里就用域备份key通过Mimikatz解密harmj0y的master key,然后使用master key解密Chrome cookie数据库:
mimikatz # dpapi::masterkey /in:b8854128-023c-433d-aac9-232b4bca414c /pvk:ntds_capi_0_32d021e7-ab1c-4877-af06-80473ca3e4d8.pvk
mimikatz # dpapi::chrome /in:Cookies /masterkey:f35cfc2b44aedd7…
如果保存一份这个.pvk key,就可以直接下载master key和需要的DPAPI blobs并离线解密。\m/
证书管理器和Windows Vaults
提示:下面的内容没有任何是我提出的,我只是将它们整理并以我认为最好理解的方式展示出来。所有荣誉都应当属于Benjamin在这个领域让人惊叹的工作。
从Windows 7开始,证书管理器准许用户存储网页和其它网络资源的证书。
用户证书文件存储在C:\Users\<USER>\AppData\Local\Microsoft\Credentials\。
系统证书文件存储在:
%systemroot%\System32\config\systemprofile\AppData\Local\Microsoft\Credentials\,这些证书文件被用户或系统特有的DPAPI master key保护着。
与此相关的是更难懂一点的Windows Vaults,它存储在C:\Users\<USER>\AppData\Local\Microsoft\Vault\\。在一个vault目录内,存在一个包含两个key(AES128和AES256)的Policy.vpol文件,该文件被一个用户特有的DPAPI master key保护着。这两个key可以用于解密相同目录里的其它*.vcrd证书。
这就是Vaults更加复杂的地方。
有一些获取这些vault证书的方法。如果证书存储的是IE或Edge登录信息,可以使用vaultcli.dll中的一系列API枚举这些证书。这可以通过Mimikatz的vault::list模块、Massimiliano Montoro的Vault转储代码、Matt Graeber引用了相同代码的PowerShell代码、Dwight Hohnstein引用了Graeber的C#代码、Seatbelt对Dwight代码的整理(seatbelt.exe DumpVault)来实现。然而,当运行这些代码时你会发现一个有趣的事情,不是所有的vault证书都返回了。为什么?
猜猜是啥?Benjamin一年多前已经在他的wiki上说明了准确的原因。下面对他的内容进行重新组织,不过还是推荐去看看他的wiki!
和我理解的一样,vault::list尝试列出和解密\AppData\Local\Microsoft\Vault\位置的证书,vault::cred尝试列出和解密\AppData\Local\Microsoft\Credentials\位置的证书。我不确定证书被分隔到两个目录的原因,看上去web证书以vaults形式存储,RDP或文件共享证书以证书文件形式存储。和Benjamin提到的一样:
那个链接已经不能访问了,我觉得那个tweet的内容应该是上面提到内容的屏幕截图。
Benjamin在wiki中说到,微软对vault证书的描述如下:
如果type成员是CRED_TYPE_DOMAIN_PASSWORD,这个成员包含UserName的明文Unicode密码。CredentialBlob和CredentialBlobSize成员不以0字节结尾。同样,对于CRED_TYPE_DOMAIN_PASSWORD,这个成员也只能被经过验证的包读取。
LSASS不想让我们轻易获得这些证书。Benjamin介绍了两个获取这些证书的相关研究。较危险的一个是运行vault::cred /patch命令修改LSASS的代码逻辑跳过CRED_TYPE_DOMAIN_PASSWORD检测。这当然不被建议(不管是Benjamin还是我),修改LSASS代码逻辑是一个危险操作,很有可能出错。此外,有一个更好地办法:moar DPAPI!
Benjamin描述了我们这里会遇到的另一个问题。根据微软介绍,“LSA线程可以通过指定CRYPTPROTECT_SYSTEM标志使用DPAPI保护那些LSA外部的无法被保护的数据(https://msdn.microsoft.com/en-us/library/ms995355.aspx )”。
所以,如果你使用CryptUnprotectData(如/unprotect)解密这类型的blobs,将得到错误。但是测试发现,这些blob是被 DPAPI master key加密的。
如果我们知道用户的明文密码,你就可以使用Chrome一样的方法(情况一)解密这个master key。如果不知道,不用担心,Mimikatz依旧可以帮你。
如Benjamin的详细介绍,MS-BKRP的一个组件(微软BackupKey远程协议)是一个运行在域控上的RPC服务,专门为授权用户解密DPAPI key(基于域范围的DPAPI备份key)的服务。换句话说,如果我们当前的用户上下文有一个特定的master key,你就可以让域控为我们解密它!这不是一个脆弱性,这是专门的设计,这是为用户修改或忘记密码的情况留下的漏报,并可用于支持各种smart card功能。
所以,如果我们从拥有master key的用户上下文(与Chrome类似,情况三)运行Mimikatz
# dpapi::masterkey /in:”%appdata%\Microsoft\Protect\\” /rpc
Mimikatz会请求域控(通过RPC)解密master key:
现在就可以通过dpapi::cred模块使用/masterkey:X参数解密保存的证书了!
更大的优势在于,当我们连接LSASS时,无需提权就可以对当前用户执行该方法。如果想对任何用户执行这类攻击,可以使用Chrome情况2-4的方法。
你可能会问:“任务调度证书呢?”Benjamin也包含了这块内容。你能够从内存(使用sekurlsa::dpapi)或LSA(使用lsadump::secrets)提取系统的DPAPI key,然后使用这个key解密保存在%systemroot%\System32\config\systemprofile\AppData\Local\Microsoft\Credentials的证书。
你可能还会问:“加密文件系统(EFS)呢?”。令人惊讶,Benjamin的wiki也介绍了。
里面还有解密Windows 10 SSH native SSH key的方法,Benjamin还提供了一个很好的demo视频:
https://twitter.com/gentilkiwi/status/1000162256456441857
里面还包括了为dpapi::wifi和dpapi::wwan提供的模块(https://twitter.com/gentilkiwi/status/696021888385028096 )及其它模块。
远程桌面连接管理器
当我起草这个文章,Benjamin分享了DPAPI的更多内容!
Windows远程桌面连接管理器有一个选项可以保存RDP连接证书,这也是将明文密码以DPAPI blob形式存储。这些配置文件存储在.rdg文件中,并可以使用新的dpapi::rdg模块解密。这个模块还没有出现在Beacon的mimikatz模块中,但在mimikatz下一次更新中会包含进去。同样,/unprotect,plaintext/hash,sekurlsa::dpapi masterkey,域备份key(Chrome 情况1-4)在这里一样工作。
关于如何枚举这些文件,见Seatbelt节。
Sidenote:Mimikatz DPAPI缓存
在文章前面提到过,基于Beacon的任务架构,每个mimikatz命令会在一个新的进程中运行,所有mimikatz命令之间无法保存状态。然而,Benjamin实现了一个很酷的DPAPI特征,我在想提一下:
如果你单独使用mimikatz.exe,Mimikatz将获得的DPAPI key存到一个缓存中以备后用。所以,如果你获得了域备份key,你可以随后解密任何master key,master key也会随后被加入缓存:
也可以保存/载入缓存来重用:
Seatbelt
我最近整合进Seatbelt了一些对相关DPAPI文件进程检查的功能(更多信息见http://www.harmj0y.net/blog/redteaming/ghostpack/ )。
Seatbelt.exe MasterKeys会搜索用户的master keys,不论是当前用户还是任何在系统内提交了上下文的用户。这是现在SeatBelt.exe用户检查功能执行的的默认检查:
枚举证书文件使用CredFiles命令,该命令现在也加入了默认的用户检查功能,使用与上文相同的用户/提交枚举策略:
使用RDCManFiles命令可以枚举远程桌面连接管理器的配置和.rdg文件,现在也加入了默认的用户检查功能,使用与上文相同的用户/提交枚举策略:
还有一些用来在默认的用户检查过程中发现浏览器cookie(包括Chrome)文件的附加信息:
这里指导你使用合适的Seatbelt命令、Mimikatz模块或者@djhohnstein的新项目SharpWeb(https://github.com/djhohnstein/SharpWeb/ )里的命令。
防御
防御这类DPAPI滥用很困难,因为这些都只是滥用提供的、现有的功能。读取和解密DPAPI blob是系统和应用程序经常做的事,所以这里没有许多捕获异常情况的机会。
对于从内存提取DPAPI key,有针对Mimikatz或LSASS读取功能的标准防护指导。
对于使用BackupKey远程协议(MS-BKRP)或获取远程DPAPI备份key,我不知道有什么很好的防护建议,但我想提供一些思路。
微软在Windows 10和Server 2016实现了一个事件日志集合可以审计DPAPI活动,但是所有事件的状态都是:“该子类的事件有一个信息,但是使用这类事件很难检测任何恶意活动,这主要用于DPAPI错误检查”。
对于ultimatewindowssecurity.com上的事件4695(“尝试解除可授权保护数据的保护”)通知,可以用来表示恶意行为,但是在一个干净隔离的测试系统中的正常行为也会导致这个事件记录。所以,这些事件只能为进一步检查提供潜在目标,它们的准确率不高。
BackupKey远程协议
当我在我的系统中调用dpapi::masterkey /in:<KEY> /rpc Mimikatz模块基于MS-BKRP进行master key获取,网络流量包括:
到远程系统IPC接口的SMB连接
在远程系统创建命名管道protected_storage
SMB调用(MS-RPCE)之上的几个包含加密stub数据的RPC
从protected_storage命名管道读备份key
清除
然而,因为在当前的域环境中这个协议在许多正常情况下也会被使用,尝试签名这个流量为异常将使这些正常使用无效。
远程获取LSA秘密
当我在系统中针对测试用域控执行远程LSA秘密获取,网络流量包括:
到远程系统IPC接口的SMB连接
在远程系统创建lsarpc命名管道
lsa_OpenPolicy2 RPC调用(RPC over SMB/[MS-RPCE]),操作码44
lsa_RetrievePrivateData RPC调用,操作码43
从lsarpc命名管道读备份key
清除
我也尝试检查远程获取LSA秘密时有没有在DC中创建特殊的事件日志,但没有发现有用的。如果有人知道如何根据DC的事件日志检测远程读LSA秘密,请告知我,我将更新本文。
微软高级威胁分析可疑行为指导上有一个“恶意数据保护私有信息请求”:
恶意数据保护私有信息请求
描述
Windows使用DPAPI保护浏览器保存的密码、加密文件和其它敏感数据。域控有一个备份key可以用来解密所有加入域的主机使用DPAPI加密的秘密。攻击者可以使用哪个master key解密任何域内主机使用DPAPI保护的秘密。为了检测该攻击,使用DPAPI获得备份key时触发一个警告。
检查
1. 源机器是否有组织许可的对Active Directory的高安全性检索权限?
2. 如果有,应该执行该操作。关闭并执行可疑行为。
3. 如果没有,不应该执行,关闭可疑行为。
处理
要使用DPAPI,攻击者需要域管理权限,实现绕过hash规则(https://www.microsoft.com/en-us/msrc?rtc=1 )。
然而,我不确定他们如何实现这个检测,也不知道他们的准确性。
总结
DPAPI很酷。因为不能花更多时间去理解Benjamin在这个领域的所有工作我感到很遗憾,但我很高兴工具盒中又多了一个TTP。
再次感谢@gentilkiwi的研究、工具和对本文的指导。
- End -
原文作者:玉林小学生
原文链接:https://bbs.pediy.com/thread-247634.htm
转载请注明转自看雪学院
更多阅读: