or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Do you want to remove this version name and description?
Syncing
xxxxxxxxxx
title: css injection
tags: udn
CSS injection
What?
可以在一個頁面上可以插入任何的 CSS 語法
(顧名思義: 你可以插入
<style>
這個標籤)How?
屬性選擇器 X 利用 CSS 發出 request
1. 屬性選擇器
input[value^=a]
開頭是 a 的(prefix)input[value$=a]
結尾是 a 的(suffix)input[value*=a]
內容有 a 的(contains)How?
屬性選擇器 X 利用 CSS 發出 request
2. 利用 CSS 發出 request
Note:
因為第一條規則有順利找到對應的元素,所以 input 的背景就會是一張伺服器上的圖片,而瀏覽器就會發 request 到 https://myserver.com?q=a。
因此,當我在 server 收到這個 request 的時候,我就知道「input 的 value 屬性,第一個字元是 a」,就順利偷到了第一個字元。
How?
屬性選擇器 X 利用 CSS 發出 request
CSRF token
X 這樣無法 (input 亦無法從 css 直接強迫顯示)
Note:
因為 input 的 type 是 hidden,所以這個元素不會顯示在畫面上,既然不會顯示,那瀏覽器就沒有必要載入背景圖片,因此 server 不會收到任何 request。而這個限制非常嚴格,就算用 display:block !important; 也沒辦法蓋過去。
O 這樣可能可以
Note:
<input name="username">
。有了 :has,這個選擇器可以選到「底下符合特殊條件的元素」
意思就是我要選到「底下有(符合那個條件的 input)的 form」,所以最後載入背景的會是 form,一樣也不是那個 hidden input。這個 has selector 很新,從上個月底釋出的 Chrome 105 開始才正式支援,目前只剩下 Firefox 的穩定版還沒支援了,詳情可看:
How?
屬性選擇器 X 利用 CSS 發出 request
偷 meta
<meta name="csrf-token" content="abc123">
meta 這個元素一樣是看不見的元素,要怎麼偷呢?
偷 meta
has
偷 meta
Note: meta 雖然也看不到,但跟 hidden input 不同,我們可以自己用 CSS 讓這個元素變成可見,可是這樣還不夠,你會發現 request 還是沒有送出,這是因為 meta 在 head 底下,而 head 也有預設的 display:none 屬性,因此也要幫 head 特別設置,才會讓 meta「能被看到」
實例
偷 HackMD 的資料
偷 HackMD 的資料
可行的原因
<style>
偷 HackMD 的資料
Note: 準備好偷第一個字元的 style,插入到 HackMD 裡面
受害者打開頁面
伺服器收到第一個字元的 request
從伺服器更新 HackMD 內容,換成偷第二個字元的 payload
受害者頁面即時更新,載入新的 style
伺服器收到第二個字元的 request
不斷循環直到偷完所有字元
偷 HackMD 的資料
BUT
就算偷到了 HackMD 的 CSRF token,依然還是沒辦法 CSRF,因為 HackMD 有在 server 檢查其他的 HTTP request header 如 origin 或是 referer 等等,確保 request 來自合法的地方。
補充 1
不支援即時更新的網站?
在不使用 JS 的情況下怎麼動態載入新的 style?
使用
@import
Note: 在 CSS 裡面,你可以用 @import 去把外部的其他 style 引入進來,就像 JavaScript 的 import 那樣。
不支援即時更新的網站?
引入 style 的迴圈
server 回傳
Note: 重點來了,這邊雖然一次引入了 8 個,但是「後面 7 個 request,server 都會先 hang 住,不會給 response」,只有第一個網址 https://myserver.com/payload?len=1 會回傳 response,內容為之前提過的偷資料 payload
不支援即時更新的網站?
第一次回傳的 style
Note: 當瀏覽器收到 response 的時候,就會先載入上面這一段 CSS,載入完以後符合條件的元素就會發 request 到後端,假設第一個字是 d 好了,接著 server 這時候才回傳 https://myserver.com/payload?len=2 的 response
不支援即時更新的網站?
假設是 d 開頭,回傳以下的 style,然後以此類推
Note: 這邊有一點要特別注意,你會發現我們載入 style 的 domain 是 myserver.com,而背景圖片的 domain 是 b.myserver.com,這是因為瀏覽器通常對於一個 domain 能同時載入的 request 有數量上的限制,所以如果你全部都是用 myserver.com 的話,會發現背景圖片的 request 送不出去,都被 CSS import 給卡住了。
不支援即時更新的網站?
Firefox 不支援前面的做法,需改下面做法,Chrome 也支援
Note: 除此之外,上面這種方式在 Firefox 是行不通的,因為在 Firefox 上就算第一個的 response 先回來,也不會立刻更新 style,要等所有 request 都回來才會一起更新。解法的話可以參考這一篇:CSS data exfiltration in Firefox via a single injection point,把第一步的 import 拿掉,然後每一個字元的 import 都用額外的 style 包著。
補充 2
一次只偷一個字元?
HackMD 的 CSRF token 共有 36 個字,要發 36 個 request?
一次只偷一個字元?
prefix selector + suffix selector
Note: 要特別注意的是開頭跟結尾的 CSS,一個用的是 background,另一個用的是 border-background,是不同的屬性,因為如果用同一個屬性的話,內容就會被其他的蓋掉,最後只會發出一個 request。
除此之外,也可以朝 server 那邊去改善,例如說改用 HTTP/2 或甚至是 HTTP/3,都有機會能夠加速 request 載入的速度,進而提升效率。
補充 3
前面是偷屬性,其他東西?
unicode-range
前面是偷屬性,其他東西?
Note: 「unicode-range」,可以針對不同的字元,載入不同的字體。& 的 unicode 是 U+0026,因此只有 & 這個字會用不同的字體來顯示,其他都用同一個字體。
前面是偷屬性,其他東西?
前面是偷屬性,其他東西?
如果你去看 network tab,會看到一共發送了 4 個 request:
可以得知頁面上有:13ac 這四個字元。
前面是偷屬性,其他東西?
侷限
前面是偷屬性,其他東西? | 解決字元順序
字體高度差異 + first-line + scrollbar
unicode-range
css 屬性控制字元的字體DEMO
前面是偷屬性,其他東西? | 解決字元順序
前面是偷屬性,其他東西? | 解決重複字元
某些字型當中,會把一些特定的組合 render 成連在一起的樣子,出現時就把他的寬度拉超大讓 scrollbar 出現
前面是偷屬性,其他東西? | 解決重複字元
實戰上的話,可以用 SVG 搭配其他工具,在 server 端迅速產生字體
防禦
Note: 3. 預想若 CSRF token 被偷走可以怎麼防禦