Bezpieczna instalacja pakietów rpm

Red Hat 6.x / CentOS 6.x
Jako administrator warstwy OS często spotykam się z koniecznością instalacji pakietów rpm dostarczonych przez zewnętrznych dostawców, lub osoby zajmujące się warstwą aplikacyjną serwera.
Instalacje takie niosą za sobą ryzyko uszkodzenia lub przejęcia kontroli nad systemem operacyjnym przez osoby nieuprawnione.
Oczywiście anaiza kodu samej aplikacji wykracza poza zakres normalnej administracji os-em i za jakość takiego kodu powinien odpowiadać jej dostawca, ale należy być świadomym, że struktura pakietów rpm umożliwia ingerencję w system również poza samym kodem.

Każdy pakiet rpm podczas instalacji ma możliwość wykonania na serwerze skryptów lub wyzwolenia triggerów z uprawnieniami użytkownika, z którego konta jest wywołany. Biorąc pod uwagę fakt, że część pakietów instalujemy z uprawnieniami root, zestawienie takie przy odrobinie nieuwagi może spowodować katastrofę.

Pobierając pakiety z nieznanego źródła w internecie weryfikację "bezpieczeństwa" aplikacji powinniśmy zacząć od weryfikacji sygnatur gpg, które opisane są tutaj.

Kolejnym elementem, który należy sprawdzić, a który tyczy się właściwie każdej paczki spoza zaufanego repozytorium, są wspomniane wcześniej skrypty i triggery wykonywane przez instalator.

Skrypty pakietu rpm

Każdy z instalowanych pakietów może zawierać cztery rodzaje skryptów, wykonywanych zależnie od operacji, które na pakiecie przeprowadzamy. Są to skrypty preinstall wykonywane przed instalacją pakietu, postinstall wykonywane po instalacji, oraz analogicznie preuninstall oraz postunistall, czyli skrypty wykonywane przed i po deinstalacji. Każdy ze skryptów może być równie groźny, jeśli wykonywany jest z uprawnieniami super usera. Wyobraźmy sobie, że jedna z linijek to "rm -rf /" ... więcej chyba nie trzeba tłumaczyć.

Istnieje oczywiście możliwość weryfikacji pakietu pod kątem takich skryptów, czyli możliwość zabezpieczenia się przed niechcianymi skutkami instalacji. Dla pzykłady posłużymy się dostępnym na płycie instalacyjnej systemu pakietem certmonger.

[root@server1 Packages]# rpm --scripts -qp certmonger-0.75.13-1.el6.x86_64.rpm
postinstall scriptlet (using /bin/sh):
if test $1 -eq 1 ; then
        killall -HUP dbus-daemon 2>&1 > /dev/null
fi
/sbin/chkconfig --add certmonger
preuninstall scriptlet (using /bin/sh):
if test $1 -eq 0 ; then
        /sbin/service certmonger stop 2>&1 > /dev/null
        /sbin/chkconfig --del certmonger
fi
exit 0
postuninstall scriptlet (using /bin/sh):
if test $1 -gt 0 ; then
        /sbin/service certmonger condrestart 2>&1 > /dev/null
fi
exit 0

Jak widać pakiet posiada skrypty w trzech sekcjach, więc kawałki kodu będą wykonywane po jego instalacji, przed deinstalacją oraz po niej. Skrypty takie przeważnie są krótkie, a ich analiza nie sprawia problemów nawet początkującym administratorom. Widzimy, że po instalacji zostanie "ubity" dbus-deamon, oraz dodany serwis certmonger. Przed deinstalacją skrypt zatrzyma serwis certmonger i usunie go z systemu, a po niej sprawdzi, czy serwis omyłkowo nie pozostał w systemie.

Dla ciekawskich systemu istnieje również możliwość weryfikacji skryptów wykonywanych przez pakiety zainstalowane już w systemie. Z polecenia usunąć należy przełącznik -p, który wskazuje na plik rpm. Przykładowe polecenie będzie zatem wyglądać następująco:

[root@server1 Packages]# rpm --scripts -q pam-1.1.1-20.el6.x86_64
postinstall scriptlet (using /bin/sh):
/sbin/ldconfig
if [ ! -e /var/log/tallylog ] ; then
        install -m 600 /dev/null /var/log/tallylog
fi
postuninstall program: /sbin/ldconfig

Oczywiście dla już zainstalowanych pakietów istotna jest weryfikacja co zrobią skrypty przy deinstalacji pakietu, ale niejednokrotnie przy analizie błędów przydatna jest również informacja jakie zmiany wprowadziły.

Triggery pakietu

Analogicznie do skryptów, możemy weryfikować wykonywane triggery. Sekcje triggerów są analogiczne do skryptów, i nazywają się odpowiednio triggerin, truggerpostin, triggerun oraz triggerpostun.

[root@server1 Packages]# rpm --triggers -qp certmonger-0.75.13-1.el6.x86_64.rpm
triggerin scriptlet (using /bin/sh) -- certmonger < 0.58
if test $1 -gt 1 ; then
        # If the daemon is running, remove knowledge of the dogtag renewer.
        objpath=`dbus-send --system --reply-timeout=10000 --dest=org.fedorahosted.certmonger --print-reply=o /org/fedorahosted/certmonger org.fedorahosted.certmonger.find_ca_by_nickname string:dogtag-ipa-renew-agent 2> /dev/null | sed -r 's,^ +,,g' || true`
        if test -n "$objpath" ; then
                dbus-send --system --dest=org.fedorahosted.certmonger --print-reply /org/fedorahosted/certmonger org.fedorahosted.certmonger.remove_known_ca objpath:"$objpath" >/dev/null 2> /dev/null
        fi
        # Remove the data file, in case it isn't running.
        for cafile in /var/lib/certmonger/cas/* ; do
                if grep -q '^id=dogtag-ipa-renew-agent$' "$cafile" ; then
                        rm -f "$cafile"
                fi
        done
fi
exit 0

Zabezpieczenia

Najpewniejszym sposobem zabezpieczenia się przed problemami związanymi z instalacją, jest analiza obu sekcji pakietu, a w przypadku kiedy budzi on nasze wątpliwości, odmowa jego instalacji. Aczkolwiek rpm daje nam możliwość zainstalowania pakietu bez wykonania skryptów czy triggerów, np:

[root@server1 Packages]# rpm --noscripts --notriggers -i certmonger-0.75.13-1.el6.x86_64.rpm


W większości przypadków aplikacja taka nie będzie działać poprawnie bez dodatkowych działań z naszej strony - przecież w skryptach tworzy serwisy, użytkowników, grupy, modyfikuje konfigurację. Jednak analizując skrypt możemy ręcznie zrealizować kroki, które nie budzą naszych wątpliwości.

Inne przydatne komendy

Do weryfikacji pakietów możemy użyć jeszcze kilku komend, które w niektórych przypadkach mogą okazać się przydatne. Przede wszystkim możemy zweryfikować dostawcę pakietu poprzez wyświetlenie informacji o nim:

[root@server1 Packages]# rpm -qpi vim-common-7.2.411-1.8.el6.x86_64.rpm
Name        : vim-common                   Relocations: (not relocatable)
Version     : 7.2.411                           Vendor: Red Hat, Inc.
Release     : 1.8.el6                       Build Date: Fri 17 Feb 2012 04:24:22 PM CET
Install Date: (not installed)               Build Host: x86-010.build.bos.redhat.com
Group       : Applications/Editors          Source RPM: vim-7.2.411-1.8.el6.src.rpm
Size        : 17773564                         License: Vim and GPLv2+ and BSD and LGPLv2+ and Open Publication
Signature   : RSA/8, Thu 05 Apr 2012 07:42:48 AM CEST, Key ID 199e2f91fd431d51
Packager    : Red Hat, Inc.
URL         : http://www.vim.org/
Summary     : The common files needed by any version of the VIM editor
Description :
VIM (VIsual editor iMproved) is an updated and improved version of the
vi editor.  Vi was the first real screen-based editor for UNIX, and is
still very popular.  VIM improves on vi by adding new features:
multiple windows, multi-level undo, block highlighting and more.  The
vim-common package contains files which every VIM binary will need in
order to run.

If you are installing vim-enhanced or vim-X11, you'll also need
to install the vim-common package.

Opcja -p odnosi się do jeszcze niezainstalowanych paczek. Weryfikacji tej możemy również dokonać na paczkach zainstalowanych, podając nazwę pakietu i pomijając przełącznik -p. Ta sama zasada tyczy się pozostałych wymienionych poniżej poleceń.

Kolejnym elementem możliwym do zweryfikowania w pakiecie, a przydatnym chyba bardziej przy próbie identyfikacji dla już zainstalowanych pakietów, jest możliwość wylistowania plików konfiguracyjnych, z jakich pakiet korzysta:

[root@server1 Packages]# rpm -qcp httpd-2.2.15-39.el6.x86_64.rpm
/etc/httpd/conf.d/welcome.conf
/etc/httpd/conf/httpd.conf
/etc/httpd/conf/magic
/etc/logrotate.d/httpd
/etc/sysconfig/htcacheclean
/etc/sysconfig/httpd
/var/www/error/HTTP_BAD_GATEWAY.html.var
/var/www/error/HTTP_BAD_REQUEST.html.var
/var/www/error/HTTP_FORBIDDEN.html.var
/var/www/error/HTTP_GONE.html.var
/var/www/error/HTTP_INTERNAL_SERVER_ERROR.html.var
/var/www/error/HTTP_LENGTH_REQUIRED.html.var
/var/www/error/HTTP_METHOD_NOT_ALLOWED.html.var
/var/www/error/HTTP_NOT_FOUND.html.var
/var/www/error/HTTP_NOT_IMPLEMENTED.html.var
/var/www/error/HTTP_PRECONDITION_FAILED.html.var
/var/www/error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var
/var/www/error/HTTP_REQUEST_TIME_OUT.html.var
/var/www/error/HTTP_REQUEST_URI_TOO_LARGE.html.var
/var/www/error/HTTP_SERVICE_UNAVAILABLE.html.var
/var/www/error/HTTP_UNAUTHORIZED.html.var
/var/www/error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var
/var/www/error/HTTP_VARIANT_ALSO_VARIES.html.var
/var/www/error/contact.html.var
/var/www/error/include/bottom.html
/var/www/error/include/spacer.html
/var/www/error/include/top.html

Widzimy tu listę wszystkich plików, w których ewentualnie możemy konfigurować dany pakiet.

Ostatnim z poleceń jest

[root@server1 Packages]# rpm -V ipa-client

Polecenie to weryfikuje, czy w plikach pakietu wprowdzone zostały jakieś zmiany. Sama opcja -V nie jest zbyt "gadatliwa" i zwraca nam tylko odnotowane zmiany, ale jeśli chcemy znać więcej detali tyczących się samego procesu weryfikacji, możemy użyć opcji -Vv, lub ekstremalnie -Vvv. Zobaczymy wtedy jakie elementy są sprawdzane, i co sprawdzeniu podlega.

[root@server1 Packages]# rpm -Vv ipa-client
.........    /usr/lib/python2.6/site-packages/ipaclient
.........    /usr/lib/python2.6/site-packages/ipaclient/__init__.py
.........    /usr/lib/python2.6/site-packages/ipaclient/__init__.pyc
.........    /usr/lib/python2.6/site-packages/ipaclient/__init__.pyo
.........    /usr/lib/python2.6/site-packages/ipaclient/ipachangeconf.py
.........    /usr/lib/python2.6/site-packages/ipaclient/ipachangeconf.pyc
.........    /usr/lib/python2.6/site-packages/ipaclient/ipachangeconf.pyo
.........    /usr/lib/python2.6/site-packages/ipaclient/ipadiscovery.py
.........    /usr/lib/python2.6/site-packages/ipaclient/ipadiscovery.pyc
.........    /usr/lib/python2.6/site-packages/ipaclient/ipadiscovery.pyo
.........    /usr/lib/python2.6/site-packages/ipaclient/ntpconf.py
.........    /usr/lib/python2.6/site-packages/ipaclient/ntpconf.pyc
.........    /usr/lib/python2.6/site-packages/ipaclient/ntpconf.pyo
.........    /usr/sbin/ipa-client-automount
.........    /usr/sbin/ipa-client-install
.........    /usr/sbin/ipa-getkeytab
.........    /usr/sbin/ipa-join
.........    /usr/sbin/ipa-rmkeytab
.........    /usr/share/doc/ipa-client-3.0.0
.........  d /usr/share/doc/ipa-client-3.0.0/COPYING
.........  d /usr/share/doc/ipa-client-3.0.0/Contributors.txt
.........  d /usr/share/doc/ipa-client-3.0.0/README
.........    /usr/share/ipa
.........    /usr/share/ipa/ipaclient
.........    /usr/share/ipa/ipaclient/ipa.cfg
.........    /usr/share/ipa/ipaclient/ipa.js
.........  d /usr/share/man/man1/ipa-client-automount.1.gz
.........  d /usr/share/man/man1/ipa-client-install.1.gz
.........  d /usr/share/man/man1/ipa-getkeytab.1.gz
.........  d /usr/share/man/man1/ipa-join.1.gz
.........  d /usr/share/man/man1/ipa-rmkeytab.1.gz
.........  d /usr/share/man/man5/default.conf.5.gz
.........    /var/lib/ipa-client
.........    /var/lib/ipa-client/sysrestore

Brak komentarzy:

Prześlij komentarz