LFI2RCE via Eternal waiting

Support HackTricks

Podstawowe informacje

Domyślnie, gdy plik jest przesyłany do PHP (nawet jeśli nie jest tego oczekiwany), generowany jest plik tymczasowy w /tmp o nazwie takiej jak php[a-zA-Z0-9]{6}, chociaż widziałem niektóre obrazy dockera, w których generowane pliki nie zawierają cyfr.

W przypadku lokalnego włączenia pliku, jeśli uda ci się dołączyć ten przesłany plik, uzyskasz RCE.

Zauważ, że domyślnie PHP pozwala na przesłanie tylko 20 plików w jednym żądaniu (ustawione w /etc/php/<version>/apache2/php.ini):

; Maximum number of files that can be uploaded via a single request
max_file_uploads = 20

Also, the liczba potencjalnych nazw plików wynosi 62*62*62*62*62*62 = 56800235584

Inne techniki

Inne techniki polegają na atakowaniu protokołów PHP (nie będziesz w stanie, jeśli kontrolujesz tylko ostatnią część ścieżki), ujawnianiu ścieżki pliku, nadużywaniu oczekiwanych plików lub sprawieniu, by PHP doznało błędu segmentacji, aby przesłane pliki tymczasowe nie zostały usunięte. Ta technika jest bardzo podobna do ostatniej, ale nie wymaga znalezienia zero day.

Technika wiecznego czekania

W tej technice musimy tylko kontrolować względną ścieżkę. Jeśli uda nam się przesłać pliki i sprawić, by LFI nigdy się nie kończył, będziemy mieli "wystarczająco dużo czasu", aby brute-forcować przesłane pliki i znaleźć dowolny z przesłanych.

Zalety tej techniki:

  • Musisz tylko kontrolować względną ścieżkę wewnątrz include

  • Nie wymaga nginx ani nieoczekiwanego poziomu dostępu do plików dziennika

  • Nie wymaga 0 day, aby spowodować błąd segmentacji

  • Nie wymaga ujawnienia ścieżki

Główne problemy tej techniki to:

  • Potrzebujesz, aby konkretne pliki były obecne (może być ich więcej)

  • szalona liczba potencjalnych nazw plików: 56800235584

  • Jeśli serwer nie używa cyfr, całkowita potencjalna liczba wynosi: 19770609664

  • Domyślnie tylko 20 plików może być przesłanych w jednym żądaniu.

  • maksymalna liczba równoległych pracowników używanego serwera.

  • Ten limit w połączeniu z poprzednimi może sprawić, że atak będzie trwał zbyt długo

  • Limit czasu dla żądania PHP. Idealnie powinien być wieczny lub powinien zabić proces PHP bez usuwania przesłanych plików tymczasowych, w przeciwnym razie będzie to również problem

Więc, jak możesz sprawić, by include PHP nigdy się nie kończył? Po prostu przez dołączenie pliku /sys/kernel/security/apparmor/revision (niestety niedostępny w kontenerach Docker...).

Spróbuj to, po prostu wywołując:

php -a # open php cli
include("/sys/kernel/security/apparmor/revision");

Apache2

Domyślnie, Apache obsługuje 150 równoległych połączeń, zgodnie z https://ubiq.co/tech-blog/increase-max-connections-apache/ można zwiększyć tę liczbę do 8000. Postępuj zgodnie z tym, aby używać PHP z tym modułem: https://www.digitalocean.com/community/tutorials/how-to-configure-apache-http-with-mpm-event-and-php-fpm-on-ubuntu-18-04.

Domyślnie, (jak widzę w moich testach), proces PHP może trwać wiecznie.

Zróbmy kilka obliczeń:

  • Możemy użyć 149 połączeń do wygenerowania 149 * 20 = 2980 plików tymczasowych z naszym webshell.

  • Następnie, użyj ostatniego połączenia do brute-force potencjalnych plików.

  • Przy prędkości 10 żądań/s czasy wynoszą:

  • 56800235584 / 2980 / 10 / 3600 ~= 530 godzin (50% szans w 265h)

  • (bez cyfr) 19770609664 / 2980 / 10 / 3600 ~= 185h (50% szans w 93h)

Zauważ, że w poprzednim przykładzie całkowicie DoSujemy innych klientów!

Jeśli serwer Apache jest ulepszony i moglibyśmy nadużywać 4000 połączeń (w połowie drogi do maksymalnej liczby). Moglibyśmy stworzyć 3999*20 = 79980 plików a liczba zostałaby zmniejszona do około 19.7h lub 6.9h (10h, 3.5h 50% szans).

PHP-FMP

Jeśli zamiast używać regularnego modułu php dla apache do uruchamiania skryptów PHP, strona internetowa używa PHP-FMP (to poprawia wydajność strony internetowej, więc jest powszechnie spotykane), można zrobić coś jeszcze, aby poprawić tę technikę.

PHP-FMP pozwala na konfigurację parametru request_terminate_timeout w /etc/php/<php-version>/fpm/pool.d/www.conf. Ten parametr wskazuje maksymalną liczbę sekund kiedy żądanie do PHP musi zakończyć się (domyślnie nieskończoność, ale 30s, jeśli parametr jest odkomentowany). Gdy żądanie jest przetwarzane przez PHP przez wskazaną liczbę sekund, jest zabijane. Oznacza to, że jeśli żądanie przesyłało pliki tymczasowe, ponieważ przetwarzanie php zostało zatrzymane, te pliki nie zostaną usunięte. Dlatego, jeśli możesz sprawić, aby żądanie trwało ten czas, możesz generować tysiące plików tymczasowych, które nie zostaną usunięte, co przyspieszy proces ich znajdowania i zmniejsza prawdopodobieństwo DoS dla platformy poprzez wykorzystanie wszystkich połączeń.

Aby unikać DoS, załóżmy, że atakujący będzie używał tylko 100 połączeń w tym samym czasie, a maksymalny czas przetwarzania php przez php-fmp (request_terminate_timeout) wynosi 30s. Dlatego liczba plików tymczasowych, które mogą być generowane na sekundę wynosi 100*20/30 = 66.67.

Aby wygenerować 10000 plików, atakujący potrzebowałby: 10000/66.67 = 150s (aby wygenerować 100000 plików czas wyniósłby 25min).

Następnie atakujący mógłby użyć tych 100 połączeń do przeprowadzenia brute-force. **** Zakładając prędkość 300 req/s, czas potrzebny do wykorzystania tego jest następujący:

  • 56800235584 / 10000 / 300 / 3600 ~= 5.25 godzin (50% szans w 2.63h)

  • (z 100000 plikami) 56800235584 / 100000 / 300 / 3600 ~= 0.525 godzin (50% szans w 0.263h)

Tak, możliwe jest wygenerowanie 100000 plików tymczasowych na instancji średniej wielkości EC2:

Zauważ, że aby wywołać limit czasu, wystarczy włączyć podatną stronę LFI, aby weszła w wieczną pętlę dołączania.

Nginx

Wygląda na to, że domyślnie Nginx obsługuje 512 równoległych połączeń w tym samym czasie (a ta liczba może być poprawiona).

Wsparcie HackTricks

Last updated