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代碼審計的內容。
XSS
XSS,全稱Cross Site Scripting,即跨站腳本攻擊,某種意義上也是一種注入攻擊,是指攻擊者在頁面中注入惡意的腳本代碼,當受害者訪問該頁面時,惡意代碼會在其瀏覽器上執行,需要強調的是,XSS不僅僅限於JavaScript,還包括flash等其它腳本語言。根據惡意代碼是否存儲在服務器中,XSS可以分為存儲型的XSS與反射型的XSS。
DOM型的XSS由於其特殊性,常常被分為第三種,這是一種基於DOM樹的XSS。例如服務器端經常使用document.boby.innerHtml等函數動態生成html頁面,如果這些函數在引用某些變量時沒有進行過濾或檢查,就會產生DOM型的XSS。DOM型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>
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>刪除,這種防護機制是可以被輕松繞過的。
漏洞利用:使用雙寫繞過:<sc<script>ript>alert(/xss/)</script> 成功彈框
或者大小寫混合繞過:<ScRipt>alert(/xss/)</script>
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
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一欄中有長度限制,可以抓包之后再修改數據
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。
漏洞利用:
抓包雙寫繞過:<sc<script>ript>alert(/xss/)</script>
成功彈窗:
或者大小寫混合繞過:
<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。
漏洞利用:
抓包改name參數為<img src=1 onerror=alert(1)>:
成功彈框