背景
RTO I 的课程结束了,Cobalt Strike 算是会用了。然后继上一篇文章之后,我还没有机会用 Cobalt Strike Beacon 做一下 Windows Defender Bypass。之后会写。
另外,我也想问一下我自己,Cobalt Strike 里面最基本的 payload - beacon,你了解清楚了吗?
所以今天,我就花点时间给自己解惑,同时也提出更多问题往后深入。
接下来先对 Beacon 做下逆向,看一下 HTTP Beacon 大致上都做了什么。
Beacon
创建一个基于 HTTP Listener 的 64位 beacon。
看一下文件格式,64位 PE 文件。
看到 PE 头。
xxd beacon.exe | less -S
这一段 bOb
很有意思,可以用作 Signature Detection 吗?
strings
一下看到了使用了哪些方法。
使用了哪些 dll。
在 IDA 里具体看一下。
创建命名管道
拖到 IDA。
从进度条长度来看,HTTP beacon 的复杂度并不高(也有可能是我什么都不懂,错的离谱)。
逆向的能力不是很强,所以先随便看看。
我的思路是能不能找到相关 API,如 VirtualAlloc,CreateThread 之类的字符串,或者是参数的字符串也行。所以我就一个一个点开看了一下。
运气比较好的是,在第四个 entry 就找到了。
如图,StartupInfo
是 CreateProcessA
API 的参数。
CreateProcessA
方法原型。
BOOL CreateProcessA(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
找到了 StartupInfo
,就意味着找到了 CreateProcess
。
接着往下看,不一会儿看到了 GetProcAddress
API。
调用之后检查 eax 返回值,如果是 0 表示成功,跳到 loc_4012A1
。
接着一个一个翻看左边的方法名列表。
在 sub_401795
找到了 CreateThread
方法。看到了默认的 pipe name
。
拼接完成之后,应该是 \\.\pipe\MSSE-XX-server
。
其中 xx
是一个数字跟 ecx 中的数值 (0x26AA -> 9898)做除法运算(实际是取模),最后取了 EDX 中的余数作为 xx
的值。
这里创建了一个线程并执行。看一下到底启动了一个什么样的线程。跟进 sub_401685
,那里是执行代码的起始地址。
再跟进 sub_4015D0
。
所以,上面的 CreateThread
方法,是创建一个命名管道,用来写入和读取数据,命令执行的结果应该就是通过管道来获取的。第一步完成,HTTP Beacon 首先创建了一个命名管道,管道名称就是上面看到的
\\.\pipe\MSSE-XX-server
继续跟进代码,看下一步做了什么操作。
连接命名管道
创建完了命名管道(如果创建成功),紧接着就是执行 ConnectNamedPipe
连接该命名管道。
这里开始网管道里面写数据。
写数据有了,读取在哪里呢?
继续往下找,可以看到这里调用了 CreateFileA
API。
这里 dwCreateionDisposition
设置为 0x3
。
查看官方文档,这个设置是会打开一个已经存在的文件或者设备。
猜想这里是用 CreateFileA
打开了已经创建好的管道。
然后通过 ReadFile
API 读取数据。
唯一可以说明这里打开的文件就是之前创建的管道的指标,就是这个 Buffer (lpFileName)
参数。
双击点进去,可以看到他指向了 sub_4015D0
。
而 sub_4015D0
正是创建命名管道的方法。
进一步可以判定,这个 Buffer
就是管道名,ReadFile
就是读取了该管道的数据。
Beacon HTTP 请求?
接下来,我想找到诸如 IP 地址,端口,从而找到 HTTP 请求的代码。
结果通过 IP 地址找不到。
返回去看 strings
命令的输出,确实没有看到跟 HTTP 或者 Socket 连接相关的方法或者是 DLL。
而如果看一下 msfvenom 生成的 payload。
msfvenom -p windows/x64/meterpreter_reverse_tcp LHOST=127.0.0.1 LPORT=443 -f exe -o msf.exe
strings msf.exe
可以很清楚看到诸如 WSADuplicateSocketA
,WinHTTPConnect
等方法,也看到了 WS2_32.dll
。
有点疑惑。
拖到 windows 机器上用 WinDBG 看一下。
看来 strings
不能列出运行期间会加载的 dll。
在 WindDBG 里面看到了 winhttp.dll
,WS2_32.dll
。
选择 WS2_32.dll
在 recv
API 上打个断点试一下。
bp ws2_32!recv
发送一条命令看一下能不能触发断点。
断点触发了。其实每隔5秒就会触发断点,因为 beacon 会 checkin,就算没有命令可以执行,C2 Server 也会发送相应的 response。
sleep
没有输出。再执行一个 whoami
看一下怎么发送命令结果的。
再次触发断点。单步执行。
今天告一段落,找时间继续。还要验证一下上面所说的读取数据的 CreateFileA
方法。
总结
这篇文章对 Beacon 做了一些比较简单的分析。开个头先,之后还会不断深入。
KEEP CALM AND HACK AWAY!
参考链接
- https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/windows-x64-calling-convention-stack-frame
- https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
- https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa
- https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread
- https://learn.microsoft.com/en-us/windows/win32/api/winhttp/nf-winhttp-winhttpconnect
- https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaduplicatesocketa
- https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect
- https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsastringtoaddressw
- https://decoded.avast.io/threatintel/decoding-cobalt-strike-understanding-payloads/
- https://docs.oracle.com/cd/E19455-01/806-3773/6jct9o0am/index.html#:~:text=div%20executes%20unsigned%20division.,AH%2C%20Dx%2C%20or%20EDX.