webshell缓存绕过/哈希碰撞

免责声明 本文全部实验操作均在本人完全可控的自建本地靶场环境完成,文章仅用于网络安全原理学习与技术研究。根据《中华人民共和国网络安全法》,未经授权对任何第三方系统进行探测、命令执行、文件写入等操作属于违法行为。

严禁复制、使用本文中的 Payload、代码应用到未获得授权的设备上。若读者将文中内容用于非法用途,一切法律责任由行为人本人承担,与本文作者无关。

个人水平有限,如有不足欢迎指正。


webshell绕过:网站存在 WAF、文件上传校验、代码检测、杀毒软件,会拦截 WebShell 文件上传或者直接查杀后门。绕过就是想方设法躲过检测,成功把后门上传到服务器并且正常执行。


1.缓存导致的绕过

HIDS

主机入侵检测,HIDS主要通过部署在各主机上的 HIDS Agent 采集主机上的文件、进程、日志、网络连接等信息,并将可疑文件或行为上报到中心管理节点,由中心节点统一调度检测引擎进行分析,最终生成检测结果并保存。

攻击者上传变形一句话木马 → HIDS Agent 捕获新增 php 文件 → 上报 Master 进入队列 → 分拣器无缓存 → 送入多引擎检测 → 机器学习 / Yara 识别为 WebShell → 结果入库并产生安全告警。

1. HIDS节点(Agent)

HIDS Agent 部署在被监控的服务器上。它负责对主机进行实时监控,例如服务器的 Web 目录突然出现:shell.php。Agent 可以发现这个文件,并将文件信息或文件内容提交给中心管理节点进行进一步分析。


2. master节点

master节点是整个系统的管理中心。

它负责:接收 Agent 上报的数据,进行任务调度,分发检测任务,获取检测结果,保存检测结果

因此可以把 master 理解成整个 HIDS 系统的控制中心多个 HIDS Agent 不需要自己管理所有检测逻辑,而是统一由 master 进行协调。


3. 队列

队列主要解决的是异步任务处理和并发问题。例如短时间内有 100 个 Agent 同时发现可疑文件:

复制代码
Agent 1 ─┐

Agent 2 ─┤

Agent 3 ─┤

Agent 4 ─┼──→ 队列 ──→ 分拣器

... │

Agent 100┘

如果直接同时进行检测,可能导致检测引擎压力过大。通过队列,可以把任务暂时保存起来,再由后面的模块按照一定速度进行处理。


4. 分拣器

分拣器的作用是:根据待检测文件的类型和特征,决定应该交给哪些检测引擎。

例如:

test.php经过分拣器到达PHP检测引擎

test.jsp经过分拣器到达Java检测引擎

也可以根据检测需求,同时交给多个引擎。所以分拣器相当于:检测任务的路由器。


5. WebShell检测引擎

这是整个流程中负责实际检测分析 的部分。内容检测

PHP引擎

xxx.php到达PHP引擎,分析PHP代码特征,判断是否具有WebShell特征

Java引擎

主要针对 JSP 等 Java Web 文件进行检测。

xxx.jsp,Java引擎,分析Java/JSP代码

Yara引擎

YARA 更偏向于基于规则进行匹配

例如预先定义一些特征规则:某些特征组合:根据YARA规则匹配文件,判断是否命中特征

机器学习引擎

机器学习引擎可以利用训练好的模型,根据文件的代码特征、行为特征等进行判断。

因此多个引擎可以形成:

规则检测+语言特征检测+特征匹配+机器学习,实现综合判断


6. Redis缓存

主要用于缓存检测任务和检测结果对文件内容做 Hash(MD5/SHA256)作为 Redis 缓存 Key。

例如某个文件已经检测过 :文件A查询Redis**,发现已经检测过,直接返回缓存结果** 这样就不需要每次都重新调用检测引擎。可以减少重复检测,提高系统处理速度。也就容易造成缓存导致的webshell绕过

第一次检测

文件 → 检测引擎 → 结果保存 → Redis

再次检测

文件 → 查询Redis → 直接获得结果

文件名/扩展名 → 主要用于分拣、确定检测类型;文件内容 → 主要用于实际 WebShell 检测;Redis → 缓存检测任务或检测结果,避免重复检测。


7. 数据库

数据库主要负责持久化存储

例如:主机信息、Agent信息、检测规则、检测结果、告警记录、历史记录

Redis 更偏向:临时缓存、快速查询

数据库更偏向:长期保存、持久化存储

利用第6点缓存的特点产生的思路

例如,首先上传一个 1.jsp 文件 ,其文件内容为 <?php phpinfo(); ?>。系统首先根据文件扩展名将该文件分配给 Java 检测引擎 。由于文件内容实际为 PHP 代码,与 Java/JSP 的语法特征不匹配,Java 检测引擎未检测出恶意特征 ,因此该文件被判定为正常并放行,同时将该文件的检测结果及其内容对应的哈希值写入 Redis 缓存。

随后再次上传一个 1.php 文件,但其文件内容与之前的 1.jsp 完全相同 。此时,如果系统的 Redis 缓存是以文件内容哈希作为缓存键,而没有进一步区分文件扩展名或实际使用的检测引擎,那么系统计算出相同的内容哈希后,会直接命中之前 1.jsp 的缓存记录,并复用之前的"正常/放行"检测结果,而不会再次调用 PHP 检测引擎对该文件进行检测。

因此,虽然第二次上传的文件扩展名已经从 .jsp 变成了 .php,理论上应该进入 PHP 检测引擎,但由于相同文件内容命中了此前由 Java 引擎产生的缓存结果 ,最终导致 1.php 继承了第一次检测的放行结果,从而出现检测引擎与缓存结果不匹配导致的检测绕过

防御:计算文件缓存时带上了文件名

绕过思路:生成一个正常文件和一个 webshell,两个文件的 hash 完全相同再让他们文件名相同,这样就可以命中同一个缓存了。

hash碰撞

基础概念:哈希算法:输入任意长度数据 → 输出固定长度哈希摘要(MD5、SHA1、SHA256)。理想状态:不同内容,一定产出不同哈希值。

哈希碰撞:两段内容完全不一样的文件 / 数据,经过同一个哈希函数计算,得到完全相同的哈希值。A ≠ B,但是 hash (A) = hash (B)

思路:

例如:创建1.php和2.php文件,第一个php文件内容设置为

复制代码
<?php
    evam($_POST[123]);

第二个php文件内容为

复制代码
<?php
    eval($_POST[123]);

首先将 1.php 提交给 PHP 检测引擎,由于 evam() 并不是 PHP 中实际存在的函数,检测引擎未识别出其中的危险代码特征,因此将其判定为正常并放行,并将该文件内容对应的 Hash 及检测结果写入 Redis 缓存。

随后,通过构造使 2.php 的文件内容与 1.php 产生相同的 Hash 值 ,再将该文件重新命名为 1.php 后上传。由于 HIDS 的缓存机制在查询缓存时使用文件内容 Hash 作为重要依据,重新命名后的 2.php 会以 1.php 的文件名进入检测流程,并命中此前 1.php 对应的正常缓存记录。此时系统直接复用之前的检测结果,而不会重新对 eval() 进行检测,从而使修改后的恶意文件被错误放行。

这里用到了这样的一个工具进行哈希碰撞

cr-marcstevens/HashClash:Project HashClash - MD5 和 SHA-1 密码分析

cpc.sh 是Chosen-Prefix Collision(选择前缀碰撞)脚本,在这里适用

最终成功生成了两文件内容不同,但是hash值相同的文件,接下就可以将第二个php文件改名为第一个php文件名,再次提交就可以绕过。

相关推荐
致Great8 小时前
Pi 的上下文压缩,到底是怎么工作的?
算法
watersink9 小时前
机器学习聚类算法
算法·机器学习·聚类
luj_176810 小时前
桥牌思维启示:系统设计的模块化架构
c语言·开发语言·c++·经验分享·算法
饼饼学习空间智能11 小时前
家庭服务机器人训练数据怎么积累?仿真、真实采集与持续学习的技术路线分析
人工智能·算法·机器学习
蛋先生DX13 小时前
你瘦不下来但大模型可以:量化原理了解一下
深度学习·算法·llm
牛阿大14 小时前
LQR算法
算法
(╹◡╹)14 小时前
18.剪枝
算法·机器学习·剪枝
Fa_Mian_Tuan15 小时前
图论基础|邻接矩阵超详细讲解(含无向/有向/带权图+完整可运行C语言代码)
c语言·数据结构·笔记·算法·图论