Win32 与内核滥用技术,供渗透测试人员使用
由 @UVision 和 @RistBS 为渗透测试人员和红队成员制作的 Win32 与内核滥用技术
开发模式已启用,欢迎任何帮助 :)
DOS_HEADER:PE 的第一个头,包含 MS DOS 消息("This programm cannot be run in DOS mode....")、MZ 头(用于标识 PE 的魔数)以及一些存根内容。IMAGE_NT_HEADER:包含 PE 文件签名、文件头和可选头SECTION_TABLE:包含节头SECTIONS:不是头,但值得了解:这些是 PE 的节区详情:https://www.researchgate.net/figure/PE-structure-of-normal-executable_fig1_259647266
简单的 PE 解析,用于获取 IAT 和 ILT 绝对地址:
GetModuleHandleA(NULL);BaseAddress+PIMAGE_DOS_HEADER.e_lfnanew(NT_HEADER 的 RVA)OptionnalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]IMAGE_DATA_DIRECTORY.VirtualAddress(IMAGE_IMPORT_DIRECTORY 的 RVA)BaseAddress + IMAGE_IMPORT_DIRECTORY.VirtualAddress(IMAGE_IMPORT_DESCRIPTOR 的 RVA)EAT 解析 PE 导出的所有函数,也解析 DLL。它定义在 IMAGE_EXPORT_DIRECTORY 结构中:```c
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name; // name of DLL
DWORD Base; // first ordinal number
DWORD NumberOfFunctions; // number of entries in EAT
DWORD NumberOfNames; // number of entries in (1) (2)
DWORD AddressOfFunctions; // RVA EAT and contains also RVA of exported functions
DWORD AddressOfNames; // Pointer array contains address of function names
DWORD AddressOfNameOrdinals; // Pointer array contains address of ordinal number of functions (index in AddressOfFunctions)
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
请注意,EAT 定义在 DLL 中,而不是在“真正的”PE 中(PE 会使用已加载 DLL 的 EAT 来解析它想要使用的函数的指针)。
### 解析函数地址
**使用函数地址**
你还在等什么?找到这个函数!
**使用序号**
序号是 `AddressOfFunctions` 数组中对应函数地址的**索引位置**。它可用于**检索函数的正确地址**,如下所示:
让我们尝试使用给定的序号 3 来查找对应地址(Addr4)。
- **AddressOfFunctions** : *Addr1 Addr2 Addr3 Addr4 .... AddrN*
- **AdressOfNameOrdinals** : *2 5 7 3 ... N*
我们要查找的地址位于第 3 个位置(从 0 开始),而我们的序号对应的是该地址的**索引**。
**使用函数名称**
AddressOfNames 数组中的第 N 个元素对应于 AddressOfNameOrdinals 数组中的第 N 个元素:使用给定的名称,您可以检索对应的序号,然后使用该序号继续查找函数地址。
## 导入地址表(IAT)
- PE 加载器不知道哪个地址对应哪个函数:让我们调用 IAT 来拯救我们
- 定义在 IMAGE_IMPORT_DIRECTORY 结构中:```c
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
DWORD Characteristics;
DWORD OriginalFirstThunk; // RVA to ILT
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name; // RVA of imported DLL name
DWORD FirstThunk; // RVA to IAT
} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;
总而言之,IAT 是一个表,其中包含指向 PE 从已加载的 DLL(ntdll、kernel32 等)导入的多个函数的指针。
PE 导入的每个 DLL 都有其自己的 ILT。``` Absolute address of ILT = BaseAddress + OriginalFirstThunk (IAT)
它包含导入 DLL 中所有函数的名称。
<br>
## 启用 SeDebug 特权
**SeDebug** 特权是 Windows 特权列表中“最抢手”的特权。它允许你“调试”任何授权进程,这可以转化为多种攻击性操作,例如以 ```PROCESS_ALL_ACCESS``` 特权打开句柄。
要在用户模式下启用它,你需要使用一个类似这样的函数:```cpp
void EnableDebugPriv()
{
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tkp;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = luid;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, false, &tkp, sizeof(tkp), NULL, NULL);
CloseHandle(hToken);
}
该函数将打开当前进程的令牌,然后将其调整为 SE_PRIVILEGE_ENABLED 特权,该特权与目标权限相对应。
这项技术几年前曾有不俗的绕过成功率;然而,随着 EDR 和其他端点解决方案数量的增加,应尽可能避免写入磁盘。