原文:brokenbrowser
原作者: Manuel Caballero
譯:Holic (知道創宇404安全實驗室)

今天我們探索 Microsoft Edge 上的另一個 SOP 繞過,而此處 data/meta 標簽的濫用,側面證實了無域頁面是可以隨意訪問有域的頁面的。

著急嗎?可以先看這 59 秒的視頻,其中我們代表 Charles Darwin 發了條推特,或者,觀看我們手動發推并抓取用戶的密碼(利用了 Microsoft Edge 的默認密碼管理器)。Charles Darwin 是一個案例,該漏洞可以讓攻擊者用已經登錄的用戶的名義發推(或是更多的事情)。欲知詳情如何,請繼續閱讀。

如果你第一次看本博客,我建議你先閱讀這兩篇 SOP 繞過的文章: Adventures in a Domainless World (Edge)More Adventures in a Domainless World (IE)。后續文章基于相同的思路,只是用了一點新技術。

(對應 Paper 譯文:http://www.bjnorthway.com/143/ 和 http://www.bjnorthway.com/254/ )

接下來快速回顧一個重要概念:about:blank 始終是其 referrer 的域,意味著來自 Twitter 的 about:blank iframe 不能訪問 google 的 blank 頁面。即使他們之間的地址是匹配的(about:blank),document.domain 卻是不同的。

過去,我們無須域名就能創建 about:blank ,或者無域的 about:blank。那些都有權訪問每個 about:blank 而無視其域。比如,假設我們在主頁上有一個無域的 blank,渲染了一個指向 Twitter,另一個指向 google 的 iframe。那些 iframe 中同樣有空的子 iframe,其域當然也是 twitter 和 google。在這種情況下,頂部窗口可以訪問有域的空頁面,意味著可以訪問 google 和 Twitter 的 DOM 了。

上述情景效果很好,但是微軟三個月前用一個很機智的技巧 修復了這個 bug:無域的 blank 已經不再是無域的了,而被設置為其域名的 GUID,比如{53394a4f-8c04-46ab-94af-3ab86ffcfd4c}。還有一些更有意思的東西(向微軟開發者致敬):域看起來像是空的,其實不是。換句話說,Edge 隱藏 GUID 并返回空,而在其內部仍是 GUID。

試一下便知!打開 Edge 啟用 Devtools(F12),然后在地址欄輸入 about:blank。用于創建一個無域的空白頁面,它仍然看起來沒有變化,這是 Edge 在給我們上演戲法。請稍事欣賞,我們有足夠的時間打破它的魔咒。

如你所見,DevTools 認為我們在空域之下,其實并不是。

打破魔咒

如果就連 DevTools 都被欺騙了,又如何了解其中發生了什么呢?比想象中簡單,僅需嘗試加載有相對路徑的東西,或者改變 window 的 location,甚至 document.write 都會揭露這個把戲。使用 location.href=1,看看會發生什么。

頂層 data:uri 被修復以及 Flash 禁用的情況

我們之前創建無域空白頁面的技術已修復。我們也曾借助 Flash/GetURL 在主(頂層) window 上設置 data:uri。而這些技巧都被修復了,更糟糕的是,已經不會自動運行 Flash 了!Windows 創意者更新中,運行 Flash 之前 Edge 會請求權限。

注意,捉蟲獵手!之前文章的 PoC現在看起來很不美觀!表揚下 Edge 團隊,這一措施減少了攻擊面。

尋找新的無域空頁面

針對頂層的 data:uri 技巧已經沒有用了,那么我們又如何攻克呢。首先,我先研究 iframe 而不是頂層,因為我們在過去看到,Edge 不喜歡主窗口的 data:uri。

top.location.href = "data:text/html,SOMETHING"; // Fails badly, error page

而將 data:uri 設置為 iframe 的 location 則頗為有效。但這并不是一個 bug,iframe 的域是與頂層隔離的。

正如在閱讀模式 SOP 繞過中看過的,data:uri 的『隔離』限制微不足道(僅一個 self document.write 就能訪問父頁面),但不是我們現在想要的。訪問頂層現在毫無意義,我們想要能訪問無域空白頁面方法。為此,我們需要三連擊:data-meta-data。然后重獲 Edge 那些修復的特性。

具體來說,我們使用 data uri 設置 iframe 的 location,該 uri 會渲染 meta 刷新,重定向至另一個 data uri。這都是我們和 Edge 忽略的地方。

創建無域空白頁面的方法:

  1. 設置 iframe 的 location 為 data:uri

  2. data:uri 渲染了 meta refresh 標簽

  3. meta refresh 重定向至另一個 data:uri

我們構建一個 URL ,將常規的(有域)的 iframe 轉換為無域的。如果在腦海中不斷重復『data-meta-data』,會更容易一些,因為...實際就是這樣。

我知道它沒有 E=mc2 那么漂亮,但是這一技巧可以用來偷取愛因斯坦的登錄憑據,電子郵件,PayPal 賬戶,甚至以他的名義發推。我們先測試所學的技巧,直到這點生效為止。我們用 bing.com 做演示,頗為簡單,因為它內部有一個空白頁面的 iframe 而且不使用 XFO。

用 bing.com 熱身

我們將創建有兩個 iframe 的頁面:其一是 bing.com ,另一個是無域的。無域頁面將在 bing 內部的blank iframe 中執行代碼。Bing 圖片正是我們想要的。我先打開 Chrome 展示下我想表達的意思。

很不錯。現在我們借助無域的 data-meta-data 構建頁面并將代碼注入到 blank iframe 中。但有一些話我還沒講。你還記得在那篇 domainless SOP 中用 nature.com 演示的命名問題嗎?若是沒有,我給你快速回顧一下。

這一點上,我們的無域 iframe 能夠訪問 bing 中的 blank 頁面,而訪問機制尤其重要。我們不能直接訪問 DOM,必須使用 window.open 方法。換句話說,我們無法以這種方式訪問 iframe 的內部:

alert(top[0][0].document.cookie); // ACCESS DENIED

其實我們甚至不能這樣做:

top[0][0].location.href = "javascript:alert(document.cookie)"; // ACCESS DENIED

那我們應該怎么辦呢?很簡單,利用 JavaScript url 和 iframe 的名稱(name 屬性,后統稱名稱)打開窗口。如果 bing 內部 iframe 名稱為 "INNER_IFRAME",以下代碼將運行正常。

window.open("javascript:alert(document.cookie)", "INNER_IFRAME"); // SOP BYPASSED!

可惡, Bing 中嵌套的 iframe 沒有名稱(name)!不要驚慌,要么我們請求 Bing 團隊為我們設置一個名稱,要么繼續推進。更好地繼續推進!

設置 iframe 的名稱(name)

我們不能設置不屬于我們的 iframe 的名稱,除非它與我們在同一個域中。然后要渲染一個內有 blank 頁面的 iframe。外部 iframe 屬于不同的域,但標簽本身(元素,對象)位于我們的域中,因此我們可以設置我們想要的任何名稱。

<iframe name="ANY_NAME" src="http://bing.com">
   <iframe src="about:blank"></iframe>
</iframe>

而內部 iframe 是通過 bing 渲染的,即使它是空白頁面,更改它名稱的方法也只能是將其 location 設置為我們可以訪問的,然后才能更改其名稱。如果現在改變 about:blank 的 location,無異于搬石頭砸腳,因為我們需要改成 bing.com 以便之后訪問無域的頁面。

記住,我們的目標是利用無域的空白頁面訪問一個有域的頁面。若是將域設置為相同的,那么這種訪問毫無意義。因此我們要做的就是:設置 location,更改 iframe 的名稱,然后把 location 恢復回來,使其保持原始的域。聽起來挺復雜的?

設置x-domain-iframe 的 name:

  1. 將 iframe 的 location 設置為 about:blank,將其域更改為可控的 crack.com.ar
  2. 隨意更改 iframe 的名稱。
  3. 再把 location 改回來,但這次使用 meta refresh,使其域==其創建者:bing.com 。

就醬。現在內部 iframe 有了名稱,它的域也恢復到了 bing.com!代碼如下:

// Sets the location of Bing's inner iframe to about:blank
// But now it is in our domain so we can set a name to it.
window[0][0].location = "about:blank";

// Set the inner iframe name to "CHARLES" so we can later inject code
// using a window.open("javascript:[...]","CHARLES");
window[0][0].name = "CHARLES";

// Restore Bing's domain to the about:blank that we've just renamed.
window[0][0].document.write('<meta http-equiv="refresh" content="0;url=about:blank">');
window[0][0].document.close();

好消息是:我們并不需要帶有"about:blank" iframe 的網站,因為按照以上方法就行了。換而言之, bing 的內部的 iframe 是不是 about:blank 并不重要,因為我們最后都能用它原來的域將其設為 blank!我不知道你怎么想的,捉蟲獵手,但我感覺這就像演員中的湯姆·漢克斯(Tom Hanks),看看便知

大門為我們敞開!我們可以從我們的 data-meta-data iframe 中運行 window.open:

window.open("javascript:alert(document.cookie)", "CHARLES"); // Fireeeeeeeeeee!!!

[Test the PoC Live on Edge]

[Video in YouTube]

有關 PoC 的一個重要事項:上述示例中,我們使用 http(不安全)連接,因為在 https(安全)中,meta refresh 是會被阻止的,所以不會重定向至最終的data uri。Edge 誤以為重定向是不安全的。然而,這點可以通過使用 document.write 取代 data uri 輕松繞過。所以將 data-meta-data 應該替換為 document.write(meta-data) 。是不是這個理?

在上述 PoC 中我沒有用到這點,因為它在進行演示交互時(你需要按下按鈕運行)Edge 有三分之一的幾率崩潰。所以我選擇使用 http 下可控且可靠的自動化 PoC 而沒在 HTTPS 下。無論如何,下面可以看到這并不重要:我們的不安全(http)無域空白頁面可以訪問安全的頁面,所以我們來構建一個真實的例子。

下面是攻擊演示了,捉蟲獵手。時光機帶我們飛到過去,把我們帶到有電腦和互聯網之前時代。查爾斯·達爾文在考慮物種隨時間的變化,阿爾弗雷德·華萊士也有類似的想法。查爾斯意識到黑客的存在,所以他只使用他自己的電腦,近乎偏執:他從來沒有使用同一個瀏覽器窗口打開他的 Gmail,Twitter 已經個人文檔。

看,他在任務欄打開了一個新的隱身窗口!

他心情不錯,直到他用新標簽打開了 Twitter 賬號,并向阿爾弗雷德·華萊士(Alfred Wallace)調侃誰先發推的消息。

幾分鐘后,華萊士帶著證件回應了他。但是別忘了,Charles不信任任何人,所以他復制了鏈接,將其粘貼至一個新的窗口中,遠離他個人數據(gmail,twitter)的窗口。

哪里錯了呢?一切!Twitter 有幾個 iframe,像大多數網站一樣。其實它有兩個名為 about:blank 的 iframe,所以這應該比 Bing 容易!但是回到故事之前,我們使用 DevTools 枚舉 Twitter 的 iframe,找到一個很好的方案。此處打開一個不同的窗口,與查爾斯的 session 無關。

很好!dm-post-iframe 貌似不錯,所以我們需要做的就是接管查理的帳戶了。

查爾斯打開一個新的隱身窗口,并加載了華萊士給他的網址。他不知道即使在隱身窗口,也是可以相互通信的。那么,如果我們在無域 iframe 下執行以下代碼,會發生什么?

window.open("javascript:alert(document.cookie)", "dm-post-iframe");

是的。我們獲得了達爾文的 cookie。

警告:以下 PoC 將會 alert(僅在您屏幕上顯示)您的 Twitter cookie。

[ Test the PoC Live on Edge ]

請記住,我們真的不需要 InPrivate 窗口。上面的例子說明了一個頗為偏執的情景,但通常情況更簡單,因為人們一般直接就點開鏈接了,不會像 Charles 那樣做。此外,考慮到攻擊者可能會使用惡意廣告,在熱門網站的廉價 banner 上部署惡意內容。如果攻擊者托管于雅虎 banner 內,用戶登錄她的 Twitter 賬戶,她就在無須交互的情況下受控了。

像達爾文一樣發推

來構造一個更好的 PoC 吧。這回不再讀取它的 cookie,我們會以他的名義發推,甚至抓取他的密碼。請記住,大多數用戶(比如 Charles)使用了密碼管理器自動填充密碼。Edge 密碼管理器不出其右,所以如果 Charles 保存了他的密碼,我們就能獲取到。這不是很難,只是強制讓他注銷,然后登陸頁面就會加載,其所有數據(用戶名與密碼)都在一個銀色播放器中呈現。實際上,這種情況如果用戶沒進行交互,表單是隱藏的。而 Edge 正進行填充,所以我們甚至不必讓表單可見。

在運行 PoC 之前,請記得這是你的賬戶,而不是 Charles 的。沒有其他東西會發送到網絡,如果你身后有人,她會在一個常規 alert 中看到你的密碼。請小心。

Video: Automatic Tweeting 1″
Video: Manual Tweeting 2″
Test the PoC Live on Edge

腦海中閃過的問題

我們可以在沒有 about:blank iframe 的站點使用這個技巧嗎?當然!我們甚至可以在沒有 iframe 的網站上使用。請閱讀這篇博文,inject an iframe on a different origin,而且在 IE 上也可以

在 Facebook 上也可以嗎?我沒有 Facebook 賬戶,所以沒有測試。但是 SOP bypass 可以訪問地球上的每個域。開發可能有點難,但不可能嗎?記住攻防安全研究員的口頭禪:再接再厲。

在其它瀏覽器中有效嗎?我沒有試過,但也不是不可能。UXSS / SOP 繞過往往針對特定瀏覽器。

下載所有 PoC

利用代碼很簡單,請仔細閱讀,如果你有問題,請問!到此為止,不然這個博客就叫 brokenmarriage.com 了。布宜諾斯艾利斯的深夜。

Have a nice day!


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/287/