cve-2019-11581 Atlassian Jira未授權服務端模板注入漏洞
漏洞描述
Atlassian Jira是澳大利亞Atlassian公司的一套缺陷跟蹤管理系統。該系統主要用於對工作中各類問題、缺陷進行跟蹤管理。
Atlassian Jira Server和Jira Data Center存在服務端模板注入漏洞,成功利用此漏洞的攻擊者可在執行受影響版本的Jira Server或Jira Data Center系統上執行任意命令。
目前PoC已放出,建議受影響的客戶儘快升級或採用臨時緩解措施。
-
第一種情況,Jira服務端已配置好SMTP伺服器,且“聯絡管理員表單”功能已開啟(預設配置不開啟);
-
第二種情況,Jira服務端已配置好SMTP伺服器,且攻擊者具有"JIRA管理員"的訪問許可權。在第一種情況下,“聯絡管理員表單”功能開啟的情況下,攻擊者可以未經任何認證,通過向
/secure/ContactAdministrators.jspa
發起請求利用此漏洞。在第二種情況下,攻擊者具有"JIRA 管理員"的訪問許可權下可通過/secure/admin/SendBulkMail!default.jspa
利用此漏洞。
影響版本
-
4.4.x
-
5.x.x
-
6.x.x
-
7.0.x
-
7.1.x
-
7.2.x
-
7.3.x
-
7.4.x
-
7.5.x
-
7.6.x < 7.6.14
-
7.7.x
-
7.8.x
-
7.9.x
-
7.10.x
-
7.11.x
-
7.12.x
-
7.13.x < 7.13.5
-
8.0.x < 8.0.3
-
8.1.x < 8.1.2
-
8.2.x < 8.2.3
修復版本
-
7.6.14
-
7.13.5
-
8.0.3
-
8.1.2
-
8.2.3
修復建議
升級到修復版本(7.6.14、7.13.5、8.0.3、8.1.2、8.2.3)。
漏洞簡析
第二種利用場景前提是拿到Jira管理員的許可權,利用條件較難滿足,這裡主要分析第一種情況。原因在於atlassian-jira/WEB-INF/classes/com/atlassian/jira/web/action/user/ContactAdministrators
未對Subject(郵件主題)處進行過濾,使用者傳入的郵件主題被當作template(模板)指令執行。在任何一種情況下,成功利用此漏洞的攻擊者都可在執行受影響版本的Jira Server或Jira Data Center的系統上執行任意命令。
第一種,未授權程式碼執行利用條件:Jira已配置好SMTP伺服器,且需開啟“聯絡網站管理員表單”功能。(從WEB介面設計上看,實際上如果沒配置SMTP伺服器,無法開啟此功能)
程式碼追蹤
以Jira Server 7.13.0版本為例。
HTTP請求中的payload如何傳入到服務端的subject物件中?
在com.atlassian.jira.config.webwork.JiraActionFactory$SafeParameterSettingActionFactoryProxy#getActionImpl
中呼叫setActionParameters
方法,通過
webwork.action.ActionContext.getParameters();
拿到HTTP請求的各個引數。
參考:https://docs.atlassian.com/DAC/javadoc/opensymphony-webwork/1.4-atlassian-17/reference/webwork/action/ActionContext.html 通過反射呼叫com.atlassian.jira.web.action.user.ContactAdministrators
物件的setSubject(java.lang.String)
方法,並將HTTP請求中的Subject引數傳入進去。 設定完之後,com.atlassian.jira.web.action.user.ContactAdministrators
物件的subject屬性已被設定成我們的payload。
payload如何傳入到郵件物件的Subject中被Velocity模板引擎解析?
部分呼叫過程為:
...
=> com.atlassian.jira.web.action.user.ContactAdministrators#doExecute
=> com.atlassian.jira.web.action.user.ContactAdministrators#send
=> com.atlassian.jira.web.action.user.ContactAdministrators#sendTo
=> com.atlassian.jira.mail.builder.Email.Builder#withSubject(使用者可控的Subject模板)
=> com.atlassian.jira.mail.builder.Email.Builder#renderLater
...
看具體程式碼
protected String doExecute() throws Exception { if (!this.getShouldDisplayForm()) { //若“聯絡管理員表單”功能已開啟,則進入else邏輯
return "modebreach";
} else { this.send(); return this.getRedirect("/secure/MyJiraHome.jspa");
}
} public boolean getShouldDisplayForm() { //判斷“聯絡管理員表單”功能是否開啟
return this.jiraContactHelper.isAdministratorContactFormEnabled();
}
在send方法中,遍歷系統所有管理員賬號,看是否存在已啟用的管理員,若至少有一個(administrator.isActive()
),則傳入該管理員物件,呼叫:this.sendTo(administrator)
。
public void send() throws MailException {
Collection<ApplicationUser> administrators = this.userUtil.getJiraAdministrators(); // 遍歷系統所有管理員賬號,看是否存在已啟用的管理員
Iterator var2 = administrators.iterator(); while(var2.hasNext()) {
ApplicationUser administrator = (ApplicationUser)var2.next(); if (administrator.isActive()) {//若至少有一個
this.sendTo(administrator);//傳入該管理員物件
}
}
}
在sendTo中,
private void sendTo(ApplicationUser administrator) throws MailException { try {
Map<String, Object> velocityParams = Maps.newHashMap(); //from為客戶端指定的郵箱地址,會校驗郵箱格式
velocityParams.put("from", this.replyTo);
velocityParams.put("content", this.details);
velocityParams.put("padSize", PADSIZE); //獲取該傳入管理員的email地址,作為收件郵箱
Email email = new Email(administrator.getEmailAddress());
email.setReplyTo(this.replyTo); //將payload傳入郵件傳送佇列
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);
}
}
com.atlassian.jira.mail.builder.EmailBuilder
物件 通過withSubject(this.subject)
方法傳入使用者指定的模板(template)命令,作為Subject(主題),
這裡的payload是subjectTemplate,一個TemplateSource$Fragment
物件。然後呼叫renderLater()
,在atlassian-jira/WEB-INF/classes/com/atlassian/jira/mail/builder/EmailBuilder
中,
public MailQueueItem renderLater() { return new RenderingMailQueueItem(this.createEmailRenderer());
}
private EmailRenderer createEmailRenderer() { return new EmailRenderer(this.email, this.subjectTemplate, this.bodyTemplate, this.attachments, this.templateParameters);
}
將payload傳入,得到一個com.atlassian.jira.mail.builder.EmailRenderer
物件,然後把這個EmailRender物件作為引數構造com.atlassian.jira.mail.builder.Email.RenderingMailQueueItem
物件。而RenderingMailQueueItem繼承了com.atlassian.mail.queue.SingleMailQueueItem
類。在其構造器中,呼叫父類構造器
SingleMailQueueItem 又繼承了AbstractMailQueueItem類。
至此,一個RenderingMailQueueItem
物件已經構造完成, 得到了一個com.atlassian.mail.queue.MailQueueItem
(這是一個介面)物件,然後將該物件加入到郵件傳送佇列com.atlassian.mail.queue.MailQueue
中。輪到這個物件對應的郵件傳送時,才會渲染這個待發郵件的Subject(主題),所以可能會有一定的延遲。
郵件傳送執行緒
在啟動郵件佇列的執行緒中,呼叫棧如下:
renderEmailSubject:87, EmailRenderer (com.atlassian.jira.mail.builder)
render:149, EmailRenderer (com.atlassian.jira.mail.builder)
send:29, RenderingMailQueueItem (com.atlassian.jira.mail.builder)
sendBufferUnderLock:103, MailQueueImpl (com.atlassian.mail.queue)
sendBuffer:56, MailQueueImpl (com.atlassian.mail.queue)
apply:51, JiraMailQueue$1 (com.atlassian.jira.mail)
apply:48, JiraMailQueue$1 (com.atlassian.jira.mail)
runWithStaticBaseUrl:110, DefaultVelocityRequestContextFactory (com.atlassian.jira.util.velocity)
runWithStaticBaseUrl:50, DefaultBaseUrl (com.atlassian.jira.util)
sendBuffer:48, JiraMailQueue (com.atlassian.jira.mail)
run:21, MailQueueService (com.atlassian.jira.service.services.mail)
run:68, JiraServiceContainerImpl (com.atlassian.jira.service)
runService:62, ServiceRunner (com.atlassian.jira.service)
runServiceId:44, ServiceRunner (com.atlassian.jira.service)
runJob:32, ServiceRunner (com.atlassian.jira.service)
runJob:153, JobLauncher (com.atlassian.scheduler.core)
launchAndBuildResponse:118, JobLauncher (com.atlassian.scheduler.core)
launch:97, JobLauncher (com.atlassian.scheduler.core)
launchJob:443, CaesiumSchedulerService (com.atlassian.scheduler.caesium.impl)
executeLocalJob:410, CaesiumSchedulerService (com.atlassian.scheduler.caesium.impl)
executeQueuedJob:388, CaesiumSchedulerService (com.atlassian.scheduler.caesium.impl)
consume:285, CaesiumSchedulerService$1 (com.atlassian.scheduler.caesium.impl)
consume:282, CaesiumSchedulerService$1 (com.atlassian.scheduler.caesium.impl)
executeJob:65, SchedulerQueueWorker (com.atlassian.scheduler.caesium.impl)
executeNextJob:59, SchedulerQueueWorker (com.atlassian.scheduler.caesium.impl)
run:34, SchedulerQueueWorker (com.atlassian.scheduler.caesium.impl)
run:745, Thread (java.lang)
主要看前面三個,
renderEmailSubject:87, EmailRenderer (com.atlassian.jira.mail.builder)render:149, EmailRenderer (com.atlassian.jira.mail.builder)send:29, RenderingMailQueueItem (com.atlassian.jira.mail.builder)
在RenderingMailQueueItem
的send方法中,呼叫了EmailRender的render
方法
在atlassian-jira/WEB-INF/classes/com/atlassian/jira/mail/builder/EmailRenderer
中:
render
=>renderEmailSubject
=>getTemplatingEngine().render(this.subjectTemplate).applying(contextParams).asPlainText();
使用預設的模板引擎對payload(Velocity模板)進行解析。
注:我們的payload物件
subjectTemplate
是一個com.atlassian.jira.template.TemplateSource$Fragment
物件,通過之前的EmailRender的withSubject(this.subject)
方法傳入。而EmailRender的subject私有成員變數是通過反射呼叫ContactAdministrators
的setSubject()
方法從HTTP請求中傳入(前面已分析)。
先是getTemplatingEngine()
得到一個com.atlassian.jira.template.velocity.DefaultVelocityTemplatingEngine
物件,然後呼叫render()
方法: 呼叫applying
生成一個org.apache.velocity.VelocityContext
物件。 呼叫
asPlainText()
=>asPlainText(StringWriter)
=>toWriterImpl()
=>writeEncodedBodyForContent()
=>VelocityEngine.evaluate()
其中fragment.getContent()就是我們的payload,傳入進writeEncodedBodyForContent方法的第二個引數
再作為VelocityEngine#evaluate()的第四個引數,在作業系統上成功執行命令。
具體到Velocity的API呼叫棧可以在catalina日誌裡看到。
下圖顯示啟動的計算器程式為Jira的子程式。
漏洞修復
下載7.13.5版本程式碼,對比atlassian-jira/WEB-INF/classes/com/atlassian/jira/web/action/user/ContactAdministrators.java
檔案
雖然使用者輸入的Subject為惡意payload,作為引數傳進了 atlassian-jira/WEB-INF/classes/com/atlassian/jira/web/action/user/ContactAdministrators
物件, 但是其subjectTemplate為硬編碼的模板$subject
,並沒有將使用者傳入的payload直接傳入這裡的withSubject方法。
於是無法在這裡觸發。
Demo
無需認證觸發
實際觸發時間可能為幾秒到幾十秒(終於錄屏到一個快的作為演示...)
後臺管理員許可權觸發
緩解措施
若無法及時升級Jira,可採取以下緩解措施:
-
1、禁用”聯絡網站管理員“功能。設定=> 系統=> 編輯設定=> 聯絡管理員表單處選擇“關”,然後點選最下面的“更新”儲存設定。具體操作方式參考:https://confluence.atlassian.com/adminjiraserver/configuring-the-administrator-contact-form-974375905.html#Configuringtheadministratorcontactform-DisablingtheContactAdministratorsForm
驗證生效方法:訪問/secure/ContactAdministrators!default.jspa
出現:“您的Jira管理員尚未配置此聯絡表。”或“Your Jira administrator has not yet configured this contact form”。
-
2、並且,禁止對
/secure/admin/SendBulkMail!default.jspa
的訪問。
參考
-
https://confluence.atlassian.com/jira/jira-security-advisory-2019-07-10-973486595.html
-
https://jira.atlassian.com/browse/JRASERVER-69532
相關文章
- spark未授權RCE漏洞Spark
- mongodb未授權訪問漏洞MongoDB
- Redis未授權漏洞復現Redis
- 【漏洞復現】Redis未授權訪問漏洞Redis
- 服務端模板注入攻擊 (SSTI) 之淺析服務端
- Redis 未授權訪問漏洞利用Redis
- 利用redis未授權訪問漏洞(windows版)RedisWindows
- 銘說 | Redis未授權訪問漏洞GetshellRedis
- Redis未授權訪問漏洞利用總結Redis
- ECS的VPC服務授權
- Laravel 5 API 服務端支援簽名授權認證LaravelAPI服務端
- 系統滲透漏洞の未授權訪問
- 授權許可權服務設計解析
- Redis v6.0.5未授權訪問漏洞復現Redis
- Redis 未授權訪問漏洞(附Python指令碼)RedisPython指令碼
- 模板,從服務端到客戶端服務端客戶端
- XSLT 服務端注入攻擊服務端
- Hadoop Yarn REST API未授權漏洞利用挖礦分析HadoopYarnRESTAPI
- Mongodb未授權訪問漏洞全網探測報告MongoDB
- Java安全漏洞:Druid未授權訪問解決JavaUI
- Linux sudo 漏洞可能導致未經授權的特權訪問Linux
- 未授權網路音樂下線 服務商可多種方式收回成本
- 微服務中如何設計一個許可權授權服務微服務
- 利用CouchDB未授權訪問漏洞執行任意系統命令
- JBOSS未授權訪問
- 聊聊常見的服務(介面)認證授權
- 服務端模板注入:現代WEB遠端程式碼執行(補充翻譯和擴充套件)服務端Web套件
- 服務端技術方案模板參考服務端
- Atlassian釋出事故管理解決方案Jira Ops
- Laravel Blade模板 授權指令 @guestLaravel
- PbootCMS模板安裝與授權方法boot
- 從零開始學習各種常見未授權訪問漏洞
- 多款Intel產品未授權訪問漏洞(CVE-2017-5689)Intel
- 蘋果補上了可被未授權收集感測器資料的iPhone漏洞蘋果iPhone
- 網站漏洞修復服務商關於越權漏洞分析網站
- [BUG反饋]分類授權漏洞
- Windows遠端桌面服務漏洞預警通告Windows
- 遭遇Tomcat遠端拒絕服務漏洞Tomcat