近期阅读了一款开源远控Havoc的源码,留下了一些笔记,干脆发出来一起学习一下,这个远控据说使用了很多高端免杀技术,比如Ekko,Ziliean,FOLIAGE睡眠混淆,返回地址欺骗,Indirect SysCall,Etw Patch,堆加密等等。
前言
FullSessionGraph.jpeg
先简单说说它TeamServer端是用golang写的,Agent端是C写的,UI是C++基于QT的,具体使用还是很多BUG,但抱着学习的心态来看看。
目录结构
首先想着看看这个C2协议这块咋样,于是读读TeamServer端的代码,看看目录结构,命名还是很清晰明了的。
Pasted image 20230906161038.png
话不多说,直接进入主题,远控提供了HTTP(S)、SMB的Agent,SMB是内网中继直连用的,直接来看HTTP(S)方面的代码。。
握手前校验
首先只有POST请求会被处理,其他请求都是直接跳fake404页面。
h.GinEngine.POST("/*endpoint", h.request)
h.GinEngine.GET("/*endpoint", h.fake404)
request里首先是对请求的header头进行判断,不符合直接跳fake404。
Pasted image 20230906160945.png
具体的Header头定义在havoc.yaotl中。
Pasted image 20230906160453.png
然后是检查url、ua,同样是不符合跳fake404,默认配置的url是这样子的。
Uris = [
"/funny_cat.gif",
"/index.php",
"/test.txt",
"/helloworld.js"
]
Pasted image 20230906161244.png
数据包的处理
经过一连串的判断后,来到parseAgentRequest函数,开始对Body内容进行判断。
Pasted image 20230906161529.png
在ParseHeader中,最终是返回Header结构。
type Header struct {
Size int
MagicValue int
AgentID int
Data *parser.Parser
}
Pasted image 20230906162130.png
NewParser时,试图将body内容赋值给Parser结构的buffer中,至于bigEndian默认是true。
type Parser struct {
buffer []byte
bigEndian bool
}
这里似乎将数据包分为了三种情况:
p.Length()小于4的情况下,直接丢弃该包,返回空的Response;
p.Length()等于4的情况下,直接将所有data复制到Header.Data中;
p.Length()大于4的情况下,将从末尾分别切出Size、MagicValue、AgentID,各为4个字节;
所以一个正常数据包的结构大致应该如下所示。
Pasted image 20230906172119.png
然后如果切出的MagicValue等于DEMON_MAGIC_VALUE,也就是0xDEADBEEF。
Pasted image 20230906170312.png
意味着是普通Deomon,否则是第三方Agent...等会,它是不是忘了什么?加解密呢?这不是白给么,建议做blueteam的小伙伴加一下流量规则。
Agent注册
继续跟进到DemonAgent,进来直接查AgentID;
if Teamserver.AgentExist(Header.AgentID){
...
}else{
...
}
函数内容是迭代Teamserver中所有的Agent,true的话就是已经存在,先看false情况,也就是注册的功能。
Pasted image 20230906171621.png
再次切掉一个CommandID,如果CommandID等于agent.DEMON_INIT也就是99,就意味着是注册包,然后切掉RequestID丢掉,进入注册流程。
Agent = agent.ParseDemonRegisterRequest(Header.AgentID, Header.Data, ExternalIP)
if Agent == nil {
return Response, false
}
go Agent.BackgroundUpdateLastCallbackUI(Teamserver)
接着从末尾切出AESKey和AESIv,并调用Parser.DecryptBuffer对Parser.buffer进行解密,解密完的结果放回buffer里。
Pasted image 20230906204004.png
所以数据包具体应该是这样的。
Pasted image 20230906204313.png
至于解密出来的buffer,据官方说法如下。
[ Agent ID ] 4 bytes