2018/05/04

[備忘錄分享] XSS (2009 年) 測試記錄

在 2009 年,我第一次接觸弱點掃描,看著掃描報告中的 XSS (Cross-Site Script) 跨網站指令碼漏洞描述,很好奇什麼樣的寫法會用來做為 XSS ,同時也想知道我該怎麼防堵 XSS 進而通過弱點掃描。

當時我找到一個格主是 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="&#106&#97&#118&#97&#115&#99&#114&#105&#112&#116&#58&#97&#108&#101&#114&#116&#40&#39&#88&#83&#83&#39&#41&#59">

十六進制編碼的版本,
<img src="&#x6a&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3a&#x61&#x6c&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29&#x3b">

測試結果:
這些只在 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() 是否可解碼
&#00106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;&#59;
以及
&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3a;&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x27;&#x58;&#x53;&#x53;&#x27;&#x29;&#x3b;

測試結果:
可用 HttpUtility.HtmlDecode() 解碼為 javascript:alert('XSS');
但是若把分號 (;) 拿掉,HttpUtility.HtmlDecode() 就不能解了,
而瀏覽器可以解碼拿掉分號後的編碼值!
這代表自己在寫偵測機制的時候,要自行補上分號再丟給 HttpUtility.HtmlDecode()。

7. 若想要偵測上述項目 4, 5 那種反斜線 \ 開頭的編碼格式,可以先自行將其轉成 html 編碼格式再丟給 HttpUtility.HtmlDecode()。
例如:
\75 把反斜線換成 &#x 同時在後面加分號,變成 &#x75;
\x6a 把反斜線換成 &# 同時在後面加分號,變成 &#x6a;

8. 用來抓編碼的正規表達式 (Regular Expression)
(?is)(?<prefix>&#)(?<cnt>[^\s&#\\;]+);?
// 用來抓 &# 開頭的值,不管結尾有無分號都抓,例如 &#106; &#97 &#118 &#x6a; &#x61 &#x76
// 後續要把 <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="&#00106;
&#97;&#118;&#97;&#115;&#99;&#114;&#105; &#112;&#116;&#58;&#97;
&#108;&#101;&#114; &#116;&#40;&#39;&#88; &#83;&#83;&#39;&#41;&#59;">test</a>

十六進制的版本,
<a href="&#x6a;&#x61;&#x76;
&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3a;
&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x27;&#x58;&#x53;&#x53;&#x27;&#x29;&#x3b;">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

b. WebResource.axd, ScriptResource.axd 參數 d 接收的格式
[A-Za-z0-9+/=_\-]+
目前看到字串長度最小 18
(2016/08/02 遇到長度有 8 的情況,不確定是否為 .net 4 與 2 的差別)
參數 t 接收的格式
[\da-fA-f]+


沒有留言:

張貼留言