查看原文
其他

Atlassian JIRA Velocity模板注入漏洞分析

启明星辰 ADLab 2022-12-23

更多安全资讯和分析文章请关注启明星辰ADLab微信公众号及官方网站(adlab.venustech.com.cn)












近两年Atlassian JIRA爆出几个SSTI(服务器端模板注入)漏洞,漏洞编号分别为CVE-2019-11581、CVE-2021-39115和CVE-2021-43947。这三个漏洞实质都发生在发送邮件过程中。本文以CVE-2019-11581为例,分析该SSTI(服务器端模板注入)漏洞的触发原理。


 01  漏洞描述 


JIRA是Atlassian公司的核心产品,JIRA被业界公认为最好的项目管理和开发管理工具。在JIRA的多个版本中存在服务器端模板注入漏洞,漏洞编号为CVE-2019-11581。攻击者可通过向网站管理员发送邮件的操作触发该漏洞,在受影响的服务器上远程执行任意代码。



 02  漏洞影响 


  • Atlassian Jira 4.4.x<7.6.14
  • Atlassian Jira 7.7.0<7.13.5
  • Atlassian Jira 8.0.x < 8.0.3
  • Atlassian Jira 8.1.x < 8.1.2
  • Atlassian Jira 8.2.x < 8.2.3


 03  漏洞分析 


洞环境:Atlassian Jira 8.2.2
漏洞利用前置条件:
  • 联系管理员表单功能为"开",默认为关;
  • 已经配置好SMTP服务器,这里SMTP服务器的信息可以随便填,不影响利用。
通过访问`/secure/admin/EditApplicationProperties!default.jspa`请求可对以上两个条件进行设置,这里的设置均需要管理员权限。
设置好以上两个前置条件后进入正题。
访问secure/ContactAdministrators!default.jspa填写"联系网站管理员"的功能表单:
其中,“主题”处填写触发velocity模板注入的poc。
为什么“主题”字段能触发漏洞呢?下面调试代码分析其原理。(说明:“主题”处对应参数为”subject”)。
根据web.xml中的配置,当请求形如*.jspa时,通过com.atlassian.jira.web.dispatcher.JiraWebworkActionDispatcher处理。
<servlet><servlet-name>action</servlet-name><servlet-class>com.atlassian.jira.web.dispatcher.JiraWebworkActionDispatcher</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>action</servlet-name><url-pattern>*.jspa</url-pattern></servlet-mapping>
在com.atlassian.jira.web.dispatcher.JiraWebworkActionDispatcher中,通过this.getActionName(httpServletRequest);获取actioinName,然后进入对应的action处理。
当访问secure/ContactAdministrators.jspa时进入Action工厂中com.atlassian.jira.web.action.user.ContactAdministrators类的doExecute()方法处理。
如上图代码所示,首先确保this.getShouldDisplayForm()为true才能进入this.send()进行后续流程。跟进this.getShouldDisplayForm()看看是如何判断的。
this.getShouldDisplayForm()->com.atlassian.jira.util.JiraContactHelperImpl#isAdministratorContactFormEnabled()代码如下:
public boolean isAdministratorContactFormEnabled() { return this.mailServerManager.isDefaultSMTPMailServerDefined() && this.applicationProperties.getOption("jira.show.contact.administrators.form") && !this.jiraSystemProperties.getBoolean("atlassian.mail.senddisabled") && !this.applicationProperties.getOption("jira.mail.send.disabled");}
以上代码解释了为什么必须要配置默认的SMTP邮件服务器以及需要设置jira.show.contact.administrators.form为true。
在以上前提满足的条件下,进入this.send(),然后跟踪到com.atlassian.jira.web.action.user.ContactAdministrators#sendTo()方法:
private void sendTo(ApplicationUser administrator) throws MailException { try {Map<String, Object> velocityParams = Maps.newHashMap();velocityParams.put("from", this.replyTo);velocityParams.put("content", this.details);velocityParams.put("padSize", PADSIZE);Email email = new Email(administrator.getEmailAddress());email.setReplyTo(this.replyTo);MailQueueItem item = (new EmailBuilder(email, this.getMimeType(administrator), I18nBean.getLocaleFromUser(administrator))).withSubject(this.subject).withBodyFromFile(this.getTemplateDirectory(administrator) + "contactadministrator.vm").addParameters(velocityParams).renderLater();this.mailQueue.addItem(item);} catch (Exception var5) {this.log.error("Error sending JIRA Administrator email", var5);}}
通过MailQueueItem item = (new EmailBuilder(email, this.getMimeType(administrator), I18nBean.getLocaleFromUser(administrator))).withSubject(this.subject).withBodyFromFile(this.getTemplateDirectory(administrator) + "contactadministrator.vm").addParameters(velocityParams).renderLater();实例化EmailBuilder对象,包含基本的Email信息(邮件发送方、邮件内容、邮件接收方等信息),然后通过com.atlassian.jira.mail.builder.EmailBuilder#withSubject方法,将EmailBuilder对象的subjectTemplate属性设置为表单中的subject值。同时通过com.atlassian.jira.mail.builder.EmailBuilder#withBodyFromFile方法设置EmailBuilder对象的bodyTemplate属性为templates/email/html/contactadministrator.vm模板文件。
然后通过this.mailQueue.addItem(item);将该邮件事件加入邮件队列中。
到此为止,没有看到渲染模板的代码,那么漏洞到底是怎么触发的呢?
完成以上流程后,SchedulerQueueWorker会唤醒邮件队列服务MailQueueService,进入com.atlassian.jira.service.services.mail.MailQueueService#run()发送邮件队列。这里是自动进行的,不需要额外发包触发该操作。
具体代码定位到com.atlassian.jira.service.services.mail.MailQueueService#run:
进入com.atlassian.jira.mail.JiraMailQueue#sendBuffer方法:
如上图调试信息所示,经上面发送邮件操作,此时JiraMailQueue.this.delegate中的item对象中包含3个邮件队列事件(对应com.atlassian.jira.mail.builder.RenderingMailQueueItem类)待发送。com.atlassian.jira.mail.builder.RenderingMailQueueItem类的emailRenderer属性包含了email、subjectTemplate等信息,这些信息都已通过第一步请求/secure/ContactAdministrators.jspa post的表单所设置。
继续分析,进入到com.atlassian.mail.queue.MailQueueImpl#sendBufferUnderLock()方法,该方法依次从邮件队列事件中取出邮件进行发送:
一路调试,经过com.atlassian.jira.mail.builder.RenderingMailQueueItem#send  ->com.atlassian.jira.mail.builder.EmailRenderer#render()
可见该方法可分别通过this.renderEmailSubject(this.templateParameters)方法渲染主题subject和通过`this.renderEmailBody(this.templateParameters);`渲染emailbody。
我们首先分析com.atlassian.jira.mail.builder.EmailRenderer#renderEmailSubject。
this.subjectTemplate中的content为表单中的subject值,即velocity待渲染的poc。
然后经以下流程进入com.atlassian.jira.template.velocity.DefaultVelocityTemplatingEngine.DefaultRenderRequest#toWriterImpl方法:
最终进入org.apache.velocity.app.VelocityEngine#evaluate(org.apache.velocity.context.Context, java.io.Writer, java.lang.String, java.lang.String)实现velocity渲染,触发漏洞。
我们再返回来看看能否通过com.atlassian.jira.mail.builder.EmailRenderer#renderEmailBody()渲染Emailbody。
通过代码可见待渲染的内容是`this.bodyTemplate`。而回溯this.bodyTemplate内容,是通过com.atlassian.jira.mail.builder.EmailBuilder#withBodyFromFile方法设置EmailBuilder对象的bodyTemplate属性为`templates/email/html/contactadministrator.vm`模板文件。该文件不可控,因此无法实现模板注入利用。若能覆盖该模板文件,同样能实现velocity模板注入。


 04  漏洞修复 


升级高版本,以8.20.5版本为例看看高版本是如何修复该漏洞的。
定位到com.atlassian.jira.web.action.user.ContactAdministrators#sendTo()方法,这里以withSubject("$subject")方式渲染主题,从而避免漏洞触发的可能性。但是,如果在templates/email/html/contactadministrator.vm文件可控,仍然可通过withBodyFromFile()加载模板文件从而实现模板注入利用。但难度很大,修改指定文件很难实现。
同时,在使用velocity渲染时设置了黑名单检查待调用的类是否在黑名单内。验证类的关键代码定位到org.apache.velocity.util.introspection.SecureIntrospectorImpl#getMethod():
通过checkObjectExecutePermission()方法判断待调用的类是否在黑名单内,黑名单将从velocity.properties配置文件中读取并载入this.badPackages和this.badClasses中。
在8.20.5版本中,this.badPackages内容为:
this.badClasses包含:
可见常用的类,例如java.lang.Class、java.lang.ClassLoader、org.springframework.expression.spel.standard.SpelExpressionParser等均在黑名单内。因此,即使上面提到的模板文件可控,也得绕过黑名单才可成功利用。
另外,与该漏洞几乎同样原理,即在邮件队列发送过程中触发velocity模板注入漏洞还有CVE-2021-39115和CVE-2021-43947两个漏洞,其中CVE-2021-39115是修改模板文件,即上文提到的在withBodyFromFile()处进行渲染的利用。而CVE-2021-43947是对CVE-2021-39115关于velocity模板注入漏洞利用方式的绕过。


05  总 结 


以上是对Atlassian JIRA近两年关于Velocity SSTI漏洞的完整分析。Atlassian JIRA中自带很多vm文件需渲染,如果可修改其中的模板文件,例如CVE-2021-39115和CVE-2021-43947,则几乎都可模板注入利用,但其难点在于如何绕过velocity配置文件中的黑名单进行利用。






    启明星辰积极防御实验室(ADLab)





    ADLab成立于1999年,是中国安全行业最早成立的攻防技术研究实验室之一,微软MAPP计划核心成员,“黑雀攻击”概念首推者。截止目前,ADLab已通过CVE累计发布安全漏洞近1100个,通过 CNVD/CNNVD累计发布安全漏洞2000余个,持续保持国际网络安全领域一流水准。实验室研究方向涵盖操作系统与应用系统安全研究、移动智能终端安全研究、物联网智能设备安全研究、Web安全研究、工控系统安全研究、云安全研究。研究成果应用于产品核心技术研究、国家重点科技项目攻关、专业安全服务等。







您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存