==Ph4nt0m Security Team==
Issue 0x02, Phile #0x07 of 0x0A
|=---------------------------------------------------------------------------=|
|=-------------------------=[ 亂談之XSS攻擊檢測(cè) ]=---------------------------=|
|=---------------------------------------------------------------------------=|
|=---------------------------------------------------------------------------=|
|=----------------------=[ By Xy7 ]=----------------------=|
|=--------------------=[
|=---------------------------------------------------------------------------=|
前言:
所謂亂談,不是科普,不是分析,
亂談之XSS攻擊檢測(cè)
。具體關(guān)于XSS攻擊的基礎(chǔ)知識(shí)感興趣的可以在網(wǎng)上一搜一大堆出來(lái),比如:百度科普。本文只是站在一個(gè)防御者的角度,探討作為第三方程序防御XSS
攻擊過(guò)程中出現(xiàn)的一些困難,思路無(wú)章,可謂雜文。
一、B/S結(jié)構(gòu)下的HTML標(biāo)簽XSS
這是最普通的一類跨站攻擊了,也就是平常經(jīng)常被人說(shuō)到的那一類,具體漏洞成因可以
用如下一個(gè)過(guò)程來(lái)表示:
javascript.:DrawImage(this);>
當(dāng)一個(gè)惡意用戶在沒有過(guò)濾的地方提交,這樣在有
其他用戶瀏覽的情況下,這段代碼就會(huì)在其他用戶的IE中被執(zhí)行。當(dāng)然這只是最基本的一種
測(cè)試方法,如果XSS只是彈框框而已,那就沒什么說(shuō)道的了,防御這種攻擊過(guò)濾HTML標(biāo)簽就可
以了。但是還有那么多標(biāo)簽的事件呢?CSS的屬性,各種編碼…要寫這么一個(gè)全面的過(guò)濾危險(xiǎn)
字符的檢測(cè)函數(shù)實(shí)在不是一件簡(jiǎn)單的工作,而且效果肯定也不是很完美。最好的防御方式最
好還是仔細(xì)的檢查WEB應(yīng)用程序代碼,限制用戶的輸入。不過(guò)這樣在現(xiàn)實(shí)中可能并不能行的
通,因?yàn)椴皇敲總(gè)WEB程序的使用者都有閱讀代碼的能力或者WEB安全意識(shí),此類站點(diǎn)出現(xiàn)XSS
漏洞見怪不怪,而稍微有點(diǎn)財(cái)力的站點(diǎn)或者企業(yè)都希望能有一批專業(yè)人員來(lái)幫助他們修補(bǔ)漏
洞,提升WEB程序的安全性,這樣就給很多提供WEB檢測(cè)服務(wù)的組織或廠商帶來(lái)了商機(jī),而更現(xiàn)
實(shí)的是服務(wù)并沒有產(chǎn)品賣錢,所以小公司賣服務(wù),大公司推產(chǎn)品,產(chǎn)品的過(guò)濾自然有考慮不周
的地方,服務(wù)也不能保證盡善盡美,所以安全等級(jí)參差不齊。在如今WEB安全日益被提上高度
的同時(shí),XSS攻擊依然風(fēng)風(fēng)火火也就不足為奇了。
二、UBB標(biāo)簽的XSS
在各大論壇或者BLOG程序中對(duì)UBB標(biāo)簽的使用已經(jīng)是非常成熟了。UBB提供了有限的標(biāo)
簽可供使用,本身可以說(shuō)已經(jīng)設(shè)置了一道過(guò)濾。常見的UBB轉(zhuǎn)換代碼如下:
function ubb($text) {
$text=trim($text);
$Text=ereg_replace("\n","
",$Text);
$Text=preg_replace("/\\t/is"," ",$Text);
$Text=preg_replace("/\[h1\](.+?)\[\/h1\]/is","
\\1
",$Text);$Text=preg_replace("/\[h2\](.+?)\[\/h2\]/is","
\\1
",$Text);$Text=preg_replace("/\[h3\](.+?)\[\/h3\]/is","
\\1
",$Text);$Text=preg_replace("/\[h4\](.+?)\[\/h4\]/is","
\\1
",$Text);$Text=preg_replace("/\[h5\](.+?)\[\/h5\]/is","
\\1
",$Text);$Text=preg_replace("/\[h6\](.+?)\[\/h6\]/is","
\\1
",$Text);$Text=preg_replace("/\[center\](.+?)\[\/center\]/is","
$Text=preg_replace("/\[url\](http:\/\/.+?)\[\/url\]/is","\\1",$Text);
$Text=preg_replace("/\[url\](.+?)\[\/url\]/is","http://\\1\">http://\\1",$Text);
$Text=preg_replace("/\[url=(http:\/\/.+?)\](.*)\[\/url\]/is","\\2",$Text);
$Text=preg_replace("/\[url=(.+?)\](.*)\[\/url\]/is","\\2",$Text);
$Text=preg_replace("/\[img\](.+?)\[\/img\]/is","",$Text);
$Text=preg_replace("/\[color=(.+?)\](.+?)\[\/color\]/is","\\2",$Text);
$Text=preg_replace("/\[size=(.+?)\](.+?)\[\/size\]/is","\\2",$Text);
….
Return $text;
?>
由于UBB代碼沒有對(duì)接受的變量進(jìn)行必要的過(guò)濾,針對(duì)該漏洞代碼的利用也很簡(jiǎn)單,提交
類似的代碼,代入程序中會(huì)被轉(zhuǎn)義成
就形成了所謂的UBB跨站。從利用角度看沒什么好說(shuō)的,但是從防守角度看呢?拋開檢查程序
代碼這類服務(wù)不說(shuō),但從標(biāo)簽分析檢測(cè)來(lái)看,[img]這類標(biāo)簽就足以繞過(guò)標(biāo)簽檢測(cè)機(jī)制了。由
于UBB代碼并不存在于所有的WEB程序中,要想通過(guò)一種通用的第三方程序來(lái)檢測(cè)這類跨站攻
擊,首先就是要在第三方程序引擎內(nèi)部實(shí)現(xiàn)一個(gè)UBB代碼的編碼還原,先把UBB代碼還原成HTML
標(biāo)簽,然后再匹配可能形成攻擊的XSSpayload,這樣一來(lái)就有一部分性能要花在還原標(biāo)簽上,
而且是不考慮所在WEB應(yīng)用程序的,如果該WEB程序沒有UBB代碼,那么這一部分性能就白白浪
費(fèi)了…
那么換一種方法呢?采用學(xué)習(xí)+模型的檢測(cè)機(jī)制,首先通過(guò)一段時(shí)間的學(xué)習(xí),使得第三方
檢測(cè)程序能夠熟悉被護(hù)WEB程序的數(shù)據(jù)流,建立正常數(shù)據(jù)流模型,如果該模型中沒有出現(xiàn)UBB
代碼則采用普通的檢測(cè)機(jī)制,否則就加載UBB還原代碼。這樣看似是一種智能的檢測(cè)分析機(jī)
制,實(shí)際上使得產(chǎn)品的檢測(cè)代碼更加復(fù)雜再加上維護(hù)和分析模型的成本,造成成功檢測(cè)比成
功利用攻擊要困難的多。僅僅是一個(gè)UBB代碼的出現(xiàn)就使得XSS檢測(cè)機(jī)制不得不增加很大的
工作量去分析,而實(shí)際利用其實(shí)并無(wú)太大差異,真是道高一尺,魔高一丈。
三、POST表單XSS
POST跨站也是一種比較常見的跨站方法了,漏洞成因上沒什么好分析的,關(guān)鍵是from表
單的一個(gè)屬性可能給第三方檢測(cè)XSS的產(chǎn)品帶來(lái)一塊絆腳石,這種問題一般的XSS攻擊者是從
來(lái)不會(huì)考慮的吧,呵呵。這兩個(gè)表單屬性就是:
multipart/form-data和application/x-www-form-urlencoded。
先看x-www-form-urlencoded屬性,F(xiàn)ROM表單的enctype屬性指定了表單數(shù)據(jù)向服務(wù)器提
交時(shí)所采用的編碼類型,默認(rèn)的屬性值是“application/x-www-form-urlencoded”,當(dāng)攻擊者
POST一句到服務(wù)器的時(shí)候,抓包看一下傳輸?shù)?/p>
格式如下:
HTTP - Hyper Text Transfer Protocol
HTTP Command: POST
URI: /xblog/insert.php
HTTP Version: HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer:
Accept-Language: zh-cn
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Host: 192.168.13.216
Content-Length: 105
Connection: Keep-Alive
Cache-Control: no-cache
Line 1: id=4&author=%D0%FD%C4%BE%C4%BE&title=eee&content=111%3Cscript%3Ealert%28document
Line .cookie%29%3C%2Fscript%3E
FCS - Frame. Check Sequence
FCS: 0x89D1A7DB Calculated
可以看到,提交的字符在POST數(shù)據(jù)包中是以URL編碼的方式傳輸?shù)摹.?dāng)檢測(cè)這種POST的
時(shí)候可以通過(guò)“&”字符分割各個(gè)變量,再通過(guò)“=”分割變量和變量的值。最后形成這么一個(gè)集
合檢測(cè)規(guī)則:
javascript.:DrawImage(this);>
用程序?qū)崿F(xiàn)這么一個(gè)檢測(cè)功能并不復(fù)雜,關(guān)鍵還是要看xsspayload的檢測(cè)規(guī)則。但是對(duì)
比這兩個(gè)屬性的問題并不在檢測(cè)規(guī)則這里。當(dāng)表單屬性為application/x-www-form-urlencoded
的時(shí)候可以很方便的定位XSS語(yǔ)句出現(xiàn)的位置,因?yàn)橹暗膮f(xié)議變量是固定的。但是接下來(lái)
看一下表單屬性為multipart/form-data的時(shí)候POST包的格式:
HTTP - Hyper Text Transfer Protocol
HTTP Command: POST
URI: /sql1/post.php
HTTP Version: HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer:
Accept-Language: zh-cn
Content-Type: multipart/form-data; boundary=---------------------------7d822d8550650
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Host: 192.168.13.216
Content-Length: 384
Connection: Keep-Alive
Cache-Control: no-cache
Line 1: -----------------------------7d822d8550650
Line 2: Content-Disposition: form-data; name="action"
Line 3: post
Line 4: -----------------------------7d822d8550650
Line 5: Content-Disposition: form-data; name="username"
Line 6: 333
Line 7: -----------------------------7d822d8550650
Line 8: Content-Disposition: form-data; name="pagetext"
Line 9: 333
Line 10: -----------------------------7d822d8550650--
FCS - Frame. Check Sequence
FCS: 0xAE3B0D65 Calculated
可以看到在向服務(wù)器發(fā)送大量的文本、包含非ASCII字符的文本或二進(jìn)制數(shù)據(jù)時(shí)這種編
碼方式效率很低,
電腦資料
《亂談之XSS攻擊檢測(cè)》(http://www.msguai.com)。在文件上載時(shí),所使用的編碼類型應(yīng)當(dāng)是“multipart/form-data”,它既可以發(fā)送文本數(shù)據(jù),也支持二進(jìn)制數(shù)據(jù)上載。這樣一來(lái)就沒辦法通過(guò)分隔符來(lái)提取各個(gè)變量的
值了,只能通過(guò)分割線來(lái)分隔各個(gè)數(shù)據(jù)段。寫到這里我就想到了市面上的一些WEB防火墻,基
本都是通過(guò)代理的方式,把真實(shí)的保護(hù)主機(jī)隱藏在后面,所有的數(shù)據(jù)都要先經(jīng)過(guò)WEB防火墻的
檢測(cè)。但是基本上WEB防火墻沒有什么基于原理的檢測(cè)機(jī)制,都是采用匹配特征的方式,對(duì)于
application/x-www-form-urlencoded的表單可能還可以用之前提過(guò)的檢測(cè)規(guī)則來(lái)進(jìn)行特征
匹配,可是對(duì)于multipart/form-data方式的呢?不光檢測(cè)之前的特征提取算法需要改進(jìn),當(dāng)
XSS語(yǔ)句出現(xiàn)在大段數(shù)據(jù)之后呢?遍歷一遍整個(gè)數(shù)據(jù)段需要耗費(fèi)的時(shí)間不算,如果是很大的數(shù)
據(jù)包,那檢測(cè)預(yù)處理的緩沖區(qū)是否能接受這么多的待檢測(cè)數(shù)據(jù)?
亂談續(xù)一、phpinfo()函數(shù)跨站
提到這個(gè)函數(shù)是為了說(shuō)明兩個(gè)問題:
1.跨站不僅僅是出現(xiàn)在WEB應(yīng)用程序中。
2.提高漏洞的利用難度也是一種積極的防御。
SE大牛在MOPB-08-2007中提到了phpinfo()函數(shù)存在一個(gè)XSS漏洞,影響版本是4.4.3到
4.4.6。測(cè)試方法為:alert(/XSS/);http://localhost/phpinfo.php?a[]=。
低版本的PHP對(duì)用戶輸入的變量沒有轉(zhuǎn)義就打印出來(lái),造成了一個(gè)XSS漏洞。其實(shí)這個(gè)漏
洞沒有什么好利用的,但是說(shuō)明了XSS漏洞不僅僅是存在于WEB應(yīng)用程序中。Phpinfo()函數(shù)
是PHP內(nèi)部實(shí)現(xiàn)的一個(gè)函數(shù),用來(lái)打印當(dāng)前有關(guān)PHP及環(huán)境變量的一些信息,跨站無(wú)處不在啊~
現(xiàn)在看看高版本的PHP是如何fixed這個(gè)漏洞的:)
file: standard/info.c
--630-636---
php_print_gpcse_array("_REQUEST", sizeof("_REQUEST")-1 TSRMLS_CC);
php_print_gpcse_array("_GET", sizeof("_GET")-1 TSRMLS_CC);
php_print_gpcse_array("_POST", sizeof("_POST")-1 TSRMLS_CC);
php_print_gpcse_array("_FILES", sizeof("_FILES")-1 TSRMLS_CC);
php_print_gpcse_array("_COOKIE", sizeof("_COOKIE")-1 TSRMLS_CC);
php_print_gpcse_array("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC);
php_print_gpcse_array("_ENV", sizeof("_ENV")-1 TSRMLS_CC);
--630-636---
Function php_print_gpcse_array() for any arrays check 4096b of varible.
file: standard/info.c
--135-154---
if (Z_TYPE_PP(tmp) == IS_ARRAY) {
zval *tmp3;
MAKE_STD_ZVAL(tmp3);
if (!sapi_module.phpinfo_as_text) {
PUTS("
");</p><p> }</p><p> php_start_ob_buffer(NULL, 4096, 1 TSRMLS_CC);</p><p> zend_print_zval_r(*tmp, 0);</p><p> php_ob_get_buffer(tmp3 TSRMLS_CC);</p><p> php_end_ob_buffer(0, 0 TSRMLS_CC);</p><p> elem_esc = php_info_html_esc(Z_STRVAL_P(tmp3) TSRMLS_CC);</p><p> PUTS(elem_esc);</p><p> efree(elem_esc);</p><p> zval_ptr_dtor(&tmp3);</p><p> if (!sapi_module.phpinfo_as_text) {</p><p> PUTS("");
}
} else if (Z_TYPE_PP(tmp) != IS_STRING) {
--135-154---
漏洞出現(xiàn)在php_print_gpcse_array函數(shù)中,該函數(shù)打印出630-636行的各類型的變量,
接著往下看檢查參數(shù)類型是否為數(shù)組,再通過(guò)php_start_ob_buffer函數(shù)在參數(shù)前填充了4096
字節(jié)的緩沖區(qū),當(dāng)攻擊者填充完4096字節(jié)的緩沖區(qū)后,之后的字符將不會(huì)被檢查,XSS語(yǔ)句可
以在最后得到執(zhí)行。測(cè)試方法:
phpinfo.php?cx[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]=[XSS]
phpinfo.php?cx[]=ccccc..~4096chars...ccc[XSS]
看到這里估計(jì)沒有一個(gè)檢測(cè)產(chǎn)品針對(duì)URL預(yù)留了大于4096字節(jié)的緩沖區(qū)吧。PHP針對(duì)這
個(gè)漏洞的修補(bǔ)方式也挺有意思的。
亂談續(xù)二、Word腳本執(zhí)行漏洞
按定義說(shuō)這個(gè)漏洞已經(jīng)不屬于XSS范疇了。但是這個(gè)漏洞的原因正是因?yàn)橹虚g經(jīng)過(guò)XML
的轉(zhuǎn)換。具體漏洞成因也有人分析過(guò)了,問題就出在這一段
W:data里面是base64過(guò)的XSS代碼,當(dāng)word打開時(shí)被還原解析執(zhí)行了。記得好像是前年
chinaunix的blog剛開發(fā)出來(lái)的時(shí)候發(fā)現(xiàn)了其中的一個(gè)XSS漏洞。用戶提交的輸入內(nèi)容都被
存儲(chǔ)在XML文件的CDATA部件中,什么是CDATA?在CDATA內(nèi)部的所有內(nèi)容都會(huì)被解析器忽略,也
就是原樣輸出。模擬測(cè)試代碼如下:
echo $form="
$title=$_POST["title"];
$content=$_POST["content"];
$data = "\n";
$data.= "
$data.= "
$data.= "\n";
$data.= "\n";
$fp = @fopen ("te.xml", "r+");
@fwrite($fp, $data);
@fclose ($fp);
?>
XML作為數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)十分嚴(yán)謹(jǐn),如果在XML文檔中使用類似"<" 的字符, 那么解析器將
會(huì)出現(xiàn)錯(cuò)誤,因?yàn)榻馕銎鲿?huì)認(rèn)為這是一個(gè)新元素的開始。所以利用起來(lái)要先提交]]>來(lái)閉合
去CDATA部件。所以現(xiàn)在很多過(guò)濾函數(shù)都增加了一個(gè)對(duì)“]]>”字符的過(guò)濾規(guī)則,不過(guò)還是有很
多程序沒有仔細(xì)檢查寫入XML里面的內(nèi)容,這樣當(dāng)一個(gè)RSS被引用的時(shí)候,所有瀏覽聚合的用
戶都會(huì)受到XSS攻擊。
亂談之解決
作為第三方XSS檢測(cè)程序來(lái)說(shuō),關(guān)鍵之處必定在于對(duì)HTML標(biāo)簽的分析過(guò)程。首先要能夠
分析出各個(gè)標(biāo)簽的內(nèi)容格式以及相關(guān)屬性,這是檢測(cè)XSS的第一步。
前段時(shí)間看linux內(nèi)核的進(jìn)程調(diào)度,從O(1)算法中獲得一些啟示。首先采用學(xué)習(xí)的方法
采集被保護(hù)WEB服務(wù)器一段時(shí)間的正常業(yè)務(wù)數(shù)據(jù),建立正常數(shù)據(jù)模型。接著通過(guò)對(duì)現(xiàn)有XSS攻
擊方法和變形模式的匯總建立一個(gè)數(shù)組類型的攻擊模型。前期通過(guò)比較著正常模型和攻擊
模型來(lái)確定是否存在誤報(bào)的可能,最終形成一個(gè)XSSpayload檢測(cè)的攻擊模型。當(dāng)有正常業(yè)務(wù)
數(shù)據(jù)流來(lái)臨時(shí),先進(jìn)行編碼還原,再與攻擊模型中的特征進(jìn)行匹配。如果有匹配成功的則報(bào)
警。如果有類似屬性但屬性內(nèi)容與XSSpayload不匹配的情況,則存入一個(gè)數(shù)組類型的預(yù)留模
型,這一步也可以當(dāng)作攻擊模型的一個(gè)學(xué)習(xí)過(guò)程。之后通過(guò)對(duì)預(yù)留模型中的數(shù)據(jù)進(jìn)行分析,
如果包含XSS威脅則直接歸并入攻擊模型中。
由于XSS攻擊環(huán)境多變,利用方式多變,所以個(gè)人認(rèn)為想通過(guò)徹底的研究實(shí)現(xiàn)一步解決幾
乎是一個(gè)不可能的任務(wù),學(xué)習(xí)過(guò)程再所難免。
當(dāng)然,以上只是個(gè)人觀點(diǎn),疏漏之處在所難免,還往大家多多交流,指出錯(cuò)誤!
尾聲
在此要感謝活躍在WEB安全圈子里的跨站師們,從你們的公開文章或者技巧中讓我學(xué)到
了很多。在WEB2.0的時(shí)代,想必XSS的攻擊大勢(shì)已經(jīng)來(lái)臨:)
P.S.:歡迎訪問80sec,http://www.80sec.com。
-EOF-