深度剖析汉得-HZERO系统Thymeleaf SSTI漏洞:从原理到修复

📅 2026/8/11 6:22:16
深度剖析汉得-HZERO系统Thymeleaf SSTI漏洞:从原理到修复
深度剖析汉得-HZERO系统Thymeleaf SSTI漏洞从原理到修复引言近期安全社区发布了关于汉得-HZERO系统存在服务端模板注入SSTI漏洞的预警信息。该漏洞存在于HZERO的OAuth登录模块中由于无需登录认证即可访问攻击者可通过注入Thymeleaf预处理表达式触发SpELSpring Expression Language执行进而实现远程代码执行RCE甚至植入内存马。本文将结合源码分析深度剖析该漏洞的成因、触发链路及修复方案。漏洞核心原理该漏洞的根本原因在于数据与代码边界的混淆。在Spring MVC结合Thymeleaf的架构中Controller返回的字符串会被视图解析器ViewResolver当作视图名称View Name进行处理。HZERO的OAuth登录模块在渲染页面时将Session中获取的template参数直接拼接为Thymeleaf视图名且未做任何合法性校验。当攻击者将恶意的Thymeleaf预处理表达式如__${...}__::x注入到该参数中时Thymeleaf引擎在解析视图名时会优先执行其中的SpEL表达式最终导致任意代码执行。源码级漏洞链路分析通过审查HZERO系统的OauthPageServiceImpl.java核心代码我们可以清晰地看到漏洞的触发过程Stringtemplate(String)session.getAttribute(template);// ...returnPagetemplate/returnPage;1. 投毒阶段Session污染虽然上述代码直接从Session中读取template且默认情况下前端并未传递该参数正常业务逻辑下默认为main但Session中的数据绝非凭空产生。在HZERO的多租户或主题切换逻辑中通常存在前置接口或拦截器Interceptor会将用户传入的主题参数写入Session。如果该前置节点未对输入进行严格过滤攻击者即可通过构造恶意请求如重定向参数污染将恶意的Payload注入到Session的template属性中。2. 触发阶段视图名拼接当攻击者在同一会话下访问/oauth/login接口时后端代码读取了被污染的Session。假设攻击者注入的Payload为__${T(java.lang.Runtime).getRuntime().exec(calc)}__::x代码将其与默认的returnPage如login拼接最终返回给Spring MVC的视图名变为__${T(java.lang.Runtime).getRuntime().exec(calc)}__::x/login3. 引擎解析与RCE触发Thymeleaf引擎在接收到该视图名时识别到了__${...}__预处理表达式语法和::片段引用语法。引擎会优先解析${...}内部的SpEL表达式调用Java底层的Runtime.getRuntime().exec()执行系统命令。尽管随后引擎会因找不到对应的模板片段而报错但恶意代码已在报错前成功执行。防御与修复方案针对此类SSTI漏洞防御的核心原则是绝不信任任何参与视图名拼接的用户输入。1. 代码层修复强制白名单校验这是最根本的解决手段。在获取template后、拼接视图名前必须增加白名单校验逻辑Stringtemplate(String)session.getAttribute(template);// 【新增】白名单校验逻辑ListStringallowedTemplatesArrays.asList(main,slide,mobile);if(templatenull||!allowedTemplates.contains(template)){templatemain;// 兜底默认值拦截非法输入}returnPagetemplate/returnPage;2. WAF/网关层临时防护在无法立即发版的情况下需在边界网关配置拦截规则URI特征拦截拒绝请求URI中包含__${、__#的请求。Payload特征拦截拒绝请求体或参数中包含T(SpEL类型引用、Runtime、ProcessBuilder、getClass、forName等敏感关键词的请求。总结HZERO的此次SSTI漏洞是一个典型的“信任边界缺失”案例。在现代Web开发中模板引擎赋予了开发者极大的灵活性但也引入了代码执行的风险。无论是从Session、Request参数还是配置文件中获取的数据只要参与了模板解析或视图路由都必须经过严格的白名单过滤才能彻底阻断攻击者的利用链路。