原文鏈接:https://www.brokenbrowser.com/abusing-of-protocols/
原作者:Manuel Caballero
譯:Holic (知道創宇404安全實驗室)
在 10 月 25 日,研究員 @MSEdgeDev twitter 了一個鏈接,成功引起了我的注意,因為我點擊那個鏈接的時候(在 Chrome 上),Windows 應用商店會自動打開。這對你來說也許不足為奇,但它足以讓我感到驚訝。
在我的印象中,Chrome 有這樣一個健康的習慣,在打開外部程序之前詢問用戶是否打開外部程序。但是這次的情況是它直接打開了相應程序,而且沒有彈出警告。
這次的差別情況反應引起了我的注意,因為我從來沒有允許 Chrome 打開 Windows 商店。有一些插件和協議會自動打開,但我從來沒有允許過 Windows 商店這一應用。

Twitter 的短鏈接重定向至 https://aka.ms/extensions-storecollection ,然后再一次重定向到:ms-windows-store://collection/?CollectionId=edgeExtensions ,Interesting ~.
關于這一協議我不甚了解,因此我馬上試著找到與該協議存在多處關聯的地方:注冊表。搜索 “ms-windows-store” 立即返回了我們在 PackageId 中的字符串,這似乎是 Windows 應用商店的程序。

注意我們也在一個名為 “Windows.Protocol” 的鍵之中,我稍微上下滾動了一些,以便看看有沒有其他的應用程序在其中。然后我發現他們很多擁有自己的注冊協議。這便是極好的,因為這直接從瀏覽器打開了一個新的攻擊面。然后我們按 F3 看看是否找到了其他的匹配項。

似乎 ms-windows-store:協議也接受搜索參數,所以我們可以試著直接從 Google Chrome 打開我們的自定義搜索。事實上,Windows 應用商店應用程序好像使用了 Edge 的引擎渲染 HTML,這也是很有趣的地方,因為我們可能嘗試進行 XSS 攻擊,亦或是針對本地程序,發送一大堆數據然后看看會發生什么。

但是現在我們不會這么干,我們回到注冊表上來,按下 F3 看看能找到什么。

這也是很有意思的,因為如果它們用字符串 “URL:”前綴的話,它會給我們快速找到更多的協議的線索。讓我們將搜索重置為 “URL:”,看看我們得到什么。按下 [HOME] 鍵回到注冊表的頂部,搜索 “URL:” ,將馬上返回第一個匹配的 “URL:about:blank”,以及各位順便確認下我們有沒有瘋掉。
再次按下 F3 ,我們找到了 bingnews: 協議,但是這次 Chrome 向我們確認了是否要打開它。沒毛病,讓我們在 Edge 上試試看會發生什么。它打開了!在注冊表中下一個匹配的的是 calculator: 協議。這會生效嗎?

Wow!exploit 的作者們肯定好氣啊。它們將彈出什么程序呢?calc 和 notepad 可以打開,而且沒有產生內存損壞。現在 cmd.exe 已經棄用,而是采用了 powershell。微軟毀了你們這群人的樂趣 ? 。
這便是枚舉所有可能被加載的協議的時候了,先去看看哪些程序接受參數,那么我們可以嘗試注入代碼(二進制或者純 Javascript,取決于應用程序的編碼方式和他如何處理參數)。有很多有趣的玩法,如果我們繼續尋找協議,我們將發現大量的能打開的程序(包括 Candy Crush,我還不知道我電腦上有這東西)。
通過按這幾次 F3 ,我受益匪淺。例如,有一個 microsoft-edge:協議在新標簽中加載 URL。這看起來似乎并不重要,直到我們想起 HTML 頁面應有的限制。彈出窗口攔截器會阻止我們打開 20 個 microsoft-edge:http://www.google.com 標簽嗎?

[ PoC – 在微軟 Edge 瀏覽器上彈窗 ]
那么 HTML5 沙箱又怎樣呢?如果你不熟悉它,它只是一種使用 iframe 沙箱屬性或者 http header 的沙箱屬性對網頁施加限制的方法。例如,如果我們想在 iframe 中渲染內容并且確保它不運行 javascript (甚至不打開新標簽),我們只需要使用此標簽:
<iframe src=”sandboxed.html” sandbox></iframe>
然后渲染的頁面將被完全限制。它基本上只能渲染 HTML/CSS ,但是沒有 javascript 或者其他訪問接觸到像 cookie 這樣的東西。事實上,如果我們使用沙盒粒度,并且至少允許打開新窗口/標簽,他們應該全都繼承沙箱屬性,以及從 iframe 點擊鏈接打開的依然受沙盒限制。然而,使用 microsoft-edge 協議完全繞過了這一點。

[ PoC – 在 微軟 Edge 瀏覽器上繞過 HTML5 沙箱 ]
很高興看到 microsoft-edge 協議允許我們繞過不同的限制。我更深入研究,但你可以一試!這是一次發現之旅,紀念這一條 tweet 激發了我研究的動力,而且最終給我們真正值得進行更多研究的材料。
我繼續在注冊表中按下 F3 鍵,發現了 read: 協議,它引起了我的注意力,因為當閱讀它的 (javascript)源碼時,它可能有潛在的 UXSS 漏洞,但是嘗試的過程中 Edge 一次次地崩潰了。它崩潰太多次了。例如,將 iframe 的 location 設置為 “read:” 就足以使瀏覽器崩潰,包括所有選項卡。想看看嗎?
[ PoC – Crash on MS Edge ]
OK,我很好奇發生了什么,所以我附加了幾個字節到 read 協議,并啟動了 WinDbg 看看崩潰是不是和無效數據有關。這些東西迅速且簡單,沒有 fuzzing 或任何特殊的東西:read:xncbmx,qwieiwqeiu;asjdiw!@#$%^&*。
Oh yes,我真的打出來了這些東西。我發現的不會使 read 協議崩潰的唯一方法就是加載來自 http[s]的東西。其他的方法都會使瀏覽器崩潰。
那么讓我們將 WinDbg 附加至 Edge 瀏覽器吧。有一個快速的臟方法,我使用它來簡單地殺死 Edge 進程和子進程,重新打開它并附加到使用 EdgeHtml.dll 的最新進程。當然還有更簡單的方法,但是...yeah,我就是這么做的。打開命令行,然后...
taskkill /f /t /im MicrosoftEdge.exe
** Open Edge and load the webpage but make sure it doesn't crash yet **
tasklist /m EdgeHtml.dll
夠了。現在加載 WinDbg ,并將其附加到使用 EdgeHtml 的,最新列出的 Edge 進程。記得在 WinDbg 中使用調試符號。

一旦附加上去,只需要按 F5 或者在 WinDbg 中按 g [回車],使 Edge 保持運行。這是我屏幕現在看起來的樣子。左邊有我用來測試一切的頁面,在右邊, WinDbg 附加到特定的 Edge 進程。

我們將使用 window.open 伴以 read: 協議繼續玩耍,而不是一個 iframe ,因為它使用起來更舒服。仔細想想,有的協議/url 可能會最終改變頂部 location,無論它們如何使用框架。
如果我們開始在 iframe 中使用協議,我們自己的頁面(頂部)將有可能被卸載,失去我們剛剛鍵入的代碼。我特定的測試頁面保存了我鍵入的內容,如果瀏覽器崩潰,它很可能被恢復。但即使一切都保存下來了,當我編寫一些可以改變我測試頁面的 URL 的代碼時,我就在一個新窗口中打開它。這只是一種習慣罷了。
在左側屏幕上,我們可以快速鍵入并執行 JavaScript 代碼,右側有 WinDbg 準備向我們解釋在崩潰的背后到底發生了什么。我們繼續,運行 JavaScript 代碼以及... Bang! WinDbg 中斷了連接。
ModLoad: ce960000 ce996000 C:\Windows\SYSTEM32\XmlLite.dll
ModLoad: c4110000 c4161000 C:\Windows\System32\OneCoreCommonProxyStub.dll
ModLoad: d6a20000 d6ab8000 C:\Windows\SYSTEM32\sxs.dll
(2c90.33f0): Security check failure or stack buffer overrun - code c0000409 (!!! second chance !!!)
EdgeContent!wil::details::ReportFailure+0x120:
84347de0 cd29 int 29h
OK,看來 Edge 知道出了問題,因為它位于一個叫做 “ReportFailure” 的函數中,對吧?得了,我知道我們可以馬上假設,如果 Edge 在此崩潰,不至于有失“優雅”。所以我們檢查 stack trace 來看看我們調用自何方。在 WinDbg 中輸入 “k” 。
0:030> k
# Child-SP RetAddr Call Site
00 af248b30 88087f80 EdgeContent!wil::details::ReportFailure+0x120
01 af24a070 880659a5 EdgeContent!wil::details::ReportFailure_Hr+0x44
02 af24a0d0 8810695c EdgeContent!wil::details::in1diag3::FailFast_Hr+0x29
03 af24a120 88101bcb EdgeContent!CReadingModeViewerEdge::_LoadRMHTML+0x7c
04 af24a170 880da669 EdgeContent!CReadingModeViewer::Load+0x6b
05 af24a1b0 880da5ab EdgeContent!CBrowserTab::_ReadingModeViewerLoadViaPersistMoniker+0x85
06 af24a200 880da882 EdgeContent!CBrowserTab::_ReadingModeViewerLoad+0x3f
07 af24a240 880da278 EdgeContent!CBrowserTab::_ShowReadingModeViewer+0xb2
08 af24a280 88079a9e EdgeContent!CBrowserTab::_EnterReadingMode+0x224
09 af24a320 d9e4b1d9 EdgeContent!BrowserTelemetry::Instance::2::dynamic
0a af24a3c0 8810053e shlwapi!IUnknown_Exec+0x79
0b af24a440 880fee33 EdgeContent!CReadingModeController::_NavigateToUrl+0x52
0c af24a4a0 88074f98 EdgeContent!CReadingModeController::Open+0x1d3
0d af24a500 b07df508 EdgeContent!BrowserTelemetry::Instance'::2::dynamic
0e af24a5d0 b0768c47 edgehtml!FireEvent_BeforeNavigate+0x118
看看前兩行,都叫做 blah blah ReportFailure ,你不覺得 Edge 是因為出現錯誤了嗎才運行到這里的嗎?當然!讓我們繼續運行下去,直到我們找到一個有意義的函數名。下一個叫做 blah FallFast,這便有一些 Edge 知道出現錯誤才會調用它的味道。但是我們想找到使 Edge 出現問題的代碼,那么繼續讀下去吧。
下一個是 blah _loadRMHTML。這個對我來說看起來好多了,你難道不也這么認為嗎?事實上,他的名字讓我覺得它是加載 HTML 的。在崩潰之前斷下程序的話,這將會變得有意思多了,所以為什么不在 _LoadRMHTML 上面幾行設置斷點呢?我們檢查了 stack-trace,現在我們來看看代碼。
我們先從那個斷點(函數+偏移)查看反匯編。這很簡單,在 WinDbg 中使用 “ub” 命令。
0:030> ub EdgeContent!CReadingModeViewerEdge::_LoadRMHTML+0x7c
EdgeContent!CReadingModeViewerEdge::_LoadRMHTML+0x5a:
8810693a call qword ptr [EdgeContent!_imp_SHCreateStreamOnFileEx (882562a8)]
88106940 test eax,eax
88106942 jns EdgeContent!CReadingModeViewerEdge::_LoadRMHTML+0x7d (8810695d)
88106944 mov rcx,qword ptr [rbp+18h]
88106948 lea r8,[EdgeContent!`string (88261320)]
8810694f mov r9d,eax
88106952 mov edx,1Fh
88106957 call EdgeContent!wil::details::in1diag3::FailFast_Hr (8806597c)
我們只關注名字,忽略其他東西,好伐?就像我們在《trying to find a variation for the mimeType bug》中一樣,我們在此投機取巧,當然如果我們失敗了就繼續深入。但有時在調試器上的快速查看能夠闡明很多事情。
我們知道如果 Edge 到達這個片段的最后一條指令(地址為 88106957,FailFast_Hr),Edge 就會崩潰掉。我們的目標是弄清我們最終運行到的地方,就是說誰把我帶到那里的。上面的代碼的第一條指令似乎是調用了一個復雜名稱的函數,這顯然大量體現了我們的東西。
EdgeContent!_imp_SHCreateStreamOnFileEx
在 ! 前的第一部分是該指令所在的模塊(exe,dll等等...)。這種情況下是 EdgeContent ,我們甚至不關心它的擴展名,它只是一段代碼。! 之后有個有趣的函數名叫_imp_ ,然后 SHCreateStreamOnFileEx 似乎是一個“創建文件流”的函數名。你同意嗎?事實上,_imp_的部分讓我想起這可能是從不同的二進制文件加載的導入函數。讓我 google 一下這個名字,看看能不能找到有趣的東西。

這太棒了。第一個結果正是我們搜索的準確名稱。讓我們來點擊一下。

好。此函數接收的第一個參數是 “A pointer to a null-terminated string that specifies the file name”(指向以空字符結尾的字符串指針,該字符串指定文件名) 。因垂絲挺!如果這段代碼正被執行,那么它應該接收一個指向文件名的指針作為第一個參數。但是我們這么能看到第一個參數呢?很簡單,我們在 Win x64上運行,調用約定/參數解析說,“前四個參數是 RCX, RDX, R8, R9 ”(表示整數/指針)。這意味著第一個參數(指向文件名的指針)將被裝載入 RCX 寄存器。
有了這些信息,我們可以在 Edge 調用之前設置一個斷點,看看 RCX 在那個確定時刻有何值。但是我們重新啟動一遍程序吧,因為這時已經有點遲了:Edge 已經崩潰了。請重新按照上面描述的做一遍(殺掉 Edge 進程,打開它,加載頁面,找到進程并附加上去)。
這個時候,不要運行(F5)進程,我們先設置一個斷點。WinDbg 顯示了我們執行 “ub” 命令時的確切偏移量。
0:030> ub EdgeContent!CReadingModeViewerEdge::_LoadRMHTML+0x7c
EdgeContent!CReadingModeViewerEdge::_LoadRMHTML+0x5a:
8810693a ff1568f91400 call qword ptr [EdgeContent!_imp_SHCreateStreamOnFileEx (882562a8)]
88106940 85c0 test eax,eax
所以斷點應該在 EdgeContent!CReadingModeViewerEdge :: _ LoadRMHTML 0x5a 處。我們鍵入 “bp” 和函數名 + 偏移[回車]。然后 “g” 讓 Edge 繼續運行。
0:029> bp EdgeContent!CReadingModeViewerEdge::_LoadRMHTML+0x5a
0:029> g
這很一顆賽艇。在 SHCreateStreamOnFileEx 執行之前,我們想要看到 RCX 指向的文件名(或者字符串)。我們運行代碼,稍適小憩。好吧,寶寶我感受到它了 =) 斷點連至我的童年。讓我們運行這段 JavaScript 代碼吧,bang!WinDbg 在此中斷。
Breakpoint 0 hit
EdgeContent!CReadingModeViewerEdge::_LoadRMHTML+0x5a:
8820693a ff1568f91400 call qword ptr [EdgeContent!_imp_SHCreateStreamOnFileEx (883562a8)]
這太棒了,現在我們可以檢查 RCX 指向的內容。為此我們使用 “d” 命令(顯示內存)@ 加上寄存器名稱,如下所示:
0:030> d @rcx
02fac908 71 00 77 00 69 00 65 00-69 00 77 00 71 00 65 00 q.w.i.e.i.w.q.e.
02fac918 69 00 75 00 3b 00 61 00-73 00 6a 00 64 00 69 00 i.u.;.a.s.j.d.i.
02fac928 77 00 21 00 40 00 23 00-24 00 25 00 5e 00 26 00 w.!.@.#.$.%.^.&.
02fac938 2a 00 00 00 00 00 08 00-60 9e f8 02 db 01 00 00 *.......`.......
02fac948 10 a9 70 02 db 01 00 00-01 00 00 00 00 00 00 00 ..p.............
02fac958 05 00 00 00 00 00 00 00-00 00 00 00 19 6c 01 00 .............l..
02fac968 44 14 00 37 62 de 77 46-9d 68 27 f3 e0 92 00 00 D..7b.wF.h'.....
02fac978 00 00 00 00 00 00 08 00-00 00 00 00 00 00 00 00 ................
這對我的眼睛很不友好,但在第一行的右邊,我看到了一些類似于 Unicode 字符串的東西。我們將它顯示為Unicode字符吧(du 命令)。
0:030> du @rcx
02fac908 "qwieiwqeiu;asjdiw!@#$%^&*"
Nice!字符串將我包圍!看看我們剛才運行的 JavaScript 代碼。

看來,傳給這個函數的參數是==逗號==后面輸入的任何內容。有了這點知識加上知道它期望獲取一個文件名,我們可以嘗試一個在硬盤上的完整的路徑。因為 Edge 在 AppContainer 內部運行,我們將嘗試一個可訪問的文件。例如來自 windows/system32 目錄的內容。
read:,c:\windows\system32\drivers\etc\hosts
我們同時刪除逗號之前的垃圾數據,看起來似乎無關緊要(雖然他值得進行進行更多研究)。我們快速分離,重啟 Edge,并運行我們的新代碼。
url = "read:,c:\\windows\\system32\\drivers\\etc\\hosts";
w = window.open(url, "", "width=300,height=300");
如預期所想,在新窗口中加載本地文件并沒有崩潰。

[ PoC – Open hosts on MS Edge ]
遵循 bug hunter,我將在此停頓,但我相信所有的這些值得進一步的研究,取決于你的興趣了:
A)枚舉所有可加載的協議,并通過查詢字符串攻擊應用程序
B) 調戲 microsoft-edge: 繞過 HTML5 沙盒,彈出窗口攔截器和誰會知道的東西。
C) 繼續使用 read: 協議。我們找到了一種方法來阻止它崩潰,但記住有一個函數 SHCreateStreamOnFileEx ,我們能夠影響它的期望值!這值得更多的嘗試。此外,我們可以繼續對傳入參數進行研究,看看是否使用逗號分隔參數等等。如果調試二進制無聊至極,那么你仍然可以嘗試對閱讀視圖進行 XSS。
希望你能找到成噸的漏洞!如果你有問題,請在@magicmac2000 上 ping 我。
Have a nice day!
Reported to MSRC on 2016-10-26
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.jmbmsq.com/125/
暫無評論