文章总结: 本文指出HVV中404状态码易致误判,需关注请求带来的实际改变。作者提出拆分边缘、应用、运行时和主机四个现场,并设计七条基于行为矛盾的规则以识别内存马威胁。建议复盘须沉淀字段字典、规则和JVM基线等资产,处置时先保全易失证据再重建,推动安全运营体系升级。 综合评分: 94 文章分类: 应急响应,WEB安全,安全运营,实战经验,红队
hvv 2026 – 404 只是表象:一次 HVV Web 告警,最后应该留下什么
利刃信安
2026年7月18日 16:30 北京
在小说阅读器读本章
去阅读
以下文章来源于MessFreeSecurity ,作者messfree
MessFreeSecurity .
提供社区优质咨询服务
在值守群里,404 是一种很有欺骗性的安慰剂。
它看上去像答案:页面不存在、请求没打中、攻击失败,可以继续看下一条了。特别是告警一多,分析员很容易顺手给它贴上“扫描”“误报”的标签。
可真正让人后背发凉的,恰恰是那些看起来最像失败的请求。
同一个会话,连续向同一路径发送 POST;每次都返回 404;响应长度却很稳定;请求间隔也不像扫描器乱撞。流量设备只告诉你“它说自己是 404”,却没有告诉你:业务逻辑有没有执行、JVM 里有没有多出一条映射、服务器有没有发起新的连接。
状态码只是应用最后递出来的一句话。至于屋里发生过什么,得去看现场。
两个老问题,今天仍然容易把人带沟里
我最近重新翻了一遍《冰蝎、蚁剑过流量监控改造及红队经典案例分享》。里面有两个问题很朴素:
-
流量监控里出现几次
/admin.jsp的 404,能否据此排除 WebShell 行为? -
.jsp、
.class已经删除,是否就等于后门已经清干净?
这两个问题值得保留,但原材料到这里就够了。今天再看它,重点已经不是某款工具怎样改流量,而是企业的检测体系为什么总在这里误判。
图注:原始材料只负责提出问题。下文讨论的是如何把问题改造成可运行、可复盘、可交接的检测工程。
HTTP 规范对 404 的描述,本来就很克制:服务端没有找到当前资源,或者不愿透露它是否存在。它描述的是响应语义,并没有替业务逻辑的执行过程作证。RFC 9110:404 Not Found
在 Servlet 里,代码可以直接设置响应状态;也可以先执行逻辑,再把状态写成 404。换句话说,客户端收到什么,和服务器刚刚做过什么,本来就是两件事。Jakarta Servlet:HttpServletResponse
所以,值守时真正该问的不是“为什么是 404”,而是下面这句:
这条请求进入系统之后,改变了什么?
只要问题换过来,调查方向也会跟着变。
一条请求,至少要看四个现场
很多误判来自同一个习惯:拿一个平面的证据,替整条攻击链下结论。
看到 WAF 放行,就认为后端收到的也是同一条请求;看到后端返回 404,就认为控制器没有执行;看到磁盘上没有 JSP,就认为 JVM 里也没有相关对象;看到机器重启后恢复正常,就认为身份凭据也恢复正常。
这些推断都跨了层。
更稳妥的办法,是把一次 Web 事件拆成四个现场:
边缘现场看请求怎样经过 CDN、负载均衡、WAF 和网关。这里最重要的并非“拦没拦”,而是规范化前后的 URI、Host、方法、请求体长度以及 Trace ID 有没有发生变化。
应用现场看路由命中、鉴权分支、异常处理和响应生成。404 可能来自业务代码,也可能来自统一异常页;500 可能发生在副作用之后;连接超时也不代表后端没有继续处理。
运行时现场看 JVM 中真实存在的 Servlet、Filter、Listener、Valve、Spring Mapping、ClassLoader 和 Agent。对于内存后门,这一层往往比文件目录更接近真相。
主机与云侧现场看进程、文件、网络、凭据和编排对象。Web 进程是否拉起子进程,是否写过临时目录,是否主动外连;Pod 重建之后,同一异常是否又从镜像、挂载卷、初始化容器或发布流水线里长出来。
四个现场缺一个,结论就容易飘。
删掉 JSP,只是把门牌摘了
第二个误区更隐蔽。很多处置动作停在“文件已经删掉”。
JSP 在容器中会经历翻译、编译、类加载和实例运行。Tomcat Jasper 的官方文档也明确提到 JSP 编译及工作目录。文件名消失,说明磁盘上的入口发生了变化;已经进入 JVM 的类、对象、映射和线程,还要看它们是否继续被引用。Tomcat Jasper How-To
Java 类的生命周期也说明了这一点:类由 ClassLoader 加载,卸载与其定义 ClassLoader 的可达性有关,并非随着源文件删除立即同步消失。Java Language Specification:Loading of Classes Java Language Specification:Unloading
图注:标准 Servlet API 对初始化后的动态注册有生命周期约束;现实中的内存驻留常常转向容器内部对象、反射、运行时映射或字节码机制,因此排查重点应落在“当前运行态”,而不是只搜某几个接口名。Jakarta ServletContext:addFilter
再往前一步,文件删除本身也只说明目录项被移除。以类 Unix 系统为例,只要还有进程持有文件引用,相关内容的生命周期就可能继续延伸。Linux unlink(2)
这也是为什么有些现场看起来“已经清完”,过几个小时又复发:
- JVM 里的异常映射还在;
- 进程被重启,但受污染的发布包仍在;
- Pod 被替换,挂载卷或初始化逻辑又把内容带回来;
- WebShell 消失了,攻击者拿走的数据库口令、云凭据和会话仍然有效;
- 只处理了当前实例,同一服务的其他副本还保留着入口。
删文件像把门牌摘掉。屋里的人走没走,钥匙换没换,楼里还有没有别的房间,都得另查。
规则别急着从正则开始
许多检测规则寿命很短,是因为它们从工具特征出发:某个固定 Header、某段请求体、某个响应长度、某种加密外观。工具一换版本,特征也跟着失效。
更耐用的规则应当描述攻击行为留下的矛盾。比如:
- 嘴上说“资源不存在”,同一会话却连续得到稳定反馈;
- 边缘设备记录的请求,与源站真正解析的请求对不上;
- 发布系统没有变更,JVM 路由和 ClassLoader 却发生了漂移;
- 文件刚创建就被访问,随后又迅速删除;
- 实例已经重建,异常却在相同服务上再次出现;
- Web 入口消失后,服务账号仍从新位置继续使用。
一条规则的寿命,不该比一个工具版本更短。
先把孤立的 404 拼成一段会话
单条 404 的噪声很大,连续行为却会暴露交互性。
可以先做一条 WEB-404-INTERACTIVE-SESSION:在 5 分钟窗口内,以“目标应用 + 规范化 URI + 会话指纹”为聚合键,寻找同一会话对同一路径连续发起 4 次以上 POST、PUT 或 PATCH,响应全部为 404,同时响应长度或时间间隔呈现稳定性。
会话指纹优先使用经过哈希的 JSESSIONID、业务 Token 或 Cookie;拿不到这些字段时,再退到源地址与 User-Agent 的组合。单纯按源 IP 聚合,经过 NAT、代理池和出口网关后,误差会很大。
基础分可以这样设:
| 观察项 | 加分 | | — | — | | 方法为 POST、PUT、PATCH | +1 | | 同会话 5 分钟内达到 4 次 | +2 | | 响应长度或往返节奏稳定 | +1 | | 边缘与源站记录存在差异 | +3 | | 出现文件、进程、网络副作用 | +5 | | JVM 映射或 ClassLoader 漂移 | +5 |
0—2 分只留存,3—5 分进入人工队列,6—8 分按高危核查,9 分以上直接拉通应用、主机和身份侧。这个分值不是行业定理,真正上线前要用本单位近 30 天流量回放,把健康检查、SPA 回退、监控探针、合法 API 和扫描器流量压一遍,校准阈值。
规则返回的证据也要讲究。别只吐出“命中 8 次”,至少带上首次与末次时间、会话哈希、URI、方法序列、状态序列、响应长度序列、Trace ID,以及前后 30 秒的主机副作用摘要。这样一线分析员打开告警时,看到的是一段行为,而不是一个红点。
状态码降级,副作用升权
更关键的一条规则叫 WEB-STATUS-SIDE-EFFECT。
它不关心响应是 200、404、500 还是超时,只看 Web 请求前后 30 秒内,应用进程有没有发生高价值副作用:
- 拉起 Shell、脚本解释器或系统工具;
- 在 Web 根目录、容器工作目录、临时目录创建或修改文件;
- 发起新的 DNS、TCP、HTTP 连接;
- 新增类加载、路由映射、Filter、Listener、Valve 或 Agent;
- 读取凭据文件、云实例元数据或高敏配置。
一旦命中,告警级别直接抬高。因为响应状态可以被业务代码控制,副作用却更难伪装。
实现这条规则,需要网关日志、应用日志、EDR 或 eBPF 进程网络遥测、文件审计、JVM 运行态快照之间共享 Trace ID,或者至少可以靠“服务实例 + 时间窗”关联。数据源暂时不齐时,先从最小闭环做起:网关请求与应用进程的外连、子进程关联,往往已经能筛掉大量假象。
比对边缘和源站,专抓“看见的不是同一条请求”
EDGE-ORIGIN-DIVERGENCE 解决的是另一个老问题:WAF、网关和后端可能对同一条请求作出不同解释。
同一个 Trace ID 下,分别保存边缘层与源站层的原始 URI、规范化 URI、Host、方法、Content-Length、Transfer-Encoding、状态码和上游状态码。未经业务配置允许,只要方法、目标路径或消息边界发生变化,就值得升高优先级。
这条规则的价值不只在某个具体绕过。它把检测目标从“搜危险字符串”变成“发现两个解析器之间的分歧”。RFC 9110 对中间件转发、URI 处理和消息语义有系统定义,工程上应尽量保存各层观察值,而不是让最后一层日志覆盖前面的事实。RFC 9110
给 JVM 建一份真正能对比的户口簿
内存后门最怕的不是关键词,而是基线。
JVM-RUNTIME-DRIFT 应在可信发布完成后,为每个应用实例采集一份运行态清单:
- Servlet、Filter、Listener、Valve 及其映射;
- Spring MVC 的 Handler Mapping;
- ClassLoader 层级、加载类数量、异常 CodeSource;
- Java Agent、Instrumentation 状态;
- 与构建制品和变更单的对应关系。
Spring 提供运行时注册 RequestMapping 的接口,Java Instrumentation 也能观察已加载类。这些能力本身有正常用途,检测重点在“是否符合发布基线、是否有变更依据、是否能追溯到可信制品”。Spring:registerMapping Java Instrumentation
告警条件可以写得很朴素:发布窗口之外出现新映射、新 ClassLoader、来源不明的类或 Agent,同时查不到构建制品和变更单。三者命中其二,进入高危;如果又与异常请求或外连重合,直接按严重事件处理。
基线也别只存“类名列表”。至少要保留实例、镜像摘要、制品摘要、采集时间、映射路径、处理类、ClassLoader、CodeSource 和变更单号。否则几万条类名摆在那里,看着很全,真正比对时仍然说不清变化来自哪里。
把“创建—命中—删除”看成一个动作
WEBROOT-EPHEMERAL-ARTIFACT 专门识别短命文件。
在 10 分钟窗口内,Web 根目录、容器工作目录或临时目录出现创建与修改,随后被 HTTP 请求命中,又在短时间内删除。三段事件只要能用路径、进程和实例串起来,就应形成一条高危告警。
它抓的不是某个固定文件名,而是“落地、使用、擦除”的节奏。合法发布、热加载和临时编译也可能出现类似动作,所以排除项必须绑定发布平台、签名制品、构建账号和批准窗口,别用一个宽泛的目录白名单把整片区域抹掉。
重启后又回来,调查对象就不再是那台机器
RESTART-REAPPEARANCE 关注重建前后的相同异常。实例或 Pod 重启后,相同文件、映射、外连目标或行为指纹再次出现,调查范围要立刻扩到镜像摘要、PodTemplate、挂载卷、初始化容器、Sidecar、Helm 参数和 CI/CD 制品。
Kubernetes 的 Pod 是短生命周期对象,真正决定它下一次长成什么样的,通常是控制器模板、镜像和卷。只清当前容器,容易把症状处理掉,把病根留在编排层。Kubernetes Pods Kubernetes Volumes Kubernetes Init Containers
再补一条 POST-COMPROMISE-CREDENTIAL-USE:Web 事件之后,如果服务账号、数据库账号、云 Token 从新 IP、新节点、新地域继续使用,或者在实例重建后仍有旧凭据活动,就把 Web 告警和身份告警合并。主机恢复只是其中一段,凭据轮换、会话失效和云侧访问审计也要进入闭环。
一条能交给同事接着用的规则,应该长什么样
规则不是一段查询语句。查询语句只负责命中,规则卡才负责让人相信、让人处置、让人维护。
每条规则至少写清这些字段:
| 字段 | 要回答的问题 | | — | — | | 规则 ID 与名称 | 它是谁,后续怎样引用 | | 检测假设 | 想捕捉哪一种攻击矛盾 | | 所需字段与数据源 | 缺哪个字段会失真 | | 聚合键与时间窗 | 事件怎样被拼成行为 | | 条件与评分 | 什么情况下升级 | | 排除项 | 哪些合法场景已经验证 | | 返回证据 | 分析员点开后能看到什么 | | 验证方法 | 用哪组历史样本和回放数据验收 | | 处置动作 | 谁先做什么,保全哪些现场 | | 负责人、版本与变更记录 | 出问题找谁,阈值为何调整 |
这里有个很现实的判断标准:换一个没参加本次事件的同事,他能否仅凭规则卡,在十分钟内说清告警为什么响、还缺什么证据、下一步找谁。做不到,说明这条规则仍然停留在作者脑子里。
复盘结束,真正该留下的是这五样东西
事件报告当然要写,但它只是过程记录。对下一次值守更有用的,是下面五份可复用资产。
一份字段字典。 把网关、WAF、应用、主机、JVM、身份、云审计的关键字段对齐,统一 Trace ID、实例 ID、服务名、镜像摘要、会话哈希和时间格式。字段没有对齐,所谓联动只会停留在会议上。
一组可运行的规则。 本文讨论的 7 条规则要进入版本库,带阈值、白名单、负责人和回滚记录。规则上线后观察命中率、误报原因、平均研判时间,并按业务域拆阈值。
一份 JVM 运行态基线。 每次可信发布后自动采集,和构建制品、镜像摘要、变更单绑定。基线不是拍一次留档,而是每次发布都能重新生成、自动比对。
一本研判与处置手册。 明确先取哪些易失证据,再做隔离、重建、凭据轮换和全副本检查。尤其要写清重启前由谁采集 JVM 状态,重启后由谁核对镜像、卷和发布链。
一套回放样本。 保存脱敏后的真实请求序列、正常发布流量、健康检查、扫描器噪声、短命文件事件和 JVM 漂移样本。每次调规则都跑一遍,看看抓到了什么,又误伤了什么。
如果还有精力,再做一块运营看板:规则命中量、有效率、误报前三项、证据完整率、平均研判时长、从告警到遏制时长。这样复盘才会从“讲故事”走向“改系统”。
现场处置,顺序也很重要
遇到疑似内存后门或状态码伪装时,处置顺序建议是:先关联边缘、源站、应用和主机记录;在业务影响允许的前提下,采集运行态、映射、类加载、进程网络、打开文件与镜像摘要;随后隔离受影响实例,从可信制品重建;再轮换相关账号、Token、数据库口令和会话密钥;最后核对所有副本、模板、卷、初始化逻辑和发布链。
“先重启再说”很痛快,也最容易把易失证据冲掉。真正成熟的处置,不追求动作快,而是追求每一步都知道自己将保留什么、又会失去什么。
写在最后
404、文件不存在、进程重启、告警消失,这些都只是某个时刻、某个平面的观察结果。它们可以成为证据,却不适合单独成为结论。
HVV 值守最值钱的能力,也不是记住多少工具特征,而是看出证据之间哪里对不上:返回失败,行为却像交互;文件消失,运行态却仍有映射;实例重建,异常却再次出现;主机干净,身份活动却还在继续。
沿着这些矛盾追下去,攻击链才会显形。
一次复盘的终点,也不该是把经过写得更长。它应该让下一次相似事件少争论十分钟,让分析员打开告警就知道该看哪几处现场,让处置人员重启之前先把该留的证据留下。
这才是一次 Web 告警真正应该留下的东西。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:利刃信安 《hvv 2026 – 404 只是表象:一次 HVV Web 告警,最后应该留下什么》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论