0×00 引言
很多不瞭解 html 、 js 編碼的童鞋遇到 xss 時,都是一頓亂插,姿勢對了,就能獲得快感,姿勢不對,就麼反應。另外在 freebuf 裏,有很多文章介紹過跨站編碼,有興趣的,可以搜索下。
本文介紹常見的編碼方法,能力不足,如有其他意見,請指正。
0×01 常用編碼
URL 編碼:一個百分號和該字符的 ASCII 編碼所對應的 2 位十六進制數字,例如“ / ”的 URL 編碼爲 %2F( 一般大寫,但不強求 )
HTML 實體編碼:
命名實體: 以 & 開頭,分號結尾的,例如“ < ”的編碼是“ < ”
字符編碼: 十進制、十六進制 ASCII 碼或 unicode 字符編碼,樣式爲“ &# 數值; ” , 例如“ < ”可以編碼爲“ < ”和“ < ”
JS 編碼: js 提供了四種字符編碼的策略,
| 1、三個八進制數字,如果不夠個數,前面補0,例如“e”編碼爲“\145” 2、兩個十六進制數字,如果不夠個數,前面補0,例如“e”編碼爲“\x65” 3、四個十六進制數字,如果不夠個數,前面補0,例如“e”編碼爲“\u0065” 4、對於一些控制字符,使用特殊的C類型的轉義風格(例如\n和\r) |
CSS 編碼: 用一個反斜線 (\) 後面跟 1~6 位的十六進制數字,例如 e 可以編碼爲“ \65 ”或“ 65 ”或“ 00065 ”
複合編碼:
所謂複合編碼,也就是說輸出的內容輸出在多個環境中,例如
|
<span
class="tag"><<span
class="title">td</span>
<span
class="attribute">onclick</span>=<span
class="value">”openUrl(add.do?userName=’<%=value%</span>></span>’);”>11<span
class="tag"></<span
class="title">td</span>></span>
|
value 的內容首先出現在一個 URL 中,這個 URL 在一段 javascript 總,而javascript 代碼又是 html 的一部分。所以解碼的順序就是 HTML 解碼 –>js 解碼 –>url 解碼,那麼正確的編碼順序就應該是 url 編碼 –>js 編碼 –>html 編碼。
0×02 基本概念
HTML 解析器能識別在文本節點和參數值裏的實體編碼,並在內存裏創建文檔樹的表現形式時,透明的對這些編碼進行解碼。
例如以下兩種寫法的功能是一樣的(忽略裏面的空格。。鄙視下這個編輯器):
| <span class="tag"><<span class="title">img</span> <span class="attribute">src</span>=<span class="value">"http://www.example.com"</span>></span> <span class="tag"><<span class="title">img</span> <span class="attribute">src</span>=<span class="value">"ht&# x74;p://www.example.com"</span>></span> |
而下面的兩個例子,實際上卻沒法真的加載圖片,因爲這種編碼干擾了標籤本身的結構。
|
<span
class="tag"><<span
class="title">img</span>
<span
class="attribute">src</span>&#
<span class="attribute">x3d</span>;"<span class="attribute">http:</span>//<span class="attribute">www.example.com</span>"></span>
<span
class="tag"><<span
class="title">img</span>
<span
class="attribute">s</span>&#
<span class="attribute">x72</span>;<span class="attribute">c</span>=<span class="value">"http://www.example.com"</span>></span>
|
下面瞭解下瀏覽器解析 HTML 的步驟:瀏覽器收到從服務器發送來的 HTML 內容,會從頭解析,當遇到 <script></script> 時,會調用 javascript 腳本解析器解析javascript ,並執行腳本,然後繼續解析其他的 HTML 內容,對於一些需要觸發才能執行的事件,當觸發事件發送時,腳本解析器纔會解析其中的腳本,在事件觸發之前,它是 HTML 的一部分。
0×03 實例剖析
3.1 HTML–>js 編碼
代碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <span class="preprocessor"><?php</span> <span class="function"><span class="keyword">function</span> <span class="title">htmlencode</span><span class="params">(<span class="variable">$str</span>)</span>{</span> <span class="keyword">if</span>(<span class="keyword">empty</span>(<span class="variable">$str</span>)) <span class="keyword">return</span>; <span class="keyword">if</span>(<span class="variable">$str</span> == <span class="string">""</span>) <span class="keyword">return</span>; <span class="variable">$str</span> = str_ireplace(<span class="string">"<"</span>,<span class="string">""</span>,<span class="variable">$str</span>); <span class="variable">$str</span> = str_ireplace(<span class="string">">"</span>,<span class="string">""</span>,<span class="variable">$str</span>); <span class="variable">$str</span> = str_ireplace(<span class="string">"script"</span>,<span class="string">""</span>,<span class="variable">$str</span>); <span class="variable">$str</span> = str_ireplace(<span class="string">"img"</span>,<span class="string">""</span>,<span class="variable">$str</span>); <span class="variable">$str</span> = str_ireplace(<span class="string">":"</span>,<span class="string">""</span>,<span class="variable">$str</span>); <span class="variable">$str</span> = str_ireplace(<span class="string">"javascript"</span>,<span class="string">""</span>,<span class="variable">$str</span>); <span class="keyword">return</span> <span class="variable">$str</span>; } <span class="keyword">if</span>(!array_key_exists (<span class="string">"name"</span>,<span class="variable">$_GET</span>) || <span class="variable">$_GET</span>[<span class="string">'name'</span>] == <span class="keyword">NULL</span> || <span class="variable">$_GET</span>[<span class="string">'name'</span>] == <span class="string">''</span>){ <span class="variable">$isempty</span> = <span class="keyword">true</span>; } <span class="keyword">else</span> { <span class="variable">$html</span> .= <span class="string">'<pre>'</span>; <span class="variable">$html</span> .= <span class="string">'<a οnclick=" '</span> .htmlencode(<span class="variable">$_GET</span>[<span class="string">'name'</span>]).<span class="string">'">click this url</a>'</span>; <span class="variable">$html</span> .= <span class="string">'</pre>'</span>; } <span class="preprocessor">?></span> <html> <script> </script> </html> |
可以看到,過濾了尖角號, script 等標籤,當輸入 javascript:alert(/xss/) 時,系統返回的爲:
我們現在分析一下 $name 的環境, $name 先在 html 環境中,然後在javascript 環境 (onclick 事件 ) 中,瀏覽器解析的順序是 html 解碼 –>js 解碼,所以我們將 javascript:alert(/xss/) 進行 html 編碼,從而可以繞過限制 ( 當然此處代碼還有其他好幾種繞過的方式,此處只是簡單說明編碼問題 ) ,因爲在 javascript 解碼時, $name 已經被 html 解碼了,那麼處在 javascript 中的 $name 變量就是正常的 js 代碼。
源代碼爲:
3.2 js–>html 編碼
代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<span
class="preprocessor"><?php</span>
<span
class="keyword">if</span>(!array_key_exists
(<span
class="string">"name"</span>,<span
class="variable">$_GET</span>)
||
<span
class="variable">$_GET</span>[<span
class="string">'name'</span>]
==
<span
class="keyword">NULL</span>
||
<span
class="variable">$_GET</span>[<span
class="string">'name'</span>]
==
<span
class="string">''</span>){
<span
class="variable">$isempty</span>
=
<span
class="keyword">true</span>;
}
<span
class="keyword">else</span>
{
<span
class="variable">$value</span>
=
<span
class="variable">$_GET</span>[<span
class="string">'name'</span>];
<span
class="variable">$html</span>
.=
<span
class="string">'<pre>'</span>;
<span
class="variable">$html</span>
.=
<span
class="string">"Your
Name is :
<div id='a'></div>
<script>
document.getElementById('a').innerHTML= "</span>.<span
class="string">"'"</span>.htmlspecialchars(<span
class="variable">$value</span>).<span
class="string">"'"</span>.<span
class="string">";
</script>
"</span>;
<span
class="variable">$html</span>
.=
<span
class="string">'</pre>'</span>;
}
<span
class="preprocessor">?></span>
|
可以看到, $value 使用了 htmlspecialchars 進行了編碼, htmlspecialchars 會對 & 、 ’ 、 ” 、 < 、 > 進行 html 編碼,當輸入 <img src=1 οnerrοr=alert(/xss/)>時,系統不會彈框,因爲特殊符號被 html 編碼了。
我們現在分析下 $value 的環境, $value 先在 javascript 中,然後在 html 環境中 ( 通過 innerHTML 操作 html) ,所以瀏覽器解碼順序爲 js 解碼 –>html 解碼,所以我們可以對 $value 進行 js 編碼,繞過 htmlspecialchars 限制,因爲 $value 在html 解碼時,已經是正常的 html 代碼了。
3.3 URL 編碼
此外,如果 & 等符號被過濾的話,可以對其進行 URL 編碼,然後測試。
0×04 Tips :
1、DOM: 只有使用合規的完整閉合的 HTML 區塊對每個 innerHTML 節點進行賦值,因爲這樣纔不會改變被重寫段落之外的文檔層級結構。如果格式不對,在重寫發生之前輸入的數據會先按照規定的語法進行強制轉換。
即通過 DOM 操作 HTML 時,可以使用 <script>alert(/xss/) 來代替<script>alert(/xss/)</script> ,因爲 DOM 會自動補全。
2、innerHTML 只能使用 <img src=1οnerrοr=alert(1)> 這種方式來觸發 JS 。而不能以 <script>alert(1)</script> 來觸發,因爲這種壓根不會執行 <script>..</script> 之間的內容。