Web標準安全性研究:對某數字貨幣服務的授權滲透

  • 2019 年 10 月 6 日
  • 筆記

表面下,現代Web只有通過不斷增長的技術標準才能實現。標準旨在管理技術和數據的互操作性。Web標準是最廣泛採用和快速發展的標準之一,其變化也經常引起瀏覽器供應商,Web開發人員和用戶之間的激烈爭論。

在這篇博文中,我們將詳細說明盲目遵從明確定義且普遍採用的Web標準所帶來的危害。我們將對一個知名的數字貨幣服務發動遠程攻擊,並」竊取其中所有的貨幣「以此來證明我們觀點的可靠性。

演示影片

Localhost Services(本地服務)

許多現代應用程式開始使用localhost 「api-servers」作為將程式邏輯與用戶介面分離的設計模式。這些服務會在127.0.0.1(localhost)上靜靜監聽,並將應用程式的核心邏輯作為一個與平台無關的遠程編程介面(RPC)進行無頭封裝。

C:WINDOWSsystem32>netstat -a -b    Active Connections    Proto  Local Address          Foreign Address        State    TCP    0.0.0.0:443            DESKTOP:0              LISTENING   [vmware-hostd.exe]    TCP    0.0.0.0:912            DESKTOP:0              LISTENING   [vmware-authd.exe]    TCP    0.0.0.0:5900           DESKTOP:0              LISTENING   [siad.exe]    TCP    0.0.0.0:49664          DESKTOP:0              LISTENING   [Spotify.exe]    TCP    0.0.0.0:57621          DESKTOP:0              LISTENING   [Discord.exe]    TCP    127.0.0.1:8307         DESKTOP:0              LISTENING   [siad.exe]    TCP    127.0.0.1:18171        DESKTOP:0              LISTENING   [Battle.net.exe]    TCP    127.0.0.1:27015        DESKTOP:0              LISTENING   [AppleMobileDeviceProcess.exe]    TCP    127.0.0.1:27060        DESKTOP:0              LISTENING   [Steam.exe]    TCP    127.0.0.1:52094        DESKTOP:0              LISTENING   [NVIDIA Web Helper.exe]

在過去的幾年裡,對這些localhost API服務的研究已發現了許多可遠程利用的問題。其中來自Google Project Zero的Tavis Ormandy的調查結果引人關註:

所有暴雪遊戲(魔獸世界,守望先鋒,暗黑破壞神III,星際爭霸II等)都易受到DNS重綁定漏洞的攻擊,允許任意網站運行任意程式碼。https://t.co/ssKyxfkuZo — Tavis Ormandy (@taviso) 2018年1月22日 以下是一系列uTorrent DNS重綁定漏洞(現已修復),從遠程程式碼執行到查詢和複製下載文件等等。https://t.co/JEvhq1IHGJ — Tavis Ormandy (@taviso) 2018年2月20日

最近的研究揭示了流行的影片會議應用程式Zoom中的一些可利用的問題

在加密貨幣領域,這種相同的「api-server」設計模式非常普遍。大量的區塊鏈項目在他們的貨幣守護進程中使用這種架構。這些守護進程負責管理用戶的加密錢包,執行事務以及與區塊鏈保持同步。

通常,面向用戶的GUI應用程式將連接到此本地服務,並將「high-level」概念(例如創建事務)轉換為守護進程通過其公開的API提供的「low-level」區塊鏈操作。此模型還允許高級用戶或第三方開發人員輕鬆編寫驅動,擴展或展示守護進程核心功能的程式碼。

Localhost 只是相對安全

將這些api-servers綁定且僅在127.0.0.1上運行,看上去似乎是一種安全且簡單的方法來防止應用程式(例如貨幣/錢包守護進程)暴露於互聯網和遠程攻擊。但遺憾的是,這並不總是一個安全的假設,特別是當與普通web瀏覽器共存時。

瀏覽網頁時,你的瀏覽器會下載並運行大量「『untrusted(不受信任)」的數據,以便在螢幕上為你呈現你喜愛的網站。通過擴展,在給定網站上發布的任何JavaScript都由本地電腦上的Web瀏覽器執行。這意味著遠程發起和惡意編寫的JavaScript可能會被用於在本地主機服務上進行探測。

將目光轉向 Siacoin

讓我們理論上的「預感」是,在瀏覽器內部執行的程式碼應該(原則上)能夠與本地服務進行交互,並且只需運行它。在接下來的部分,我們將攻擊Siacoin:一個知名的加密貨幣項目,旨在通過區塊鏈技術提供廉價,高效和去中心化的文件存儲。

我們的主要目標是成功執行對Sia/wallet/seed端點的API調用。在加密貨幣中,「wallet-seed(錢包種子)」是一個字元串,可用於重建與特定錢包相關聯的私鑰。如果你擁有了這個私鑰,那就擁有資金。

我們可以通過創建一個惡意網站來測試這一理論,該網站試圖從他們的本地守護進程中請求受害者的錢包種子:

但是我們的請求被阻止了!發生了什麼?

顯然,想通過瀏覽器攻擊本地主機服務並不容易。這是因為現代Web瀏覽器採用了一種稱之為」Same-Origin-Policy(SOP)「的保護策略。

SOP(同源策略)介紹

SOP最早是在Netscape Navigator 2(約1995年)中引入的,旨在規範對文檔對象模型(DOM)的訪問。隨著網站越來越面向用戶,JavaScript也越來越普遍,SOP明確了特定網頁上的資源程式碼可以與之交互或修改的邊界。

如果沒有SOP,惡意網站可能會向其他網站發出請求,並從其響應中讀取潛在的敏感資訊。想像一下下面的惡意偽javaScript程式碼:

let req = await fetch("https://mail.google.com/") // Request data from current logged in gmail  let mail_content = await req.text(); // Decode the response data  exfil(mail_content); // Exfil the emails to an attacker

在沒有SOP之前,惡意網站可能會執行這樣的請求,以讀取訪問其網站的任何人的電子郵件!SOP的主要思想是,由於訪問某個特定源站(如,attacker.com)而執行的腳本,不應與另一個源站(如,mail.google.com或localhost)上的數據進行交互。

為了強制執行此操作,瀏覽器會檢查每個出站請求以確保其符合要求。當瀏覽器確定某個網站正在向其他來源發出請求時(「跨來源請求(cross origin request)」)時,它將首先檢查該請求是否包含有任何「不安全」的標頭。如果有,則瀏覽器將完全阻止該請求,如下所示:

相反,如果請求並未包含任何不安全的標頭,則瀏覽器會將其轉發到目標站點。這個「目標站點」現在可以選擇告訴瀏覽器是否允許其他來源讀取響應。此功能通過可由「目標站點」設置的跨域資源共享(CORS)標頭實現。

通常,網站不啟用CORS,或僅為特定域啟用CORS。這意味著瀏覽器只會阻止傳遞響應。因此,請求站點無法讀取響應數據。

如果某個特定請求被標記為「safe(安全)」,則允許其傳遞到目標站點。儘管這些請求被標記為「安全」,但對於給定的應用程式來說,這些請求仍然會帶來很大的安全風險。以下面的請求為例:

fetch('http://localhost:1337/wallet/make_transaction', {    method:'POST',    body:'to=attack_address&amount=100000'  })

以下是發送到伺服器的實際數據:

POST /wallet/make_transaction  Host: localhost:1337  Origin: http://attacker.com  User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36  Accept: */*  Referer: http://attacker.com    to=attack_address&amount=100000

在本例中,惡意腳本控制的唯一數據塊是路徑和請求主體,這兩部分在CORS下都被視為「安全的」。因此,儘管存在明顯的實質性風險,但該請求總體上被認為是「安全的」!如果伺服器不執行任何其他驗證,則請求將成功觸發事務。

既然我們已經知道了SOP是如何阻止我們的跨域請求的(http://localhost:9980/wallet/seed),那麼接下來我們要做的就是想辦法繞過SOP,讓瀏覽器認為我們的惡意請求來自localhost(即同源)。我們可以通過一種稱之為DNS重綁定的技術來做到這點。

DNS重綁定

DNS重綁定是一種現代技術,它會使瀏覽器誤以為當前源站與實際不同的IP地址相關聯。

這種類型的攻擊可以通過控制特定的域名以及相關的DNS伺服器來執行。當受害者訪問域時,DNS伺服器用真實的IP地址響應,但使用非常短的生存時間(TTL)來防止快取。

之後,一旦TTL過期,就會向攻擊者的域發出另一個請求(例如通過JavaScript)。然而,這次DNS伺服器將以內部IP地址(如127.0.0.1)進行響應。瀏覽器則認為它仍在與原始的attacker.com通訊,但現在請求將轉到目標服務!

在此示例中,可以看到attacker.com第一次被解析為12.34.56.78,但第二次卻被解析為了127.0.0.1。

現在,當attacker.com向自己發出請求時,瀏覽器會向127.0.0.1發出同源請求。

保護 Localhost API 伺服器

針對這些攻擊最強壯的防禦是在向API發出請求時,需要一個在磁碟上的secret token:攻擊者可能無法從遠程上下文中知道這一點。然而,這有時並不理想,因為這會讓API的使用變得更為困難,因此開發人員也經常為此尋找替代解決方案。

另一種常見的技術是驗證請求頭,以確保請求來自合法的客戶端應用程式。執行此操作的常見方法是,檢查主機頭是否設置為localhost或其他預期值。另一種方法是檢查瀏覽器要發送的某些頭文件,如Origin、User-Agent或Referer。但是,這種「頭檢查」本身可能存在問題,因為哪些頭可以被信任,哪些頭可以被惡意腳本修改並不明確。

讓我們來看一下siacoin守護進程是如何保護自己免受未經授權交互的……在項目生命初期,Sia的開發人員意識到來自瀏覽器的請求可能會成為一個問題。為了減輕這種風險,它們包含了以下程式碼,以確保守護進程只接受具有值為「Sia-Agent」的User-Agent的請求:

if !strings.Contains(req.UserAgent(), "Sia-Agent") {      writeError(w, "Browser access disabled due to security vulnerability. Use Sia-UI or siac.", http.StatusBadRequest)      return  }

要繞過此檢查,我們需要在執行跨域請求時指定User-Agent標頭。讓我們看看是否可行!

檢查標準

要確定我們可以在出站請求中控制哪些標頭,就需要我們對Web標準有更為深入的了解。這些標準定義了兩個標頭列表。第一個稱為no-CORS-safe:它可以安全地為Cross-Origin請求設置標頭(例如標頭attacker.com可以發送到bank.com):

`Accept`  `Accept-Language`  `Content-Language`  `Content-Type`

在執行跨域請求時,JavaScript可以設置這些標頭,並且只能設置這些標頭。如果設置了其他選項,瀏覽器將會阻止該請求。這就是為什麼上面描述的用戶代理過濾方法看起來是安全的原因。User-Agent不在白名單中,因此無法設置為跨域請求。

另一個列表是Forbidden列表:它明確禁止設置黑名單標頭,無論其跨源狀態如何(即使對於同一源請求,如bank.com發送到bank.com也不允許):

`Accept-Charset`                    | `Accept-Encoding`  `Access-Control-Request-Headers`    | `Access-Control-Request-Method`  `Connection`                        | `Content-Length`  `Cookie`                            | `Cookie2`  `Date`                              | `DNT`  `Expect`                            | `Host`  `Keep-Alive`                        | `Origin`  `Referer`                           | `TE`  `Trailer`                           | `Transfer-Encoding`  `Upgrade`                           | `Via`

有一些技巧可以阻止其中一些標頭中被發送,但是它們無法被欺騙:如果它們存在,那麼接收者可以信任它們。要注意,我們看到Origin和Referer列表,但User-Agent沒有。這意味著對於同源請求,攻擊者可以將User-Agent標頭更改為他們想要的任意值!

讓我們在Siacoin守護進程上測試一下吧!

完整的 Siacoin Exploit

我們把之前的那些片段都整合在一起:

Siacoin Daemon通過驗證User-Agent標頭來驗證請求 允許Same-Origin請求設置自定義User-Agents,因為User-Agent不在Forbidden列表中 DNS重綁定允許我們將跨域請求轉換為同源請求

要真正利用這個問題,我們需要針對http://localhost:9980設置DNS重綁定攻擊。我們可以通過使用rbndr.us做到這一點,這是Tavis在他的相關研究中創建的一個實用程式。Rbndr提供了一個DNS伺服器,可以在兩個目標的IP之間進行切換,非常適用於這種攻擊場景。

首先,我們在7f000001..rbndr.us創建一個惡意站點,然後嘗試訪問/wallet/seeds。但是,我們仍然需要欺騙User-Agent標頭。這是非常容易,你可以按如下方式進行操作:

我們只需要等待DNS記錄的更新。一旦更新完成,我們將能夠直接與Siacoin Daemon通訊,那麼用戶的seed將舉手可得。

這將導致許多嚴重的後果,最直接的就是如果錢包被「解鎖(unlocked)」(假設用戶正在運行Sia錢包應用程式的默認狀態)那麼我們就可以竊取受害者的錢包種子。這些種子可在之後用於不可撤銷地轉移受害者所有的資金。

從貨幣竊取到遠程執行程式碼

通過這種攻擊,我們不僅可以竊取受害者的資金,甚至還可以通過濫用Sia守護進程的預期功能來實現遠程程式碼執行。

如前所述,Siacoin主要是一個去中心化的系統,用於促進廉價和可靠的文件存儲。有權訪問Sia錢包守護進程API的攻擊者,可以使用它在去中心化存儲網路和受害者電腦之間上傳和下載任意文件。由於能夠在目標電腦上以任意路徑寫入任意文件,我們能夠以多種不同的方式演示程式碼執行。

受影響的瀏覽器

從我們的測試來看,Google的Chrome是唯一一款能夠在DNS重新綁定攻擊時,阻止設置用戶代理欄位的主流瀏覽器。

我們發現Apple Safari和Mozilla Firefox用戶都很容易受到此帖中演示的攻擊。這是因為兩個瀏覽器都正確遵循標準。有趣的是,儘管Microsoft Edge瀏覽器也遵循該標準,但Microsoft Edge的用戶卻是安全的。這是由於Edge的app-container的內置網路隔離,使得瀏覽器無法實際建立與localhost的連接。

披露時間

在2018年9月我們向Nebulous Labs負責任的披露了該問題。他們對該漏洞的嚴重性表示了認同,並通過強化其使用磁碟令牌的服務及時解決了這個問題。

2018.09.12 – 向Nebulous Labs披露 2018.09.25 – 修複合併到source tree 2018.10.16 – 修復版發布(Sia 1.3.6)

*參考來源:ret2,FB小編secist編譯,轉載請註明來自FreeBuf.COM