James向我挑戰,看看是否有可能創建一個polyglot JavaScript/JPEG。這樣做可以讓我繞過幾乎任何一個網站的CSP,這些網站承載用戶在同一個域上傳的圖片。我興高采烈地接受了挑戰,開始剖析格式。前四個位元組是有效的非ASCII JavaScript變數0xFF 0xD8 0xFF 0xE0。接下來的兩個位元組指定JPEG頭的長度。如果我們使用位元組0x2F 0x2A來設定頭0x2F2A的長度,您可能會猜到我們有一個非ASCII變數,後面跟著一個多行JavaScript注釋。然後,我們必須將JPEG頭填充為長度為0x2F2A的空值。下麵是它的樣子:
FF D8 FF E0 2F 2A 4A 46 49 46 00 01 01 48 00 48 00 00 00 00 00 00 00 00 00 00 00。。。。
FF D8 FF E0 2F 2A 4A 46 49 46 00 01 01 01 00 48 00 48 00 00 00 00 00 00 00 00 00 00....
在JPEG注釋中,我們可以關閉JavaScript注釋,為非ASCII JavaScript變數創建一個賦值,後跟有效負載,然後在JPEG注釋的末尾創建另一個多行注釋。
FF鐵00 1C 2A 2F 3D 61 6C 65 72 74 28 42 75 72 70 20 72 6F 63 6B 73 2E 22 29 3B 2F 2A
FF FE 00 1C 2A 2F 3D 61 6C 65 72 74 28 22 42 75 72 70 20 72 6F 63 6B 73 2E 22 29 3B 2F 2A
0xFF 0xFE是注釋頭0x00 0x1C指定注釋的長度,然後剩下的是JavaScript負載,當然*/=alert(“Burp rocks.”)/*
接下來我們需要關閉JavaScript注釋,我編輯了影像標記結束之前的最後四個位元組的影像數據。檔案的結尾是這樣的:
2A 2F 2F 2F FF D9型
2A 2F 2F 2F FF D9
0xFF 0xD9是影像結束標記。很好,所以有我們的polyglot JPEG,還不是很好。如果您不指定字元集,但在Firefox上使用UTF-8字元集時,它工作得很好,如果將其作為腳本包含在檔案中,它會破壞我們的polyglot!在MDN上,它沒有聲明腳本支持charset内容,但它支持。囙此,要使腳本工作,您需要在腳本標記上指定ISO-8859-1字元集,它執行得很好。
值得注意的是,polyglot JPEG可以在Safari、Firefox、Edge和IE11上工作。Chrome不會明智地將影像作為JavaScript執行。
這是polyglot JPEG:
多邊形JPEG
將影像作為JavaScript執行的代碼如下:
<script charset=“ISO-8859-1”src=“http://portswigger labs.net/polyglot/jpeg/xss.jpg”></script>
<script charset="ISO-8859-1" src="http://portswigger-labs.net/polyglot/jpeg/xss.jpg"></script>
文件大小限制
我試圖將此圖形上載為phpBB個人資料圖片,但它有限制。有6k文件大小限制,最大尺寸為90x90。我通過裁剪縮小了logo的大小,並考慮了如何减少JPEG數據。在JPEG標頭檔中,我使用/*十六進位為0x2F和0x2A,將0x2F2A組合在一起,其長度為12074,這是一個很大的填充,將導致圖形太大,無法作為設定檔圖片。查看ASCII錶,我試圖找到一個有效的JavaScript字元組合,並减少JPEG頭中所需的填充量,同時仍被識別為有效的JPEG檔案。
我能找到的最小起始位元組是0x9(定位字元),後跟0x3A(冒號),這會產生一個0x093A(2362)的組合十六進位值,從檔案中删除很多位元組,並創建一個有效的非ASCII JavaScript label語句,後跟一個使用JFIF識別字的變數。然後我在JFIF識別字的末尾放一個正斜杠0x2F,而不是空字元,並用一個星號作為版本號。魔咒是這樣的:
FF D8 FF E0 09 3A 4A 46 49 46 2F 2A型
FF D8 FF E0 09 3A 4A 46 49 46 2F 2A
現在,我們繼續JPEG頭的其餘部分,然後填充空值並注入JavaScript負載:
FF D8 FF E0 09 3A 4A 46 49 46 2F 2A 01 01 00 48 00 48 00 00 00 00 00 00 00 00 00。。。(填充更多空值)2A 2F 3D 61 6C 65 72 74 28 42 75 72 70 20 72 6F 63 6B 73 2E 22 29 3B 2F 2A
FF D8 FF E0 09 3A 4A 46 49 46 2F 2A 01 01 00 48 00 48 00 00 00 00 00 00 00 ... (padding more nulls) 2A 2F 3D 61 6C 65 72 74 28 22 42 75 72 70 20 72 6F 63 6B 73 2E 22 29 3B 2F 2A
下麵是較小的圖形:
Polyglot JPEG更小
影響
如果允許用戶上載JPEG,則這些上載與應用程序位於同一域,並且CSP允許“self”中的腳本,則可以通過插入腳本並將其指向該影像,使用polyglot JPEG繞過CSP。
結論
總之,如果您允許在網站或任何類型的檔案上上載JPEG,那麼將這些資產放在單獨的域中是值得的。驗證JPEG時,應重寫JPEG頭,以確保沒有程式碼潜入其中,並删除所有JPEG注釋。很明顯,CSP不為腳本白名單您的影像資產域也是很重要的。
如果沒有安格·阿爾貝蒂尼出色的工作,這個職位是不可能的。我廣泛地使用他的JPEG格式圖形來創建polygot JPEG。賈斯維爾·納格拉的博客文章也啟發了我對polyglot GIFs的看法。
PoC公司
更新。。。
Mozilla正在Firefox51中修復這個問題。
訪問我們的Web安全學院,瞭解有關跨網站腳本(XSS)的更多資訊