* 本文原創作者:lonehand,轉載請註明來自FreeBuf.COM
目前,最新的DVWA已經更新到1.9版本(http://www.dvwa.co.uk/),而網上的教程大多停留在舊版本,且沒有針對DVWA high級別的教程,因此萌發了一個撰寫新手教程的想法,錯誤的地方還請大家指正。
DVWA簡介DVWA(Damn Vulnerable Web Application)是一個用來進行安全脆弱性鑑定的PHP/MySQL Web應用,旨在為安全專業人員測試自己的專業技能和工具提供合法的環境,幫助web開發者更好的理解web應用安全防範的過程。
DVWA共有十個模塊,分別是:
Brute Force(暴力(破解))
Command Injection(命令行注入)
CSRF(跨站請求偽造)
File Inclusion(文件包含)
File Upload(文件上傳)
Insecure CAPTCHA (不安全的驗證碼)
SQL Injection(SQL注入)
SQL Injection(Blind)(SQL盲注)
XSS(Reflected)(反射型跨站腳本)
XSS(Stored)(存儲型跨站腳本)
需要注意的是,DVWA 1.9的代碼分為四種安全級別:Low,Medium,High,Impossible。初學者可以通過比較四種級別的代碼,接觸到一些PHP代碼審計的內容。
DVWA的搭建Freebuf上的文章《新手指南:手把手教你如何搭建自己的滲透測試環境》已經寫得非常好了,在這裡就不贅述了。
本篇為完結篇,介紹XSS模塊的相關內容,之前的教程包括(點擊文末的閱讀原文,查看這些文章):
Brute Force
Command Injection
CSRF
File Inclusion
File Upload
Insecure CAPTCHA
SQL Injection
SQL Injection(Blind)
XSS
XSS,全稱Cross Site Scripting,即跨站腳本攻擊,某種意義上也是一種注入攻擊,是指攻擊者在頁面中注入惡意的腳本代碼,當受害者訪問該頁面時,惡意代碼會在其瀏覽器上執行,需要強調的是,XSS不僅僅限於JavaScript,還包括flash等其它腳本語言。根據惡意代碼是否存儲在伺服器中,XSS可以分為存儲型的XSS與反射型的XSS。
DOM型的XSS由於其特殊性,常常被分為第三種,這是一種基於DOM樹的XSS。例如伺服器端經常使用document.boby.innerHtml等函數動態生成html頁面,如果這些函數在引用某些變量時沒有進行過濾或檢查,就會產生DOM型的XSS。DOM型XSS可能是存儲型,也有可能是反射型。
(註:下面的實驗都是在Firefox瀏覽器下進行的,感謝火狐沒做XSS filter)
反射型XSS下面對四種級別的代碼進行分析。
Low伺服器端核心代碼
<?php
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Feedback for end user
echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}
?>
可以看到,代碼直接引用了name參數,並沒有任何的過濾與檢查,存在明顯的XSS漏洞。
漏洞利用
輸入<script>alert(/xss/)</script>,成功彈框:
相應的XSS連結:
http://192.168.153.130/dvwa/vulnerabilities/xss_r/?name=%3Cscript%3Ealert(/xss/)%3C%2Fscript%3E#
Medium伺服器端核心代碼
<?php // Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input $name = str_replace( '<script>', '', $_GET[ 'name' ] );
// Feedback for end user echo "<pre>Hello ${name}</pre>";
}
?>
可以看到,這裡對輸入進行了過濾,基於黑名單的思想,使用str_replace函數將輸入中的<script>刪除,這種防護機制是可以被輕鬆繞過的。
漏洞利用
1.雙寫繞過
輸入<sc<script>ript>alert(/xss/)</script>,成功彈框:
相應的XSS連結:
http://192.168.153.130/dvwa/vulnerabilities/xss_r/?name=%3Csc%3Cscript%3Eript%3Ealert%28%2Fxss%2F%29%3C%2Fscript%3E#
2.大小寫混淆繞過
輸入<ScRipt>alert(/xss/)</script>,成功彈框:
相應的XSS連結:
http://192.168.153.130/dvwa/vulnerabilities/xss_r/?name=%3CScRipt%3Ealert(%2Fxss%2F)%3C%2Fscript%3E#
High伺服器端核心代碼
<?php // Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );
// Feedback for end user echo "<pre>Hello ${name}</pre>";
}
?>
可以看到,High級別的代碼同樣使用黑名單過濾輸入,preg_replace() 函數用於正則表達式的搜索和替換,這使得雙寫繞過、大小寫混淆繞過(正則表達式中i表示不區分大小寫)不再有效。
漏洞利用
雖然無法使用<script>標籤注入XSS代碼,但是可以通過img、body等標籤的事件或者iframe等標籤的src注入惡意的js代碼。
輸入<img src=1 onerror=alert(/xss/)>,成功彈框:
相應的XSS連結:
http://192.168.153.130/dvwa/vulnerabilities/xss_r/?name=%3Cimg+src%3D1+onerror%3Dalert%28%2Fxss%2F%29%3E#
Impossible伺服器端核心代碼
<?php // Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input $name = htmlspecialchars( $_GET[ 'name' ] );
// Feedback for end user echo "<pre>Hello ${name}</pre>";
}
// Generate Anti-CSRF token generateSessionToken();
?>
可以看到,Impossible級別的代碼使用htmlspecialchars函數把預定義的字符&、」、』、<、>轉換為 HTML 實體,防止瀏覽器將其作為HTML元素。
存儲型XSS
下面對四種級別的代碼進行分析。
Low伺服器端核心代碼
<?php if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input $message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input $message = stripslashes( $message );
$message = mysql_real_escape_string( $message );
// Sanitize name input $name = mysql_real_escape_string( $name );
// Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
//mysql_close(); }
?>
相關函數介紹
trim(string,charlist)
函數移除字符串兩側的空白字符或其他預定義字符,預定義字符包括、\t、\n、\x0B、\r以及空格,可選參數charlist支持添加額外需要刪除的字符。
mysql_real_escape_string(string,connection)
函數會對字符串中的特殊符號(\x00,\n,\r,\,『,「,\x1a)進行轉義。
stripslashes(string)
函數刪除字符串中的反斜槓。
可以看到,對輸入並沒有做XSS方面的過濾與檢查,且存儲在資料庫中,因此這裡存在明顯的存儲型XSS漏洞。
漏洞利用
message一欄輸入<script>alert(/xss/)</script>,成功彈框:
name一欄前端有字數限制,抓包改為<script>alert(/name/)</script>:
成功彈框:
Medium伺服器端核心代碼
<?php if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input $message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input $message = strip_tags( addslashes( $message ) );
$message = mysql_real_escape_string( $message );
$message = htmlspecialchars( $message );
// Sanitize name input $name = str_replace( '<script>', '', $name );
$name = mysql_real_escape_string( $name );
// Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
//mysql_close(); }
?>
相關函數說明
strip_tags() 函數剝去字符串中的 HTML、XML 以及 PHP 的標籤,但允許使用<b>標籤。
addslashes() 函數返回在預定義字符(單引號、雙引號、反斜槓、NULL)之前添加反斜槓的字符串。
可以看到,由於對message參數使用了htmlspecialchars函數進行編碼,因此無法再通過message參數注入XSS代碼,但是對於name參數,只是簡單過濾了<script>字符串,仍然存在存儲型的XSS。
漏洞利用
1.雙寫繞過
抓包改name參數為<sc<script>ript>alert(/xss/)</script>:
成功彈框
2.大小寫混淆繞過
抓包改name參數為<Script>alert(/xss/)</script>:
成功彈框:
High伺服器端核心代碼
<?php if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input $message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input $message = strip_tags( addslashes( $message ) );
$message = mysql_real_escape_string( $message );
$message = htmlspecialchars( $message );
// Sanitize name input $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
$name = mysql_real_escape_string( $name );
// Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
//mysql_close(); }
?>
可以看到,這裡使用正則表達式過濾了<script>標籤,但是卻忽略了img、iframe等其它危險的標籤,因此name參數依舊存在存儲型XSS。
High
抓包改name參數為<img src=1 onerror=alert(1)>:
成功彈框:
Impossible伺服器端核心代碼
<?php if( isset( $_POST[ 'btnSign' ] ) ) {
// Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input $message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input $message = stripslashes( $message );
$message = mysql_real_escape_string( $message );
$message = htmlspecialchars( $message );
// Sanitize name input $name = stripslashes( $name );
$name = mysql_real_escape_string( $name );
$name = htmlspecialchars( $name );
// Update database $data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' );
$data->bindParam( ':message', $message, PDO::PARAM_STR );
$data->bindParam( ':name', $name, PDO::PARAM_STR );
$data->execute();
}
// Generate Anti-CSRF token generateSessionToken();
?>
可以看到,通過使用htmlspecialchars函數,解決了XSS,但是要注意的是,如果htmlspecialchars函數使用不當,攻擊者就可以通過編碼的方式繞過函數進行XSS注入,尤其是DOM型的XSS。
最後附贈最近遇到的一個實例:一次有趣的XSS+CSRF組合拳
0×01 前言最近執著於滲透各種xx人才網,前兩天在某網站上發現了一個極其雞肋的XSS漏洞,本來以為沒有太大的利用價值,沒想到結合CSRF攻擊,卻獲得了意想不到的效果。
0×02 一個雞肋的XSS漏洞下面是某個招聘網站的用戶個人資料界面:
用戶可以在這裡修改自己的基本資料並保存,經過XSS測試,這裡的輸入都過濾了成對的尖括號(< >)、script、img、&等字符,但是似乎遺漏了事件,於是嘗試使用input標籤的onchange事件注入XSS代碼。
在通訊地址一欄輸入」 onchange=alert(2) 「並保存,刷新頁面,右鍵查看源碼,注入成功:
只要嘗試在通訊地址一欄中輸入新的內容,就會觸發XSS,彈框:
是的,成功觸發XSS代碼了,可是這個雞肋的XSS漏洞有什麼卵用呢?首先,這個XSS漏洞依賴事件觸發,只有用戶在修改個人資料時惡意代碼才有可能執行,其次這是一個存儲型的XSS漏洞,你不可能要求用戶按照攻擊者的意思,事先在自己的個人資料裡鍵入XSS代碼並保存吧。
0×03 CSRF帶來的曙光在修改個人資料的過程中,抓包發現這個修改接口並沒有任何的防CSRF機制,存在明顯的CSRF漏洞:
這給雞肋的XSS漏洞帶來了曙光,於是想到了可以結合CSRF攻擊實現用戶cookie的大面積盜取。攻擊思路如下:
1.構造一個CSRF攻擊頁面,誘使用戶訪問(在這種招聘網站,發布一個包含惡意頁面的虛假招聘很容易做到)
2.用戶訪問頁面後,個人基本資料會被清空,同時注入XSS代碼
3.用戶嘗試補全個人資料,觸發XSS代碼,自動發送cookie
0×04 攻擊演示下面是構造的CSRF攻擊頁面:
調皮地把cookie發(這裡調皮地把cookie發給百度= =)
下面是本地的攻擊過程演示:
1.受害者進入攻擊頁面,會看到「你的基本資料被我清空了」的提示:
還會看到資料修改成功的提示,並跳轉:
2.這時候受害者會發現自己的個人資料被清空了:
卻不知道已經被注入了XSS代碼:
3.當用戶嘗試修改通訊地址一欄時,就會觸發XSS代碼,自動發送cookie(其中包含用戶id、用戶名、密碼哈希值、session-id) :
這樣,大規模盜取用戶cookie的攻擊也就完成了。
* 本文原創作者:lonehand,轉載請註明來自FreeBuf.COM