Uwięziony Apacz + PHP + mod_ssl
wersja 0.4
 

Spis treści

Po kiego ... ?

1. Od czegoś trzeba zacząć
2. Nowy system plików
3. Biblioteki - prawdziwe wyzwanie
4. Pierdoły

Posłowie


Po kiego ... ?

Już w przedszkolu uczą, że najlepszym (a przy okazji najbardziej
popularnym) serwerem www na świecie jest Apache. Oczywiście ostatnią
wersję (1.3.x) wspomnianego softu masz już na dysku.

Aby zwiększyć bezpieczeństwo naszego serwera www, możemy umieścić go
w pierdlu. Tak jest, jeśli nawet ktoś się do nas włamie - wyląduje
tam gdzie jego miejsce. W praktyce polga to na tym, że Apacz zostaje
uruchomiony w "zamkniętym" systemie plików. Są tam tylko niezbędne do
jego działania pliki, nic więcej. Brak katalogów domowych użytkowników,
SUIDów, plików z hasłami itd. Mechanizm chroot (znany także jako
jail) uważany jest za rozwiązanie podnoszące w znaczący sposób
bezpieczeństwo systemu. Zapowiada się ciekawie...

No i może na koniec wspomnę tylko, że niniejszy dokument nie opisuje
szczegółów pliku konfiguracyjnego Apacza - tych w Sieci nie brakuje.


1. Od czegoś trzeba zacząć

A więc zaczynam. Na początek informacje praktyczno - techniczne.
Opisuję tutaj instalację z kodu źródłowego. Różnego rodzaju
instalatory - ułatwiacze rozmieszczają pliki Apacza po całym
dysku i nikt nie wie gdzie czego szukać. Nie wiadomo nawet co się jak
nazywa ;). Po drugie: konfiguracja i działanie zostały przetestowane
pod Slackiem 9.0. Po trzecie: instaluję wersję 1.3.27. Po czwarte i
chyba najważniejsze: nie cuduj. Jeśli nie jesteś w temacie chroota,
rób krok po kroku to, co opisuję. Gdy już szczaisz o co chodzi, będziesz
mógł to robić po swojemu (ścieżki, prawa itp.).

Na początek musisz wybrać sobie użytkownika, z prawami którego będzie
chodził nasz serwerek. Domyślnie jest to nobody. Wykorzystuje
go pewnie jeszcze parę usług, więc powinieneś stworzyć sobie nowego,
dedykowanego usera. I stworzyć nową grupę. Mój wybór padł na użytkownika
www, którego podstawową grupą będzie www. Ciekawe dlaczego...
Dobra jest, teraz musimy utworzyć go z minimalną liczbą przywilejów.
Zaczniemy od grupy:

groupadd www
useradd -c "serwer www" -d /dev/null -g www -s /bin/false www


Tak więc utworzyliśmy najpierw grupę www. Będzie należał do niej
tylko użytkownik www. W drugiej linii dodaliśmy tego użytkownika.
Jego katalogiem domowym jest /dev/null, należy on do grupy www,
jego shellem jest /bin/false a opisem "serwer www". Nasz nowy użytkownik
to prawdziwy looser, nie ma nic. Gdyby wszyscy tacy byli...

----------------------------- dla Apache + PHP ---------------------------
W przypadku instalacji Apacza z PHP należy na początku postępować
standardowo:

cd apache-1.3.27
./configure
cd ../php-4.3.2
./configure --with-apache=../apache-1.3.27 --without-mysql
make
make install
--------------------------------------------------------------------------
-------------------------- dla Apache + mod_ssl --------------------------
Sednem sprawy jest wygenerowanie sobie certyfikatu, klucza itp.
Szczegółowy opis umieściłem w dokumencie na mojej stronie.
W dalszym ciągu niniejszej pracy zakładam, że postąpiłeś zgodnie ze
wskazówkami tam zawartymi (do tej pory punkt 1: OpenSSL).
Po wejściu do katalogu mod_ssl-2.8.14-1.3.27 robisz tyle:
./configure --with-apache=../apache_1.3.27 --with-crt=/etc/ssl/server.crt
      --with-key=/etc/ssl/server.key

--------------------------------------------------------------------------

Czas skonfigurować Apacza.
Oto opcje, które proponuję na początek:

./configure --prefix=/usr/apache --server-gid=www --server-uid=www

--------------------------- dla Apache + PHP ---------------------------
Jeśli chcemy dorzucić obsługę PHP (jako moduł statyczny), należy do
powyższych opcji dorzucić:
--activate-module=src/modules/php4/libphp4.a
---------------------------------------------------------------------------
------------------------- dla Apache + mod_ssl --------------------------
Aby dołączyć nasz moduł, do wyżej wymienionych opcji musimy dopisać:
--enable-module=ssl
Przed wydaniem polecenia ./configure ... powinniśmy także ustawić
zmienną SSL_BASE tak, aby wskazywała katalog ze źródłem openssl'a
Całe polecenie konfiguracyjne Apacza może więc wyglądać tak:
SSL_BASE=../openssl-0.9.7b ./configure [tutaj wyżej opisane opcje]
---------------------------------------------------------------------------

Teraz standardowo:
make
make install

Tymczasowo proponuję umieścić Apacza właśnie w /usr/apache. Gdy
wszystko przeniesie się do wydzielonego systemu plików, będzie o wiele
prościej. W każdym razie chodzi o jak najkrótszą ścieżkę i minimalną
liczbę porozrzucanych katalogów (logi, pliki konfiguracyjne, plik .pid itp).
W tym przypadku wszystko to zamyka się w /usr/apache.

------------------------------ dla Apache + PHP --------------------------
Instalacja PHP przebiega cały czas normalnie:

cd php-4.3.2
cp php.ini-dist /usr/local/lib/php.ini

Pozostało jeszcze wyedytować plik httpd.conf i dorzucić do niego
wpis: AddType application/x-httpd-php .php
--------------------------------------------------------------------------

Teraz nadszedł czas, abyś spróbował uruchomić Apacza i zobaczyć czy
"normalnie" zainstalowany działa
jak należy. W konfigu
(/usr/apache/conf/httpd.conf) powinieneś zmienić opcję "Port" na "80"
i sprawdzić czy "User" i "Group" wskazują na www.

------------------------------ dla Apache + PHP --------------------------
Powinieneś sprawdzić działanie i Apacza i PHP, wykorzystując
np. funkcję phpinfo()
--------------------------------------------------------------------------
-------------------------- dla Apache + mod_ssl --------------------------
Sprawdź, czy połączenie przez SSL działa prawidłowo.
W razie potrzeby sięgnij do dokumentu na mojej stronie.
--------------------------------------------------------------------------
Jeśli działa - jest dobrze. Wyłącz Apacza, zaczynamy zabawę.


2. Nowy system plików

Należy teraz wybrać katalog, który stanie się / (rootem)
dla naszego serwerka www. Apacz nie będzie widział nic, co jest
wcześniej. Linuxową tradycją, przekazywaną z ojca na syna, stał się
katalog /chroot jako podstawa dla wszyskich więzionych programów.
Tak więc robimy, co następuje:

mkdir /chroot
mkdir /chroot/apache

Jak już pewnie się domyśliłeś, rootem dla naszego Indiańca
będzie /chroot/apache.

Teraz wyobraź sobie, że jesteś programem, który działa z prawami
jakiegoś użytkownika. Na początek przydałby się tobie shell (a
jest nim /bin/false).

mkdir /chroot/apache/bin
cp /bin/false /chroot/apache/bin


Jak wspomniałem wcześniej, /chroot/apache staje się /.
Tak się składa, że jest w nim bin, który zawiera shella.

Inną ważną sprawą jest katalog domowy (tutaj: /dev/null).
Najpier sprawdź jakie ma prawa i do kogo należy wyżej wymieniony
(ls -l /dev/null). Prawa i właściciela należy odwzorować w
nowym roocie. /dev/null jest urządzeniem znakowym, którego
nie można tak po prostu skopiować. Należy je utworzyć:

mkdir /chroot/apache/dev
cd /chroot/apache/dev
mknod null c 1 3
chmod 666 null
chown root:sys null

Teraz ls -l /chroot/apache/dev/null powinien wyglądać jak
ls -l /dev/null (nie licząc daty utworzenia :).

Na razie jest dobrze, w więzieniu mamy /dev oraz /bin.
Jeszcze var/run na różne dziwne rzeczy :)

mkdir /chroot/apache/var
mkdir /chroot/apache/var/run

Gdybym chciał przycynić, powyższe dwie linijki zastąpiłbym jedną:
mkdir -p /chroot/apache/var/run
Jedziemy dalej - czas przerzucić Apacza:

mkdir /chroot/apache/usr
cp -r /usr/apache /chroot/apache/usr

Dobra, mamy kolejny element układanki. Teraz czas na /etc/ i kilka
plików, które tam siedzą:

mkdir /chroot/apache/etc
cd /chroot/apache/etc
cp /etc/hosts .
cp /etc/resolv.conf .
cp /etc/nsswitch.conf .
cp /etc/host.conf .
cp /etc/localtime .
cp /etc/group .
cp /etc/passwd .

Spokojnie! Teraz wrzuć do jakiegoś edytora plik group i usuń z niego
wszystkie linijki, za wyjątkiej tej z definicją grupy www. Zapisz
zmiany. Plik /chroot/apache/etc/group jest teraz plikiem mającym
jedną linijkę. To samo zrób z passwd - pozostaw tylko linię z
definicją użytkownika www. Pozostałych wyrzuć. Zapisz zmiany,
plik /chroot/apache/etc/passwd ma także jedną linijkę.

---------------------------- dla Apache + PHP ----------------------------
Nasz Apacz potrzebuje pliku php.ini. Nie pozostało nam nic innego
jak wykonać poniższe:

mkdir /chroot/apache/usr/local
mkdir /chroot/apache/usr/local/lib
cp /usr/local/lib/php.ini /chroot/apache/usr/local/lib

Dla bardziej złożonych aplikacji, będziesz prawdopodobnie potrzebował
jeszcze tego:

mkdir /chroot/apache/tmp
chmod 1777 /chroot/apache/tmp

--------------------------------------------------------------------------
------------------------- dla Apache + mod_ssl -------------------------
Zaczynamy od urządzenia /dev/urandom.
Jeśli go nie masz, wykorzystaj /dev/random postępując analogicznie:
Sprawdź jego prawa - musisz je odwzorować w chroocie.
cd /chroot/apache/dev
mknod urandom c 1 9
Prawa dostępu i właściciela powinny pokrywać się z prawami /dev/urandom.
Jeśli masz tylko /dev/random, utwór z go zamiast urandom.

Jak zauważa Paweł P. (thx): dla RedHata 7.2 "trzeba było dodatkowo stworzyć
mknod /dev/tty c 5 0 - bez tego wyskakiwał komunikat o braku klucza prywatnego".

Jeszcze pozostał katalog tmp, który w przypadku PHP nie był wymagany.
Jeśli go nie masz - już czas go utworzyć:
mkdir /chroot/apache/tmp
chmod 1777 /chroot/apache/tmp

--------------------------------------------------------------------------
Teraz zauważ, że wszystkie pliki, które znajduą się w /chroot/apache,
są "nieszkodliwe". Nie ma ich wiele i nie zdradzają żadnych istotnych
informacji o systemie, jego konfiguracji, użytkownikach itp.


3. Biblioteki - prawdziwe wyzwanie

Tutaj zaczyna się sedno sprawy - część najtrudniejsza. Apacz bowiem
potrzebuje do prawidłowego działania pewnych bibliotek. Jakich ?
Zależy od systemu, jego wersji, kompilatora itp. Poniższy opis
pasuje do Slacka 9. Postaram się wyjaśnić, jak rozpoznać co gdzie
wrzucić, dlatego poniższe polecenia należy odpowiednio zmodyfikować.

Demonem odpowiadającym za działanie naszego programu jest httpd.
Znajduje się on w katalogu /chroot/apache/usr/apache/bin/. Aby
dowiedzieć się, które biblioteki są wymagane do jego działania, należy
posłużyć się poleceniem ldd. Jego argumentem jest binarka.

ldd /chroot/apache/usr/apache/bin/httpd

Dla Slacka 9 wynik działania polecenia przedstawia się następująco:

libm.so.6 => /lib/libm.so.6 (...)
libcrypt.so.1 => /lib/libcrypt.so.1 (...)
libexpat.so.0 => /usr/lib/libexpat.so.0 (...)
libc.so.6 => /lib/libc.so.6 (...)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2(...)

---------------------------- dla Apache + PHP ----------------------------
W tym przypadku powinno pojawić się trochę więcej bibliotek. U mnie były
to dodatkowo:
libresolv.so.2 => /lib/libresolv.so.2 (...)
libdl.so.2 => /lib/libdl.so.2 (...)
libnsl.so.1 => /lib/libnsl.so.1 (...)
--------------------------------------------------------------------------
U Ciebie powyższe może wyglądać trochę inaczej, dlatego teraz uważaj...
Bierzemy pod uwagę prawą stronę. Pliki tam wymienione należy skopiować
do odpowiednich katalogów w /chroot/apache.

Oto odpowiednie polecenia (u siebie zmień je analogicznie) dla wyżej
otrzymanego wyniku.

mkdir /chroot/apache/lib
cd /chroot/apache/lib

cp /lib/libm.so.6 .
cp /lib/libcrypt.so.1 .
cp /lib/libc.so.6 .
cp /lib/ld-linux.so.2 .

mkdir /chroot/apache/usr/lib
cd /chroot/apache/usr/lib
cp /usr/lib/libexpat.so.0 .


----------------------------- dla Apache + PHP ------------------------
Jak łatwo się domyślić, należy dodatkowo zrobić to:
cd /chroot/apache/lib
cp /lib/libresolv.so.2 .
cp /lib/libdl.so.2 .
cp /lib/libnsl.so.1 .

---------------------------------------------------------------------------
--------------------------- dla Apache + mod_ssl ------------------------
mod_ssl nie wymaga dodatkowych bibliotek. Przynajmniej u mnie :)
(to z cyklu "niewiarygodne ale prawdziwe").
---------------------------------------------------------------------------

Powinieneś już wiedzieć o co chodzi. Chciałbym w tym momencie napisać,
że to już wszystko... Już pewnie się domyśliłeś że tak nie jest.
Lecimy dalej. Aby uruchomić jakiś program w chroocie używa się
następującej składni: chroot nowy_root_programu względna_ścieżka_programu.
W naszym przypadku wygląda to tak:

chroot /chroot/apache /usr/apache/bin/httpd

Objaśnienie: chroot to program, który zamknie w /chroot/apache
program /usr/apache/bin/httpd. Ścieżka do samego programu (ostatni
parametr) jest podana względem /chroot/apache. Czyli chroot
zamyka nas w /chroot/apache (od tej porty jest on / rootem)
i uruchamia /usr/apache/bin/httpd. Program, który zostaje uruchomiony
to /chroot/apache/usr/apache/bin/httpd. Mam nadzieję, że rozumiesz :)

Uwaga: uruchom apacza demonem httpd, a nie apachectl czy jakimś
skryptem w stylu rc.X. Żadnych skryptów, robimy ręcznie to co one.
Powinieneś otrzymać błąd :). W Slacku 9 jest to: "httpd: bad user name www".
Niezłe, co ? Czegoś jeszcze brakuje. I tu dochodzimy do sedna.

Ta część pracy nazywa się "w poszukiwaniu zaginionych bibliotek".
Wykorzystamy tutaj fajny programik o nazwie strace. Pozwala
on śledzić działanie programu - a co za tym idzie jego odwołania do
(pozostałych) bibliotek, plików itp.

strace uruchamia się z poleceniem, którego działanie należy śledzić.
No to lecimy:

strace chroot /chroot/apache /usr/apache/bin/httpd

Okej, przez ekran przewinęło nam się multum informacji. Wystarczy
teraz uważnie czytać (często cofając ekran "do tyłu :)" ) i szukać nazw plików,
do których httpd się odwołuje. W powyższym przypadku wyczaiłem
gdzieś linię:

open("/lib/libnss_compact.so.2", O_RDONLY) = -1 ENOENT (No such file ...)

Mam cię ! Następuje tutaj odwołanie do biblioteki, której nie
skopiowałem do mojego chroota (/chroot/apache). Wykonuję
więc następujący krok:

cp /lib/libnss_compact.so.2 /chroot/apache/lib/

Próbujemy znowu uruchomić Apacza:
chroot /chroot/apache /usr/apache/bin/httpd
Albo otrzymamy znowu błąd (często ten sam), albo Apacz się uruchomi.
Powinniśmy wałkować to wszystko tak długo, dopóki Apacz nie uruchomi się
bez żadnego pierdnięcia. Jeśli widzimy jakikolwiek błąd, uruchamiamy znowu
strace szukając odwołania do czegoś, czego nie skopiowaliśmy do
naszego chroota. Nie musi to być biblioteka, może to być jakiś
plik w /etc/. Jeszcze jedno: po kilku takich próbach Apacz może
wystartować, nawet jeśli zrobi to z błędem. Nie chcemy błędów. Dlatego
po próbie uruchomienia Apacza w chroocie, przed kolejnym uruchomieniem
strace dobrze jest wydać polecenie killall httpd.

To koniec części "w poszukiwaniu zaginionych bibliotek". Poniżej przedstawiam
listę plików (dokładnie: poleceń) które musiałem wykonać aby Apacz w końcu
bezbłędnie wystartował w chroocie na Slacku 9.

cp /lib/libnss_compact.so.2 /chroot/apache/lib
cp /lib/libnsl.so.1 /chroot/apache/lib
cp /lib/libnss_dns.so.2 /chroot/apache/lib
cp /lib/libnss_files.so.2 /chroot/apache/lib

------------------------------ dla Apache + PHP ---------------------------
Plik libnsl.so.1 przerzuciliśmy już wcześniej.
---------------------------------------------------------------------------

Dobra, po wydaniu polecenia:

chroot /chroot/apache /usr/apache/bin/httpd

bez żadnych błędów serwerek wystartował. Można to sprawdzić przy
pomocy polecenia ps waux |grep httpd. Okej - jest. Widzimy.
Ale skąd mamy mieć pewność, że to ten Apacz chodzi co trzeba, skoro
ścieżka do niego jest inna ? Najlepiej się o tym przekonać usuwając
oryginalnie zainstalowanego przez make install Apacza:

rm -rf /usr/apache

Teraz zatrzymujemy naszego (killall httpd) i jeszcze raz go
uruchamiamy w chroocie. Chodzi ? To dobrze. Ciągle nie jesteś
pewien ? Wykonaj polecenie ps x|grep httpd i zapamiętaj PID procesu
httpd. Teraz wykonaj polecenie ls /proc/PID/root (PID to
liczba) - powinieneś ujrzeć zawartość katalogu /chroot/apache/.

Wygląda na to, że działa :).

----------------------------- dla Apache + PHP -------------------------
Wygląda na to, że działa :)).
--------------------------------------------------------------------------
---------------------------- dla Apache + mod_ssl ---------------------
Dla mod_ssl dopisujemy parametr -DSSL :
chroot /chroot/apache /usr/apache/bin/httpd -DSSL

Wygląda na to, że działa :)))
-------------------------------------------------------------------------

I jeszcze ważna uwaga dotycząca funkcji system PHP.
Zacytuje tutaj mejla którego otrzymałem od Marcina R. (THX!):

Po pierwsze znalazłem w sieci informacje, że funkcja "system"
wymaga pliku /bin/sh (więc wrzuciłem go do /chroot/apache/bin/sh).
Jednak to nie rozwiązało problemu.
Polecenie dalej nie działało, mimo, że:
"chroot /chroot/apache/ /usr/apache/bin/ls -l" wykonywane było poprawnie.
Zrobiłem tak: uruchomiłem sh w chroocie i z tamtego (uwięzionego shella)
wywołałem polecenie ls. Co się okazało? Brakuje mu bibliotek
(mimo, że sprawdzałem wcześniej "ldd /chroot/apache/bin/ls" i nic nie wspominał o nich).
Przekopiowałem brakujące pliki i jest ok.



4. Pierdoły

Po pierwsze: start i stop
Start Apacza: chroot /chroot/apache /usr/apache/bin/httpd
Stop Apacza: killall httpd

Po drugie: konfigi
Jestem przyzwyczajony do trzymania wszystkich plików konfiguracyjnych
w katalogu /etc/. Dlatego też wykonuje polecenie:
ln -s /chroot/apache/usr/apache/conf /etc/apache

Po trzecie: logi
Jestem przyzwyczajony do trzymania logów w /var/log/. Dlatego
też wykonuje następujące polecenie:
ln -s /chroot/apache/usr/apache/logs /var/log/apache

Po czwarte: zacznij mieszać po swojemu. Pamiętaj, że ścieżki bezwzględne
w pliku konfiguracyjnym Apacza rozpoczynają się tak naprawdę w
/chroot/apache. Jeśli modyfikujesz coś w httpd.conf, musisz
odpowiednio to uwzględnić.

Po piąte: skrypty dostarczone razem z Apaczem (np. apachectl)
raczej nie będą działały. Odnoszą się one do takich poleceń jak
echo, kill itp., które znajdują się np. w katalogu /bin/.
U nas ich nie ma. Masz dwa wyjścia - albo zrezygnować z ww. skryptów, albo
przerzucać odpowiednie binarki i/lub modyfikować skrypty. Wybór należy do
Ciebie.

Po szóste: jeśli coś zamieszałeś i przestało działać, pamiętaj o poleceniu
strace. Jest kwestią czasu, kiedy zaczniesz myśleć jak
chroot. Nie pytaj mnie o pliki startowe, "zrób to sam".


Posłowie

Jest to pierwsza wersja tego dokumentu i zawiera pewnie
jakieś błędy/niedoróbki/potknięcia itp. Będę bardzo wdzięczny
za wszelkie uwagi, komentarze, poprawki, wyrazy wdzięczności.
Z góry przepraszam za powyższe i mam nadzieję, że będziecie mnie
informować w których miejscach coś nie gra.
Jako (częściowe) wytłumaczenie przedstawiam fakt, że większość tej
pracy powstawała w późnych godzinach nocnych.

Ostatnia wersja tego dokumentu znajduje się pod niżej wymienionym adresem.
Kontakt ze mną: linio@terramail.pl
Wesprzyj finansowo autora - kliknij tutaj


 
===============================
Henryk Liniowski, Poznań 2003
http://linio.terramail.pl
===============================