原文鏈接:http://blog.portswigger.net/2016/12/bypassing-csp-using-polyglot-jpegs.html
原作者: Gareth Heyes
譯:Holic (知道創宇404安全實驗室)
James 曾請我看看是否能創建一個多語言的 JavaScript/JPEG (注:此處即將 JPEG 當做 JS 執行)。這么做的話,我將可以通過在同一域名用戶可上傳的圖片,來繞過 CSP 的保護。我欣然接受挑戰,然后開始剖析圖片格式。前四個字節是非 ASCII 的 JavaScript 變量 0xFF 0xD8 0xFF 0xE0 。然后,接下來的兩個字節指定了 JPEG 頭部的長度。如果我們使用字節 0x2F 2A設置文件頭的長度為 0x2F2A,你會猜到,我們有一個非 ASCII 字符的變量,后面更早多行 JavaScript 注釋。然后,我們必須將 JPEG 頭填充為 0x2F2A 長度的 null。它看起來是這樣的:
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 注釋,并在 payload 后面為我們的非 ASCII 字符的 JavaScript 變量賦初值,隨后在 JPEG 注釋的末尾創建另一個多行注釋。
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 payload,當然此處為 */=alert("Burp rocks.")/*
接下來需要閉合 JavaScript 注釋,我在圖像結束標記之前編輯了圖片數據的最后四個字節。文件的結尾看起來是這樣子的:
2A 2F 2F 2F FF D9
0xFF 0xD9是圖片結束的標志。很好,我們的多語義 JPEG 就有了,不過這還不夠。如果你不指定字符編碼,這很有效,但是 FireFox 使用 UTF-8 作為文檔編碼,包含腳本代碼的時候,它破壞了其多語義性。在 MDN 里,它沒有說明腳本支持 charset 屬性,但實際上是支持的。所有要讓腳本正常運行,你需要在 script 標簽里指定 ISO-8859-1 編碼,這就能運行良好了。
值得注意的是,多語義的 JPEG 可以在 Safari,Firefox,Edge 和 IE 11 上使用。Chrome 機智地沒有將圖像作為 JavaScript 執行。
多語義 JPEG PoC 在此:
將圖像作為 JavaScript 執行的代碼如下:
<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 標簽語句,后面便是 JFIF 標識符的變量。然后,我將斜杠 0x2F 而不是 NULL 放在 JFIF 標識符的結尾,將星號放在對應版本號的位置。十六進制是這樣的:
FF D8 FF E0 09 3A 4A 46 49 46 2F 2A
現在我們繼續用 NULL 注入其余的 JPEG 頭,并注入 JavaScript payload:
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
這是更小的圖片:
影響
如果你允許用戶上傳 JPEG 圖片,且這些上傳的圖片與你的應用程序在同一域下,你的 CSP 還允許來自 "self" 的腳本,你便可以通過注入腳本將其指向圖像的方法繞過 CSP 。
結論
總而言之,如果你在你的站點上允許上傳 JPEG 圖片或者任何形式的文件,這值得將它們放在一個不同的域下。當驗證一個 JPEG 時,你應該重寫 JPEG 頭,以確保其中沒有偷偷放置的代碼,并且刪除 JPEG 注釋。顯然,你的 CSP 也不必將腳本的圖片資源列入白名單。
如果沒有Ange Albertini的出色工作,這篇文章就不會出現。我使用它的 JPEG 格式圖片創建了通用的多語義 JPEG 圖片。Jasvir Nagra 也在 多語義 GIF 上啟發了我。
Enjoy - @garethheyes
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.jmbmsq.com/133/
暫無評論