Session Fixation

Wpis napisany 29 lutego 2008 w kategoriach: PHP/MySQL, Security, Techblog, Wszystkie | 18:24:29 | 7 komentarzy

W dzisiejszym artykule opiszę jeden z groźniejszych ataków na aplikacje PHP. Jest nim Session Fixation. W PHP istnieje mechanizm, zwany mechanizmem sesji. Istnieje po to, aby możliwe było jednoznaczne określenie unikalnego użytkownika odwiedzającego naszą stronę w danym czasie. Jak to zazwyczaj bywa, nic nie jest idealne.

Czytaj dalej »

Directory Traversal oraz RFI (Remote File Inclusion)

Wpis napisany 22 lutego 2008 w kategoriach: PHP/MySQL, Security, Techblog, Wszystkie | 19:27:21 | 7 komentarzy

W każdym systemie operacyjnym istnieje coś takiego jak drzewo katalogów. W nich umieszczone są pliki. W tym także i nasze skrypty. Często zdarza się, że wczytujemy z tego drzewa różne pliki przy pomocy PHP. Możemy je edytować, zapisywać, usuwać lub po prostu wczytywać do wykonania. Czasem zdarza się, że na podstawie różnych danych ustalamy co wczytać lub zapisać.

W takiej sytuacji pobieramy dane od użytkownika, łączymy z jakimś ciągiem znaków i wywołujemy skrypt. I tutaj błąd! Nigdy nie należy ufać danym przesłanym przez użytkownika. Postaram się wytłumaczyć zasadę działania całego błędu na przykładzie prostego skryptu wczytującego odpowiednie moduły:

<?php
function getModule($sModuleName)
{
        require_once($sModuleName.'.php');
        $module = new $sModuleName;
        return $module;
}

getModule($_GET['module']);
?>

Wydawałoby się, że wszystko jest w porządku. Nasz mały skrypt pobiera nazwę modułu, wczytuje plik z klasą i tworzy obiekt tej klasy. Jednak nie wszystko jest w porządku. Co się stanie w przypadku, gdy ktoś o złych zamiarach, zamiast zwykłego parametru poda coś w stylu „http://example.com/somebadscript”? Przypadkiem wczytamy plik z zewnętrznego serwera, a następnie wykonamy z niego kod. Teraz atakujący ma pełną władzę nad tym, co dzieje się w skrypcie, posiada dostęp do naszego połączenia z bazą danych... Jeden błąd, a tak tragiczny w skutkach!

Zacznijmy zabezpieczać. Na początek ograniczmy dostęp do folderów spoza naszego serwera. Jak to zrobić? Bardzo proste. Dwie najlepsze metody to wyłączenie w php.ini dyrektywy allow_url_include oraz dodanie przed ścieżką do pliku odwołania do lokalnego katalogu. Warto wykonać obydwie te czynności, jednak wystarczy właściwie zmienić skrypt w sposób pokazany poniżej:

<?php
function getModule($sModuleName)
{
        require_once('./'.$sModuleName);
        $module = new $sModuleName;
        return $module;
}

getModule($_GET['module']);
?>

Od tej pory nie wykonamy już żadnego zewnętrznego skryptu. Jednak dziura nadal istnieje! Atakujący nadal posiada dostęp do wszystkich plików na naszym serwerze... Dlaczego? Przecież może podać ścieżkę do katalogu nadrzędnego! Wczytajmy sobie teraz /etc/passwd:

GET script.php?module=../.../../../etc/passwd

Skutek po raz kolejny okazuje się opłakany. Treść naszego /etc/passwd zostaje przekazana atakującemu. W ten sposób można dostać się do niemal każdego pliku w systemie (szczególnie narażony jest Windows, który dość kiepsko radzi sobie z uprawnieniami – nie wiem jak to wygląda w wersji serwerowej). Kontynuujmy zatem łatanie naszego skryptu. Musimy się zastanowić, co tak naprawdę pozwala atakującemu na podglądanie naszych plików. Odpowiedź jest bardzo prosta. Aby dostać się do pliku wystarczyło odwołać się do nadrzędnego katalogu. Zrobienie tego polegało na użyciu ciągu znaków "../" w parametrze zapytania.

Kontynuujmy więc łatanie naszego skryptu. W PHP istnieje bardzo przyjemna funkcja basename(), która pozwala na ograniczenie dostępu do pojedynczego pliku z lokalnego katalogu. Jak działa? Usuwa po prostu wszystkie dane o katalogach url'ach z parametru i zwraca taką okrojoną nazwę. Wykorzystajmy to:

<?php
function getModule($sModuleName)
{
        require_once('./modules/'.basename($sModuleName).'.php');
        $module = new $sModuleName;
        return $module;
}

getModule($_GET['module']);
?>

W ten sposób zabezpieczony skrypt pozwoli na wczytanie plików tylko z katalogu modules. Nie ma możliwości „wyjścia z katalogu” przy pomocy directory traversal. Istnieją oczywiście inne metody zabezpieczania się przed tym atakiem. Jednym z nich jest używanie instrukcji warunkowej dla każdego modułu lub sprawdzanie występowania nazwy danego modułu w z góry zdefiniowanej tablicy modułów.

Pokazałem jedynie dwa przykłady z całej listy możliwości ataku. Należy pamiętać, że dane od użytkownika to nie tylko tablice $_GET i $_POST. Więcej na ten temat z pewnością umieszczę na blogu w oddzielnym wpisie. Poza tym należy szczególnie uważać podczas stosowania także takich funkcji jak fopen(), file() czy unlink(). Na zakończenie warto podsumować zdobyte informacje.

RFI (Remote File Inclusion) to błąd polegający na wczytaniu zewnętrznego pliku z serwera atakującego i wykonaniu go. Sposób na zabezpieczenie skryptu jest banalny, wystarczy wszystkie nazwy plików filtrować dzięki funkcji basename(). Jeżeli w ogóle nie potrzebujemy wczytywania plików PHP z zewnętrznych domen, możemy ustawić dyrektywę php.ini allow_url_include na false.

Directory Traversal to błąd pozwalający atakującemu na modyfikację lub wczytywanie pliku spoza dozwolonych. Polega na wykorzystaniu znaków powrotu do poprzedniego katalogu lub przejścia do katalogów podrzędnych w adresie pliku do wczytania.

Jakie jeszcze znacie metody użycia Directory Traversal? Spotkaliście się kiedyś z tego typu błędami w jakichś serwisach? A może sami go popełniliście/popełnialiście?

PS: Dodałem trackback do wpisu BTM'a o RFI.

NULL byte poisoning

Wpis napisany 18 maja 2007 w kategoriach: PHP/MySQL, Security, Techblog, Wszystkie | 15:27:50 | 12 komentarzy

Ten wpis jest kontynuacją i uzupełnieniem pierwszego artykułu na moim blogu dotyczącym błędów w PHP. Prosiliście o jakieś mniej znane metody ataków, więc opiszę ten, który miałem okazję poznać nie tak dawno. Miłej lektury ;).

Błąd polegający na dodaniu do nazwy wczytywanego przez skrypt php pliku tzw. "bajtu zerowego", czyli znaku o kodzie ASCII 0. Celem takiego ataku jest pozbycie się na siłę narzuconego przez programistę rozszerzenia. Tekst znajdujący się po wprowadzonym NULL'u jest po prostu ignorowany przez PHP, co pozwala na wczytanie dowolnego pliku. Często wykorzystywany z directory traversal. Nie działa przy włączonych magic_quotes (PHP automatycznie dodaje "\" przed NULL byte pochodzącym od użytkownika).

Przykładowy skrypt:

<?php include($_GET['file'].'.php'); //http://example.com/?file=../config.asd%00 ?>

Jak się zabezpieczyć?

Włączyć magic_quotes, filtrować dane wykorzystywane podczas wczytywania plików za pomocą addslashes, usuwać NULL byte za pomocą wyrażeń regularnych.

SQL Injection

Wpis napisany 26 lutego 2007 w kategoriach: PHP/MySQL, Security, Techblog, Wszystkie | 18:05:17 | 8 komentarzy

Artykuł ten jest rozwinięciem poprzedniego. Opiszę w nim ataki typu sql injection z przykładami oraz sposoby zabezpieczenia się przed nim na przykładzie bazy mysql. Artykuł adresowany jest zarówno dla początkujących programistów, jak i dla tych, którzy chcą się trochę zabawić skryptami, które przygotowałem :> (tutaj).

Na czym to dokładnie polega?

Całość jest wbrew pozorom bardzo łatwa do zrozumienia. Celem atakującego jest zmiana "sensu" wysyłanego do bazy zapytania, w celu uzyskania dodatkowych informacji, dostępu do konta lub nawet dowolnej zmiany zawartości bazy.

Czytaj dalej »

Najpopularniejsze ataki w PHP

Wpis napisany 21 lutego 2007 w kategoriach: PHP/MySQL, Security, Techblog, Wszystkie | 16:44:14 | 41 komentarzy

Tekst ten jest zestawieniem wszystkich najczęściej popełnianych przez programistów PHP błędów. Mimo tego, że wielu już na ten temat pisało, nie znalazłem takiego, w którym znalazły by się wszystkie te, o których słyszałem. Dlatego powstał ten artykuł, który ma za zadanie wyjaśnienie sposobu działania oraz sposobów zabezpieczania się przed niebezpieczeństwem. W dzisiejszych czasach niemal każdy piszący cokolwiek w PHP słyszał pewnie o sql_injection. Jednak takie rzeczy jak ataki typu session fixation czy XSS stają się czarną magią. Dlatego pozwolę sobie opisać je w sposób dostępny, mam nadzieję, dla każdego.

Czytaj dalej »

© Powered by JoggerPL and Albi