PHP Tricks
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Cookies common location:
Це також стосується куків phpMyAdmin.
Cookies:
Місця:
Обхід порівнянь PHP
Слабкі порівняння/Типове маніпулювання ( == )
Якщо в PHP використовується ==
, то є несподівані випадки, коли порівняння не веде себе так, як очікується. Це пов'язано з тим, що "==" порівнює лише значення, перетворені в один і той же тип, якщо ви також хочете порівняти, що тип порівнюваних даних однаковий, вам потрібно використовувати ===
.
Таблиці порівняння PHP: https://www.php.net/manual/en/types.comparisons.php
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F2585115637-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FhAv2kYoPrT3n8552GaQU%252Fuploads%252Fgit-blob-53dd523e3097738b14730e72b491c182672a1fc0%252Fimage%2520%28567%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=ff72bbee&sv=1)
"string" == 0 -> True
Рядок, який не починається з числа, дорівнює числу"0xAAAA" == "43690" -> True
Рядки, що складаються з чисел у десятковому або шістнадцятковому форматі, можуть бути порівняні з іншими числами/рядками з результатом True, якщо числа були однаковими (числа в рядку інтерпретуються як числа)"0e3264578" == 0 --> True
Рядок, що починається з "0e" і за яким слідує будь-що, буде дорівнювати 0"0X3264578" == 0X --> True
Рядок, що починається з "0" і за яким слідує будь-яка літера (X може бути будь-якою літерою) і за яким слідує будь-що, буде дорівнювати 0"0e12334" == "0" --> True
Це дуже цікаво, оскільки в деяких випадках ви можете контролювати вхідний рядок "0" і деякий вміст, який хешується і порівнюється з ним. Тому, якщо ви можете надати значення, яке створить хеш, що починається з "0e" і без будь-якої літери, ви могли б обійти порівняння. Ви можете знайти вже захешовані рядки з цим форматом тут: https://github.com/spaze/hashes"X" == 0 --> True
Будь-яка літера в рядку дорівнює int 0
Більше інформації на https://medium.com/swlh/php-type-juggling-vulnerabilities-3e28c4ed5c09
in_array()
Типове маніпулювання також впливає на функцію in_array()
за замовчуванням (вам потрібно встановити третій аргумент в true, щоб зробити строгий порівняння):
strcmp()/strcasecmp()
Якщо ця функція використовується для будь-якої перевірки автентифікації (наприклад, перевірка пароля) і користувач контролює одну сторону порівняння, він може надіслати порожній масив замість рядка як значення пароля (https://example.com/login.php/?username=admin&password[]=
) і обійти цю перевірку:
Та ж помилка виникає з strcasecmp()
Жорстке приведення типів
Навіть якщо ===
використовується, можуть бути помилки, які роблять порівняння вразливим до приведення типів. Наприклад, якщо порівняння перетворює дані в інший тип об'єкта перед порівнянням:
preg_match(/^.*/)
preg_match()
може бути використано для перевірки введення користувача (він перевіряє, чи є будь-яке слово/регулярний вираз з чорного списку присутнім у введенні користувача, і якщо його немає, код може продовжити своє виконання).
Обхід нового рядка
Однак, при обмеженні початку регулярного виразу preg_match()
перевіряє лише перший рядок введення користувача, тому, якщо якимось чином ви зможете надіслати введення в кількох рядках, ви зможете обійти цю перевірку. Приклад:
Щоб обійти цю перевірку, ви можете надіслати значення з новими рядками, закодованими в URL (%0A
), або якщо ви можете надіслати JSON-дані, надішліть їх у кількох рядках:
Знайдіть приклад тут: https://ramadistra.dev/fbctf-2019-rceservice
Обхід помилки довжини
(Цей обхід, очевидно, був спробований на PHP 5.2.5, і мені не вдалося змусити його працювати на PHP 7.3.15)
Якщо ви зможете надіслати preg_match()
дійсний дуже великий вхід, він не зможе його обробити і ви зможете обійти перевірку. Наприклад, якщо він блокує JSON, ви можете надіслати:
From: https://medium.com/bugbountywriteup/solving-each-and-every-fb-ctf-challenge-part-1-4bce03e2ecb0
ReDoS Bypass
Trick from: https://simones-organization-4.gitbook.io/hackbook-of-a-hacker/ctf-writeups/intigriti-challenges/1223 and https://mizu.re/post/pong
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F2585115637-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FhAv2kYoPrT3n8552GaQU%252Fuploads%252Fgit-blob-746083bbabdbedd055c5dddac1d3ebcce0f1f726%252Fimage%2520%2826%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=280a74b3&sv=1)
Коротко кажучи, проблема виникає через те, що функції preg_*
у PHP базуються на бібліотеці PCRE. У PCRE певні регулярні вирази співпадають, використовуючи багато рекурсивних викликів, що займає багато стекового простору. Можливо встановити обмеження на кількість дозволених рекурсій, але в PHP це обмеження за замовчуванням становить 100.000, що більше, ніж вміщується в стек.
Ця тема на Stackoverflow також була згадана в пості, де більш детально обговорюється ця проблема. Наше завдання стало зрозумілим:
Надіслати вхідні дані, які змусили б regex виконати 100_000+ рекурсій, викликавши SIGSEGV, змусивши функцію preg_match()
повернути false
, таким чином змусивши додаток вважати, що наші вхідні дані не є шкідливими, підкидаючи сюрприз в кінці корисного навантаження щось на кшталт {system(<verybadcommand>)}
для отримання SSTI --> RCE --> flag :).
Отже, в термінах regex, ми насправді не виконуємо 100k "рекурсій", а замість цього ми рахуємо "кроки назад", які, як зазначає документація PHP, за замовчуванням становлять 1_000_000 (1M) у змінній pcre.backtrack_limit
.\ Щоб досягти цього, 'X'*500_001
призведе до 1 мільйона кроків назад (500k вперед і 500k назад):
Перетворення типів для обфускації PHP
Execute After Redirect (EAR)
Якщо PHP перенаправляє на іншу сторінку, але жодна функція die
або exit
не викликається після того, як заголовок Location
встановлено, PHP продовжує виконання та додає дані до тіла:
Вразливість обходу шляху та включення файлів
Перевірте:
File Inclusion/Path traversalБільше трюків
register_globals: У PHP < 4.1.1.1 або якщо неправильно налаштовано, register_globals може бути активним (або їхня поведінка імітується). Це означає, що в глобальних змінних, таких як $_GET, якщо вони мають значення, наприклад, $_GET["param"]="1234", ви можете отримати доступ до них через $param. Таким чином, відправляючи HTTP параметри, ви можете перезаписати змінні, які використовуються в коді.
PHPSESSION куки одного домену зберігаються в одному місці, тому якщо в межах домену використовуються різні куки в різних шляхах, ви можете зробити так, щоб шлях отримував доступ до куки іншого шляху, встановивши значення куки іншого шляху. Таким чином, якщо обидва шляхи отримують доступ до змінної з однаковою назвою, ви можете зробити так, щоб значення цієї змінної в path1 застосовувалося до path2. І тоді path2 вважатиме змінні path1 дійсними (надаючи куки ім'я, яке відповідає йому в path2).
Коли у вас є імена користувачів користувачів машини. Перевірте адресу: /~<USERNAME>, щоб дізнатися, чи активовані php каталоги.
password_hash/password_verify
Ці функції зазвичай використовуються в PHP для генерації хешів з паролів та для перевірки, чи є пароль правильним у порівнянні з хешем.
Підтримувані алгоритми: PASSWORD_DEFAULT
та PASSWORD_BCRYPT
(починається з $2y$
). Зверніть увагу, що PASSWORD_DEFAULT часто є тим же, що і PASSWORD_BCRYPT. І наразі PASSWORD_BCRYPT має обмеження на розмір вхідних даних у 72 байти. Тому, коли ви намагаєтеся згенерувати хеш для чогось більшого за 72 байти за допомогою цього алгоритму, будуть використані лише перші 72B:
HTTP заголовки обхід зловживання помилками PHP
Виклик помилки після встановлення заголовків
З цього треду в твіттері ви можете побачити, що надсилаючи більше ніж 1000 GET параметрів або 1000 POST параметрів або 20 файлів, PHP не буде встановлювати заголовки у відповіді.
Це дозволяє обійти, наприклад, заголовки CSP, які встановлюються в кодах, таких як:
Заповнення тіла перед встановленням заголовків
Якщо PHP-сторінка виводить помилки та відображає деякі дані, надані користувачем, користувач може змусити PHP-сервер вивести деякий контент достатньої довжини, так що коли він намагається додати заголовки до відповіді, сервер видасть помилку. У наступному сценарії зловмисник змусив сервер видати великі помилки, і, як ви можете бачити на екрані, коли PHP намагався змінити інформацію заголовка, він не зміг (тому, наприклад, заголовок CSP не був надісланий користувачу):
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F2585115637-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FhAv2kYoPrT3n8552GaQU%252Fuploads%252Fgit-blob-14119d0754739cfdb01a8cdd752ea4a282899451%252Fimage%2520%281085%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=9a1f2385&sv=1)
SSRF у функціях PHP
Перевірте сторінку:
PHP SSRFВиконання коду
system("ls"); `ls`; shell_exec("ls");
Перевірте це для більш корисних функцій PHP
RCE через preg_replace()
Щоб виконати код у аргументі "replace", потрібне принаймні одне співпадіння. Ця опція preg_replace була застаріла з PHP 5.5.0.
RCE через Eval()
RCE через Assert()
Ця функція в php дозволяє вам виконувати код, написаний у рядку, щоб повернути true або false (і в залежності від цього змінити виконання). Зазвичай змінна користувача буде вставлена в середину рядка. Наприклад:
assert("strpos($_GET['page']),'..') === false")
--> У цьому випадку, щоб отримати RCE, ви могли б зробити:
Вам потрібно зламати синтаксис коду, додати ваш payload, а потім виправити його знову. Ви можете використовувати логічні операції такі як "and" або "%26%26" або "|". Зверніть увагу, що "or", "||" не працює, оскільки якщо перша умова істинна, наш payload не буде виконано. Так само ";" не працює, оскільки наш payload не буде виконано.
Інша опція - додати до рядка виконання команди: '.highlight_file('.passwd').'
Інша опція (якщо у вас є внутрішній код) - змінити деяку змінну, щоб змінити виконання: $file = "hola"
RCE через usort()
Ця функція використовується для сортування масиву елементів за допомогою конкретної функції. Щоб зловживати цією функцією:
Ви також можете використовувати // для коментування решти коду.
Щоб виявити кількість дужок, які потрібно закрити:
?order=id;}//
: ми отримуємо повідомлення про помилку (Parse error: syntax error, unexpected ';'
). Можливо, нам не вистачає однієї або кількох дужок.?order=id);}//
: ми отримуємо попередження. Це, здається, правильно.?order=id));}//
: ми отримуємо повідомлення про помилку (Parse error: syntax error, unexpected ')' i
). Можливо, у нас занадто багато закриваючих дужок.
RCE через .httaccess
Якщо ви можете завантажити .htaccess, то ви можете налаштувати кілька речей і навіть виконати код (налаштувавши, щоб файли з розширенням .htaccess могли бути виконані).
Різні оболонки .htaccess можна знайти тут
RCE через змінні середовища
Якщо ви знайдете вразливість, яка дозволяє вам модифікувати змінні середовища в PHP (і ще одну для завантаження файлів, хоча з більшою дослідженням, можливо, це можна обійти), ви могли б зловживати цією поведінкою, щоб отримати RCE.
LD_PRELOAD
: Ця змінна середовища дозволяє вам завантажувати довільні бібліотеки під час виконання інших бінарних файлів (хоча в цьому випадку це може не спрацювати).PHPRC
: Інструктує PHP про де знайти свій конфігураційний файл, зазвичай називаєтьсяphp.ini
. Якщо ви можете завантажити свій власний конфігураційний файл, то використовуйтеPHPRC
, щоб вказати PHP на нього. Додайте записauto_prepend_file
, що вказує на другий завантажений файл. Цей другий файл містить звичайний PHP код, який потім виконується PHP-інтерпретатором перед будь-яким іншим кодом.
Завантажте PHP файл, що містить наш shellcode
Завантажте другий файл, що містить директиву
auto_prepend_file
, інструктуючи PHP-препроцесор виконати файл, який ми завантажили на етапі 1Встановіть змінну
PHPRC
на файл, який ми завантажили на етапі 2.
Отримайте більше інформації про те, як виконати цей ланцюг з оригінального звіту.
PHPRC - ще один варіант
Якщо ви не можете завантажити файли, ви можете використовувати в FreeBSD "файл"
/dev/fd/0
, який міститьstdin
, будучи тілом запиту, надісланого доstdin
:curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary 'auto_prepend_file="/etc/passwd"'
Або для отримання RCE, увімкніть
allow_url_include
і додайте файл з base64 PHP кодом:curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary $'allow_url_include=1\nauto_prepend_file="data://text/plain;base64,PD8KICAgcGhwaW5mbygpOwo/Pg=="'
Техніка з цього звіту.
XAMPP CGI RCE - CVE-2024-4577
Веб-сервер аналізує HTTP запити і передає їх PHP скрипту, виконуючи запит, такий як http://host/cgi.php?foo=bar
як php.exe cgi.php foo=bar
, що дозволяє ін'єкцію параметрів. Це дозволить ін'єктувати наступні параметри для завантаження PHP коду з тіла:
Крім того, можливо ввести параметр "-" за допомогою символу 0xAD через подальшу нормалізацію PHP. Перевірте приклад експлуатації з цього посту:
PHP Sanitization bypass & Brain Fuck
У цьому пості можна знайти чудові ідеї для генерації brain fuck PHP коду з дуже обмеженою кількістю дозволених символів. Більше того, також пропонується цікавий спосіб виконання функцій, які дозволили їм обійти кілька перевірок:
PHP Статичний аналіз
Подивіться, чи можете ви вставити код у виклики цих функцій (з тут):
Якщо ви налагоджуєте PHP-додаток, ви можете глобально увімкнути друк помилок у /etc/php5/apache2/php.ini
, додавши display_errors = On
, і перезапустити apache: sudo systemctl restart apache2
Деобфускація PHP-коду
Ви можете використовувати web www.unphp.net для деобфускації php-коду.
PHP обгортки та протоколи
PHP обгортки та протоколи можуть дозволити вам обійти захисти на запис і читання в системі та скомпрометувати її. Для додаткової інформації перегляньте цю сторінку.
Xdebug неавторизований RCE
Якщо ви бачите, що Xdebug увімкнено в phpconfig()
виводі, вам слід спробувати отримати RCE через https://github.com/nqxcode/xdebug-exploit
Змінні змінних
RCE зловживання новим $_GET["a"]($_GET["b")
Якщо на сторінці ви можете створити новий об'єкт довільного класу, ви можете отримати RCE, перевірте наступну сторінку, щоб дізнатися як:
PHP - RCE abusing object creation: new $_GET["a"]($_GET["b"])Виконання PHP без літер
https://securityonline.info/bypass-waf-php-webshell-without-numbers-letters/
Використання воськової системи
XOR
XOR easy shell code
Згідно з цією статтею можливо згенерувати простий shellcode таким чином:
Отже, якщо ви можете виконувати довільний PHP без цифр і літер, ви можете надіслати запит, подібний до наступного, зловживаючи цим корисним навантаженням для виконання довільного PHP:
Для більш детального пояснення перегляньте https://ctf-wiki.org/web/php/php/#preg_match
XOR Shellcode (всередині eval)
Perl подібний
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Last updated