當時我找到一個格主是 OpenBlue 的部落格,裡面寫了很多 XSS 相關的知識,我覺得是個寶庫(可惜現在這個部落格已經關了)。我在那個部落格中找到一篇叫做「淺析XSS(Cross Site Script)漏洞原理」的文章,照著文章裡的描述開始了我的摸索與測試。
今日再次搜尋「淺析XSS(Cross Site Script)漏洞原理」才知道原文出處在內地,還好這篇文章還看得到,請看 http://safe.it168.com/n/2007-07-04/20070704004201_all.shtml。
以下為當時我所記錄的內容,
測試時間:
2009 年某日
測試環境:
Windows 7
瀏覽器 IETester(IE6, IE7, IE8RC1), IE8, Chrome, Firefox
1. 測試文章中「一、XSS的触发条件」提到的
「在 <A HREF=""></A> 的屬性 HREF 值裡面加上 "><script>alert('XSS');</script> <"」
將 <A HREF=""><script>alert('XSS');</script> <""></A> 存成 html 檔案並且使用各瀏覽器開啟。
測試結果:
受測的瀏覽器都有效,都會彈出訊息 XSS,不過,好消息是 <script> 之中的指令必須正確,無法使用編碼的方式(文章中「二、XSS转码引发的过滤问题」提到的)。
2. 測試文章中提到的
「把 js 寫在屬性裡,例如 img 的 src 屬性,
<img src="javascript:alert('XSS');">
十進制編碼的版本,
<img src="javascript:alert('XSS');">
十六進制編碼的版本,
<img src="javascript:alert('XSS');">
」
測試結果:
這些只在 IE6、7、8RC1 有效。
3. 測試文章中「一、XSS的触发条件」提到的
「利用事件,例如 img 的 onerror,
<img src=" http://xss.jpg" onerror=alert('XSS')>
」
測試結果:
受測的瀏覽器都有效,而且 onerror 之中的指令可使用編碼的方式。
4. 測試文章中「二、XSS转码引发的过滤问题」提到的
「使用 eval() 執行編碼後的指令,例如十六進制編碼
<SCRIPT LANGUAGE="JavaScript">
eval("\x6a\x61\x76\x61\x73\x63\x72\x69\x70\x74\x3a\x61\x6c\x65\x72\x74\x28\x22\x58\x53\x53\x22\x29")
</SCRIPT>
」
測試結果:
受測的瀏覽器都有效。
另外,若在 eval() 的字串參數的字碼之間加了 tab 符號 (ascii 09) 或換行符號 (ascii 0D0A),執行結果就會變成失敗,指令就失效。
這代表自己在寫偵測機制的時候,這裡不需要考慮 tab 和換行符號。
5. 測試文章中「二、XSS转码引发的过滤问题」提到的
「利用 css 認識的編碼去塞指令,例如
<img STYLE="background-image: \75\72\6c\28\6a\61\76\61\73\63\72\69\70\74\3a\61\6c\65\72\74\28\27\58\53\53\27\29\29">
它被翻譯後是
<img STYLE="background-image: url(javascript:alert('XSS'))">
」
這裡的反斜線開頭的碼,用十六進制解碼。
比起項目 4 的 eval() 裡面的碼,少了 x 。
測試結果:
只在 IE6、7、8RC1 有效。
6. 測試 .net 提供的函式 HttpUtility.HtmlDecode() 是否可解碼
javascript:alert('XSS');
以及
javascript:alert('XSS');
測試結果:
可用 HttpUtility.HtmlDecode() 解碼為 javascript:alert('XSS');
但是若把分號 (;) 拿掉,HttpUtility.HtmlDecode() 就不能解了,
而瀏覽器可以解碼拿掉分號後的編碼值!
這代表自己在寫偵測機制的時候,要自行補上分號再丟給 HttpUtility.HtmlDecode()。
7. 若想要偵測上述項目 4, 5 那種反斜線 \ 開頭的編碼格式,可以先自行將其轉成 html 編碼格式再丟給 HttpUtility.HtmlDecode()。
例如:
\75 把反斜線換成 &#x 同時在後面加分號,變成 u
\x6a 把反斜線換成 &# 同時在後面加分號,變成 j
8. 用來抓編碼的正規表達式 (Regular Expression)
(?is)(?<prefix>&#)(?<cnt>[^\s&#\\;]+);?
// 用來抓 &# 開頭的值,不管結尾有無分號都抓,例如 j a v j a v
// 後續要把 <cnt> 變成 &#<cnt>;
(?is)(?<prefix>\\x?)(?<cnt>[^\s&#\\;]+)
// 用來抓反斜線開頭的值,例如 \x6a \x61 \x76 \75 \72 \6c
// 後續要把 <cnt> 變成 &#x<cnt>;
9. 文章裡沒提到的,但是我有測試到的情況,
<a href="javascript:alert('XSS');">test</a>
若在 href 的內容裡加上 tab 符號 (ascii 09) 或換行符號 (ascii 0D0A),變成
<a href="ja
vascr ipt:alert('XSS');">test</a>
瀏覽器還是會正常執行。
另外再應用文章中「二、XSS转码引发的过滤问题」提到的編碼,變成
<a href="j
avascri pt:a
ler t('X SS');">test</a>
十六進制的版本,
<a href="jav
ascript:
alert('XSS');">test</a>
測試結果:
(2018/05/09) 在 Chrome 66, Firefox 59, IE 11, edge 41 都有效。
這代表自己在寫偵測機制的時候,需要考慮 tab 和換行符號。
當時的備忘錄總結
- 屬性中的惡意程式 (<img src="javascript:alert(''XSS'');">),不管有無編碼,在 IE6、7、8RC1 都有效,新的瀏覽器沒事。
- 事件 (onerror, onload) 為例外,全中。
- 新版瀏覽器怕 <script> 之中的指令 (和事件),還可以用 eval() 執行編碼後的指令。
.以下是其他和 XSS 無關的,但是被我記在一起
a. 用來抓弱掃工具會送來的 SQL Injection 測試值的正規表達式
(?is)(?<verb>and|or)\s+(?<expr>.+?\s*=\s*['"]?\s*[^\s-;'"]+)
// or xxx=xxx
// xxx' and 31337-31337='0
a. 用來抓弱掃工具會送來的 SQL Injection 測試值的正規表達式
(?is)(?<verb>and|or)\s+(?<expr>.+?\s*=\s*['"]?\s*[^\s-;'"]+)
// or xxx=xxx
// xxx' and 31337-31337='0
b. WebResource.axd, ScriptResource.axd 參數 d 接收的格式
[A-Za-z0-9+/=_\-]+
目前看到字串長度最小 18
(2016/08/02 遇到長度有 8 的情況,不確定是否為 .net 4 與 2 的差別)
參數 t 接收的格式[A-Za-z0-9+/=_\-]+
目前看到字串長度最小 18
(2016/08/02 遇到長度有 8 的情況,不確定是否為 .net 4 與 2 的差別)
[\da-fA-f]+
沒有留言:
張貼留言