PHP Tricks
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Typowa lokalizacja ciasteczek:
To również dotyczy ciasteczek phpMyAdmin.
Ciasteczka:
Lokalizacje:
Obejście porównań PHP
Luźne porównania/Typ Juggling ( == )
Jeśli ==
jest używane w PHP, to istnieją nieoczekiwane przypadki, w których porównanie nie zachowuje się zgodnie z oczekiwaniami. Dzieje się tak, ponieważ "==" porównuje tylko wartości przekształcone do tego samego typu, jeśli chcesz również porównać, że typ porównywanych danych jest taki sam, musisz użyć ===
.
Tabele porównań PHP: https://www.php.net/manual/en/types.comparisons.php
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F600722126-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FJtticLwENZ4i7WwgHiQe%252Fuploads%252Fgit-blob-53dd523e3097738b14730e72b491c182672a1fc0%252Fimage%2520%28567%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=86b64d12&sv=1)
"string" == 0 -> True
Ciąg znaków, który nie zaczyna się od liczby, jest równy liczbie"0xAAAA" == "43690" -> True
Ciągi składające się z liczb w formacie dziesiętnym lub szesnastkowym mogą być porównywane z innymi liczbami/ciągami z wynikiem True, jeśli liczby były takie same (liczby w ciągu są interpretowane jako liczby)"0e3264578" == 0 --> True
Ciąg zaczynający się od "0e" i następnie cokolwiek będzie równy 0"0X3264578" == 0X --> True
Ciąg zaczynający się od "0" i następnie dowolna litera (X może być dowolną literą) i następnie cokolwiek będzie równy 0"0e12334" == "0" --> True
To jest bardzo interesujące, ponieważ w niektórych przypadkach możesz kontrolować ciąg wejściowy "0" oraz niektóre treści, które są haszowane i porównywane z nim. Dlatego, jeśli możesz dostarczyć wartość, która stworzy hash zaczynający się od "0e" i bez żadnej litery, możesz obejść porównanie. Możesz znaleźć już haszowane ciągi w tym formacie tutaj: https://github.com/spaze/hashes"X" == 0 --> True
Dowolna litera w ciągu jest równa int 0
Więcej informacji w https://medium.com/swlh/php-type-juggling-vulnerabilities-3e28c4ed5c09
in_array()
Typ Juggling również wpływa na funkcję in_array()
domyślnie (musisz ustawić trzeci argument na true, aby dokonać ścisłego porównania):
strcmp()/strcasecmp()
Jeśli ta funkcja jest używana do jakiejkolwiek weryfikacji uwierzytelnienia (jak sprawdzanie hasła) i użytkownik kontroluje jedną stronę porównania, może wysłać pustą tablicę zamiast ciągu jako wartość hasła (https://example.com/login.php/?username=admin&password[]=
) i obejść tę weryfikację:
Ten sam błąd występuje z strcasecmp()
Ścisłe mieszanie typów
Nawet jeśli ===
jest używane, mogą wystąpić błędy, które sprawiają, że porównanie jest podatne na mieszanie typów. Na przykład, jeśli porównanie konwertuje dane na inny typ obiektu przed porównaniem:
preg_match(/^.*/)
preg_match()
może być użyty do walidacji danych wejściowych użytkownika (sprawdza, czy jakiekolwiek słowo/regex z czarnej listy jest obecne w danych wejściowych użytkownika, a jeśli nie, kod może kontynuować swoje wykonanie).
Ominięcie nowej linii
Jednakże, przy delimitacji początku regexp preg_match()
sprawdza tylko pierwszą linię danych wejściowych użytkownika, więc jeśli w jakiś sposób możesz wysłać dane wejściowe w kilku liniach, możesz być w stanie obejść to sprawdzenie. Przykład:
Aby obejść tę kontrolę, możesz wysłać wartość z nowymi liniami zakodowanymi w URL (%0A
) lub jeśli możesz wysłać dane JSON, wyślij je w kilku liniach:
Znajdź przykład tutaj: https://ramadistra.dev/fbctf-2019-rceservice
Obejście błędu długości
(To obejście było podobno testowane na PHP 5.2.5 i nie mogłem go uruchomić na PHP 7.3.15)
Jeśli możesz wysłać do preg_match()
ważny bardzo duży input, nie będzie w stanie go przetworzyć i będziesz mógł obejść kontrolę. Na przykład, jeśli czarna lista dotyczy JSON-a, możesz wysłać:
From: https://medium.com/bugbountywriteup/solving-each-and-every-fb-ctf-challenge-part-1-4bce03e2ecb0
Ominięcie ReDoS
Sztuczka z: https://simones-organization-4.gitbook.io/hackbook-of-a-hacker/ctf-writeups/intigriti-challenges/1223 i https://mizu.re/post/pong
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F600722126-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FJtticLwENZ4i7WwgHiQe%252Fuploads%252Fgit-blob-746083bbabdbedd055c5dddac1d3ebcce0f1f726%252Fimage%2520%2826%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=c76888a7&sv=1)
Krótko mówiąc, problem występuje, ponieważ funkcje preg_*
w PHP opierają się na bibliotece PCRE. W PCRE niektóre wyrażenia regularne są dopasowywane przy użyciu wielu wywołań rekurencyjnych, co zużywa dużo miejsca na stosie. Można ustawić limit na liczbę dozwolonych rekurencji, ale w PHP ten limit domyślnie wynosi 100.000, co jest więcej niż mieści się na stosie.
Ten wątek na Stackoverflow również został podlinkowany w poście, w którym bardziej szczegółowo omawiano ten problem. Nasze zadanie było teraz jasne:
Wyślij dane wejściowe, które spowodują, że regex wykona 100_000+ rekurencji, powodując SIGSEGV, co sprawi, że funkcja preg_match()
zwróci false
, a tym samym aplikacja pomyśli, że nasze dane wejściowe nie są złośliwe, zaskakując na końcu ładunku czymś w rodzaju {system(<verybadcommand>)}
w celu uzyskania SSTI --> RCE --> flagi :).
Cóż, w terminach regex, tak naprawdę nie wykonujemy 100k "rekurencji", ale zamiast tego liczymy "kroki cofania", które, jak stwierdza dokumentacja PHP, domyślnie wynosi 1_000_000 (1M) w zmiennej pcre.backtrack_limit
.\ Aby to osiągnąć, 'X'*500_001
spowoduje 1 milion kroków cofania (500k do przodu i 500k do tyłu):
Typowe przełączanie typów dla obfuskacji PHP
Execute After Redirect (EAR)
Jeśli PHP przekierowuje na inną stronę, ale żadna funkcja die
lub exit
nie jest wywoływana po ustawieniu nagłówka Location
, PHP kontynuuje wykonywanie i dodaje dane do treści:
Wykorzystanie przejścia ścieżki i włączenia plików
Sprawdź:
File Inclusion/Path traversalWięcej sztuczek
register_globals: W PHP < 4.1.1.1 lub w przypadku błędnej konfiguracji, register_globals może być aktywne (lub ich zachowanie jest naśladowane). Oznacza to, że w zmiennych globalnych, takich jak $_GET, jeśli mają wartość np. $_GET["param"]="1234", możesz uzyskać do nich dostęp przez $param. Dlatego, wysyłając parametry HTTP, możesz nadpisać zmienne używane w kodzie.
Ciasteczka PHPSESSION tej samej domeny są przechowywane w tym samym miejscu, dlatego jeśli w obrębie domeny różne ciasteczka są używane w różnych ścieżkach, możesz sprawić, że jedna ścieżka uzyska dostęp do ciasteczka drugiej ścieżki, ustawiając wartość ciasteczka innej ścieżki. W ten sposób, jeśli obie ścieżki uzyskują dostęp do zmiennej o tej samej nazwie, możesz sprawić, że wartość tej zmiennej w path1 będzie miała zastosowanie w path2. A następnie path2 uzna zmienne path1 za ważne (nadając ciasteczku nazwę, która odpowiada jej w path2).
Kiedy masz nazwy użytkowników użytkowników maszyny. Sprawdź adres: /~<USERNAME>, aby zobaczyć, czy katalogi php są aktywowane.
password_hash/password_verify
Funkcje te są zazwyczaj używane w PHP do generowania hashy z haseł i do sprawdzania, czy hasło jest poprawne w porównaniu z hashem.
Obsługiwane algorytmy to: PASSWORD_DEFAULT
i PASSWORD_BCRYPT
(zaczyna się od $2y$
). Zauważ, że PASSWORD_DEFAULT często jest tym samym co PASSWORD_BCRYPT. A obecnie, PASSWORD_BCRYPT ma ograniczenie rozmiaru wejścia do 72 bajtów. Dlatego, gdy próbujesz zhashować coś większego niż 72 bajty za pomocą tego algorytmu, tylko pierwsze 72B zostanie użyte:
HTTP headers bypass abusing PHP errors
Causing error after setting headers
Z tego wątku na Twitterze można zobaczyć, że wysyłając więcej niż 1000 parametrów GET lub 1000 parametrów POST lub 20 plików, PHP nie ustawi nagłówków w odpowiedzi.
Pozwala to na obejście na przykład nagłówków CSP ustawianych w kodach takich jak:
Wypełnianie ciała przed ustawieniem nagłówków
Jeśli strona PHP wyświetla błędy i zwraca niektóre dane wprowadzone przez użytkownika, użytkownik może sprawić, że serwer PHP zwróci treść wystarczająco długą, aby podczas próby dodania nagłówków do odpowiedzi serwer zgłosił błąd. W następującym scenariuszu atakujący spowodował, że serwer zgłosił kilka dużych błędów, a jak widać na ekranie, gdy PHP próbowało zmodyfikować informacje o nagłówkach, nie mogło (na przykład nagłówek CSP nie został wysłany do użytkownika):
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F600722126-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FJtticLwENZ4i7WwgHiQe%252Fuploads%252Fgit-blob-14119d0754739cfdb01a8cdd752ea4a282899451%252Fimage%2520%281085%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=82370169&sv=1)
SSRF w funkcjach PHP
Sprawdź stronę:
PHP SSRFWykonanie kodu
system("ls"); `ls`; shell_exec("ls");
Sprawdź to dla bardziej przydatnych funkcji PHP
RCE za pomocą preg_replace()
Aby wykonać kod w argumencie "replace", potrzebne jest przynajmniej jedno dopasowanie. Ta opcja preg_replace została wycofana od PHP 5.5.0.
RCE za pomocą Eval()
RCE via Assert()
Ta funkcja w php pozwala na wykonywanie kodu zapisanego w ciągu w celu zwrócenia true lub false (a w zależności od tego zmienić wykonanie). Zazwyczaj zmienna użytkownika będzie wstawiana w środek ciągu. Na przykład:
assert("strpos($_GET['page']),'..') === false")
--> W tym przypadku, aby uzyskać RCE, możesz zrobić:
Będziesz musiał złamać składnię kodu, dodać swój ładunek, a następnie naprawić to z powrotem. Możesz użyć operacji logicznych takich jak "and" lub "%26%26" lub "|". Zauważ, że "or", "||" nie działa, ponieważ jeśli pierwszy warunek jest prawdziwy, nasz ładunek nie zostanie wykonany. W ten sam sposób ";" nie działa, ponieważ nasz ładunek nie zostanie wykonany.
Inną opcją jest dodanie do ciągu wykonania polecenia: '.highlight_file('.passwd').'
Inną opcją (jeśli masz wewnętrzny kod) jest modyfikacja niektórej zmiennej, aby zmienić wykonanie: $file = "hola"
RCE za pomocą usort()
Ta funkcja jest używana do sortowania tablicy elementów za pomocą określonej funkcji. Aby nadużyć tej funkcji:
Możesz również użyć // do komentowania reszty kodu.
Aby odkryć liczbę nawiasów, które musisz zamknąć:
?order=id;}//
: otrzymujemy komunikat o błędzie (Parse error: syntax error, unexpected ';'
). Prawdopodobnie brakuje nam jednego lub więcej nawiasów.?order=id);}//
: otrzymujemy ostrzeżenie. To wydaje się w porządku.?order=id));}//
: otrzymujemy komunikat o błędzie (Parse error: syntax error, unexpected ')' i
). Prawdopodobnie mamy za dużo zamykających nawiasów.
RCE przez .httaccess
Jeśli możesz przesłać .htaccess, to możesz skonfigurować kilka rzeczy, a nawet wykonać kod (konfigurując, że pliki z rozszerzeniem .htaccess mogą być wykonywane).
Różne powłoki .htaccess można znaleźć tutaj
RCE przez zmienne środowiskowe
Jeśli znajdziesz lukę, która pozwala ci modyfikować zmienne środowiskowe w PHP (i inną, aby przesyłać pliki, chociaż z większym badaniem może to być możliwe do obejścia), możesz nadużyć tego zachowania, aby uzyskać RCE.
LD_PRELOAD
: Ta zmienna środowiskowa pozwala na ładowanie dowolnych bibliotek podczas wykonywania innych binarnych (chociaż w tym przypadku może to nie działać).PHPRC
: Instrukcja dla PHP, gdzie znaleźć plik konfiguracyjny, zazwyczaj nazywanyphp.ini
. Jeśli możesz przesłać własny plik konfiguracyjny, użyjPHPRC
, aby wskazać PHP na niego. Dodaj wpisauto_prepend_file
, określający drugi przesłany plik. Ten drugi plik zawiera normalny kod PHP, który jest następnie wykonywany przez środowisko PHP przed jakimkolwiek innym kodem.
Prześlij plik PHP zawierający nasz shellcode
Prześlij drugi plik, zawierający dyrektywę
auto_prepend_file
, instruującą preprocesor PHP do wykonania pliku, który przesłaliśmy w kroku 1Ustaw zmienną
PHPRC
na plik, który przesłaliśmy w kroku 2.
Uzyskaj więcej informacji na temat wykonania tego łańcucha z oryginalnego raportu.
PHPRC - inna opcja
Jeśli nie możesz przesyłać plików, możesz użyć w FreeBSD "pliku"
/dev/fd/0
, który zawierastdin
, będąc treścią żądania wysłanego dostdin
:curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary 'auto_prepend_file="/etc/passwd"'
Lub aby uzyskać RCE, włącz
allow_url_include
i dodaj plik z kodem PHP w base64: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=="'
Technika z tego raportu.
XAMPP CGI RCE - CVE-2024-4577
Serwer WWW analizuje żądania HTTP i przekazuje je do skryptu PHP wykonującego żądanie takie jak http://host/cgi.php?foo=bar
jako php.exe cgi.php foo=bar
, co pozwala na wstrzyknięcie parametrów. To pozwoli na wstrzyknięcie następujących parametrów, aby załadować kod PHP z treści:
Ponadto możliwe jest wstrzyknięcie parametru "-" za pomocą znaku 0xAD z powodu późniejszej normalizacji PHP. Sprawdź przykład exploita z tego posta:
PHP Sanitization bypass & Brain Fuck
W tym poście można znaleźć świetne pomysły na generowanie kodu PHP w stylu brain fuck z bardzo ograniczoną liczbą dozwolonych znaków. Ponadto zaproponowano również interesujący sposób na wykonywanie funkcji, które pozwoliły im na ominięcie kilku kontroli:
PHP Static analysis
Sprawdź, czy możesz wstawić kod w wywołania tych funkcji (z tutaj):
Jeśli debugujesz aplikację PHP, możesz globalnie włączyć drukowanie błędów w /etc/php5/apache2/php.ini
, dodając display_errors = On
i zrestartować apache: sudo systemctl restart apache2
Deobfuskacja kodu PHP
Możesz użyć web www.unphp.net do deobfuskacji kodu php.
Wrappery PHP i protokoły
Wrappery PHP i protokoły mogą pozwolić ci na obejście ochrony zapisu i odczytu w systemie i jego kompromitację. Aby uzyskać więcej informacji, sprawdź tę stronę.
Xdebug nieautoryzowane RCE
Jeśli widzisz, że Xdebug jest włączony w wyjściu phpconfig()
, powinieneś spróbować uzyskać RCE za pomocą https://github.com/nqxcode/xdebug-exploit
Zmienne zmiennych
RCE nadużywając nowego $_GET["a"]($_GET["b")
Jeśli na stronie możesz utworzyć nowy obiekt dowolnej klasy, możesz uzyskać RCE, sprawdź następującą stronę, aby się dowiedzieć:
PHP - RCE abusing object creation: new $_GET["a"]($_GET["b"])Wykonaj PHP bez liter
https://securityonline.info/bypass-waf-php-webshell-without-numbers-letters/
Używając ósemkowego
XOR
XOR łatwy kod powłoki
Zgodnie z tym opisem możliwe jest wygenerowanie łatwego kodu powłoki w ten sposób:
Więc, jeśli możesz wykonać dowolny PHP bez cyfr i liter możesz wysłać żądanie takie jak poniższe, wykorzystując ten ładunek do wykonania dowolnego PHP:
Dla bardziej szczegółowego wyjaśnienia sprawdź https://ctf-wiki.org/web/php/php/#preg_match
XOR Shellcode (wewnątrz eval)
Perl like
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Last updated