绕过AV进行UserAdd的方法总结及实现

admin 2023年12月11日16:29:05评论13 views字数 5276阅读17分35秒阅读模式

我们知道,一般我们想要进行添加用户等操作时,基本运行的是:

net user username password /add
net localgroup administrators username /add

其实一般杀软只会检测前面添加用户的命令,而后面的命令并不会触发杀软的报警行为,其实在这里 net 是在 C:WindowsSystem32 下的一个可执行程序,并且该目录下还有 net1.exe,这两个程序的功能是一模一样的:

绕过AV进行UserAdd的方法总结及实现

不论我们是使用 net 或者是 net1 都会被杀软检测,至于是不是对底层 APIHook 操作,我们还并不清楚

绕过AV进行UserAdd的方法总结及实现

因此在这里,我们来监测系统使用 user add 时具体对应的 API:

实际上当我们使用 net user username password /addnet 程序会去调用 net1.exe 程序,然后使用相同的命令:

绕过AV进行UserAdd的方法总结及实现

当尝试跟进 net1.exe 来跟踪相关操作时发现应该是使用 RPC,并且 endpointPIPElsarpc 来进行其他的操作

绕过AV进行UserAdd的方法总结及实现

到这里就没有进一步跟进下去,其实在这里了解到实际上是通过 MS-SAMR 协议通过 RPC 实现的,MS-SAMR 的官方 IDL 文档贴出:

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/1cd138b9-cc1b-4706-b115-49e53189e32e

可以看到其中 SamrSetInformationDomain 等方法都是其接口方法,这也为后文埋下了一定伏笔,因此使用 BypassAV 进行 AddUser 的方法并没有结束

Win API 进行UserAdd

MSDN 搜索添加用户相关资料时就会发现微软官方是提供了标准 API 进行添加用户的,可以参考:

https://docs.microsoft.com/en-us/windows/win32/api/lmaccess/nf-lmaccess-netuseradd

NetUserAdd 其函数原型如下:

NET_API_STATUS NET_API_FUNCTION NetUserAdd(
  [in]  LPCWSTR servername,
  [in]  DWORD   level,
  [in]  LPBYTE  buf,
  [out] LPDWORD parm_err
);

其中 level=1 时,指定有关用户帐户的信息。此时 BUF 参数指向一个 USER_INFO_1 结构:

typedef struct _USER_INFO_1 {
  LPWSTR usri1_name;
  LPWSTR usri1_password;
  DWORD  usri1_password_age;
  DWORD  usri1_priv;
  LPWSTR usri1_home_dir;
  LPWSTR usri1_comment;
  DWORD  usri1_flags;
  LPWSTR usri1_script_path;
} USER_INFO_1, *PUSER_INFO_1, *LPUSER_INFO_1;

这意味着我们本地实现时需要注意设置 user_info_1 这样一个结构体,在这里使用 Golang 进行简单的实现,其中核心源码如下:

绕过AV进行UserAdd的方法总结及实现

果然不出意外,杀软应该是对该 API 进行 Hook 了,即使通过调用 API 这一方式也会轻易被杀软检测到相关可疑操作

绕过AV进行UserAdd的方法总结及实现

互联网上一顿搜索发现21年6月份时该杀软就已拦截 netapi 加用户的方式:

绕过AV进行UserAdd的方法总结及实现

到这里只好硬着头皮去尝试对 netapi32.dll 进行逆向分析,看其中是否有更加底层的 API 实现,如果本身 NetUserAdd 也是封装的话,那我们完全可以实现自己封装从而绕过该 API

对NetAddUser的底层封装调用

在互联网上搜索看看有没有前人已经进行过相关工作,结果发现确实有前人已经做过相关逆向的工作:

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

Win10 中的 netapi32.dll 已经找不到相关添加用户的函数,只有一个 NetUserAdd 的导出函数,我们尝试逆向 XP 中的 netapi32.dll:

绕过AV进行UserAdd的方法总结及实现

Security Account Manager (SAM) 是运行 Windows 操作系统的计算机上的数据库,该数据库存储本地计算机上用户的用户帐户和安全描述符。

这里对 UserAdd 的实现也是首先尝试连接 SAM 数据库,判断 SAM 中是否已经存在该用户,然后利用 RtlInitUnicodeString 对新建用户信息等做一个初始化操作,最后调用 SamCreateUser2InDomain 来创建用户账户,创建成功会继续调用 UserpSetInfo 设置用户密码,因此实际上 NetUserAdd 就是被这样几个关键函数进行封装,因此我们需要做的是哪些函数能够直接调用,而哪些函数是还需要自己进一步封装

其中 UaspOpenSam 没有导出,而实际上对应的是 SamConnect:

绕过AV进行UserAdd的方法总结及实现

UaspOpenDomain 同样没有导出,实际上对应的也是 Sam 系的函数:

绕过AV进行UserAdd的方法总结及实现

这里 SamOpenDomain 的函数原型大致如下:

SamOpenDomain(ServerHandle, DesiredAccess, DomainSid, &DomainHandle)

因此我们是需要 DomainSid 的,也就是说我们还需要获取账户所在域的 SID 信息,经过搜索发现可以使用 Sam 函数获取的,而在 ReactOSmimikatz 中就是使用的 LSA 函数进行查询的:

绕过AV进行UserAdd的方法总结及实现

MSDN 中查询该函数 (LsaQueryInformationPolicy) 发现存在:

函数原型如下:

NTSTATUS LsaQueryInformationPolicy(
  [in]  LSA_HANDLE               PolicyHandle,
  [in]  POLICY_INFORMATION_CLASS InformationClass,
  [out] PVOID                    *Buffer
);
// in Advapi32.dll

继续跟进,发现 UserpSetInfo 同样没有导出函数,继续跟进这个函数:

绕过AV进行UserAdd的方法总结及实现

而在 React OSSetUserInfo 函数中同样找到该方法的调用:

绕过AV进行UserAdd的方法总结及实现

这里的 UserAllInfo 对应的就是 USER_INFO 结构体,而通常情况下我们都是使用 USER_INFO_1,并且将值设置为 1

绕过AV进行UserAdd的方法总结及实现

因此大致过程已经比较清楚:

1. 调用 SamConnect 连接 SAM 数据库
2. 通过 LsaQueryInformationPolicy 获取 SID 信息后调用 SamOpenDomain
3. 验证完成后调用 SamCreateUser2InDomain 创建用户信息
4. 最后通过 SamSetInformationUser 来设置新建用户的密码

最后成功绕过杀软进行用户添加:

绕过AV进行UserAdd的方法总结及实现

Cobalt Strike argue参数欺骗

CS 3.1 版本后引入了 argue 参数欺骗技术,使得进程在创建时记录的参数与实际运行时不同

windows系统从进程的进程控制块的commandline中读取参数,并对参数做相应的处理,在线程未初始化完成前,我们可以修改这些参数,达到伪装commandline的目的

操作其实就是读取进程中 PEBRTL_USER_PROCESS_PARAMETERS 结构体,在该结构体中对 CommandLine 指针进行修改

typedef struct _RTL_USER_PROCESS_PARAMETERS {
  BYTE           Reserved1[16];
  PVOID          Reserved2[10];
  UNICODE_STRING ImagePathName;
  UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

这里我们使用 argue 进行参数混淆污染 net1 程序,然后在通过 execute net1 username password /add 方式来进行添加用户,笔者反复试验了多次,均为检测到,因此判断通过参数欺骗这种方式还是可以逃过杀软的检测,毕竟杀软对于 commandline 的检测也是通过读取进程 PEB 表实现的

绕过AV进行UserAdd的方法总结及实现

C#利用命名空间和目录服务添加用户

这其实是微软文档中自己给出的一种方式,具体可以参考:

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

注意需要添加对程序集System.DirectoryServices.dll的引用

这种方式通过 C# 中调用 DirectoryServices 添加本地用户,同时支持删除用户、添加用户组等实现

这里直接参考官方文档的描述就行,核心代码如下:

DirectoryEntry AD = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
DirectoryEntry addUser = AD.Children.Add(username, "user");
addUser.Invoke("SetPassword", new object[] { password });
addUser.CommitChanges();
DirectoryEntry grp;

grp = AD.Children.Find("Administrators", "group");
if (grp != null) {
grp.Invoke("Add", new object[] { addUser.Path.ToString() });
}
grp = AD.Children.Find("Remote Desktop Users", "group");
if (grp != null) {
grp.Invoke("Add", new object[] { addUser.Path.ToString() });
}

经过检测这种方式同样不会被杀软拦截,并且利用 C# 还有代码简洁,可以结合 CS 内存加载运行的特点,我们知道 CS 3.1 后便支持使用 execute-assembly 方式来调用 NET 程序集文件

绕过AV进行UserAdd的方法总结及实现

编写反射DLL以及CS插件化实现

在编写的过程中其实已经发现,数字杀软已经对反射注入的行为特征进行检测,这里或许可以对反射 DLL 的一些属性进行修改,看到一些思路说是先不使用 RWE 属性的内存页,先使用 RW 属性执行 DLL 加载,加载完成后再将代码段改为 RE 可以绕过,在这里没有进行相关修改

在反射 DLL 编写中实现了2种方式,通过 Win API 创建用户和重构 NetUserAdd,实现底层创建用户,当使用反射注入方式时2种方法都会被检测到

绕过AV进行UserAdd的方法总结及实现

而前文已经提到,重构 NetUserAdd 实现底层创建,即通过 SamSetInformationUser 创建是不会被杀软拦截的,因此插件的实现只是包含反射注入的功能作为参考(或许对其他 EDR 比较好使),结合其他两种方式实现绕过杀软进行用户添加的功能

基于上述原理和方法,实现了一个简单的 Bypass 添加用户的插件,主要实现的有利用反射注入实现 API 添加用户和底层实现 API 添加用户,以及内存加载 NET 程序集实现 C# 活动目录添加用户和底层实现 API 的可执行程序上传再执行

实现效果如图:

绕过AV进行UserAdd的方法总结及实现

绕过AV进行UserAdd的方法总结及实现

但令我不解的是前一天利用 C# 编写的添加用户还能够成功绕过该杀软,第二天将上述这些能够绕过的封装到反射 DLL 或者封装到插件里面去之后,杀软都检测到了…这更新速度未必也太快了?

而且连前一天的 argue 参数欺骗都被检测了,中间间隔不到 24h 时间,在这里不得惊叹速度之快(可以看截图信息里的时间)

绕过AV进行UserAdd的方法总结及实现

因此我也比较无奈,刚写好插件就发现没办法 Bypass 杀软了,只好作为实现原理和姿势分析,还有一个思路就是直接调用 RPC 接口方法,不过这种方式其实本质和重新封装 NetUserAdd 是一样的,具体能不能绕过我没有实现了…

绕过AV进行UserAdd的方法总结及实现

发现 @loong716 师傅之前分享过利用 ms-samr RPC 实现过更改用户密码,可以参考:

https://github.com/loong716/CPPPractice/tree/master/ChangeNTLM_SAMR

这里应该在此基础上进行修改就能够实现创建用户,稍微留个坑等之后再来重写下

 

本文作者:Crispr原文地址:https://www.crisprx.top/archives/531
参考文章:https://idiotc4t.com/redteam-research/netuseradd-ni-xianghttps://loong716.top/posts/Set_ChangeNTLM_SAMR/#2-%E7%9B%B4%E6%8E%A5%E8%B0%83%E7%94%A8ms-samrhttps://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/1cd138b9-cc1b-4706-b115-49e53189e32e

 

绕过AV进行UserAdd的方法总结及实现

公众号(刨洞安全团队):绕过AV进行UserAdd的方法总结及实现

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月11日16:29:05
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   绕过AV进行UserAdd的方法总结及实现https://cn-sec.com/archives/2276266.html

发表评论

匿名网友 填写信息