27-09-2018 / Od 0 do pentestera

Omijanie filtrów PHP przy użyciu znaku mniejszości

Czasami potrzebujemy umożliwić użytkownikowi pobranie plików z serwera.

Może on pobrać wszystkie pliki z konkretnego katalogu oprócz jednego - nazwanego u nas sekret.txt.

Funkcjonalność tą możemy uzyskać przy pomocy 3 linijek:

$plik = basename((string) $_GET['plik']);
if (stristr($plik, 'sekret.txt') === false) {
            echo file_get_contents($plik);
}

Na początek funkcja basename, która usuwa wszystkie znaki ../ oraz ..\ z parametru plik.

Dzięki temu jesteśmy pewni, że podany przez użytkownika adres do pliku nie zawiera katalogów nadrzędnych.

Następnie przy pomocy funkcji stristr sprawdzamy, czy podany ciąg nie zawiera słowa "sekret.txt".

Funkcja ta ma w swojej nazwie i - co oznacza, że nie rozróżnia wielkich i małych liter.

Zabezpieczamy się zatem przed sytuacją, w której użytkownik podałby nazwę naszego pliku zaczynając od wielkiej litery i w ten sposób ominął filtr.

Jeśli parametr nie posiada w nazwie słowa sekret.txt, plik jest wyświetlany przy użyciu funkcji file_get_contents1.

Sprawdźmy jak działa ten prosty skrypt.

W katalogu zawarłem również plik test.txt, spróbujmy wyświetlić najpierw jego treść.

Przykład działania

Wszystko działa jak należy. Teraz plik sekret.txt.

Działanie filtru

Jak widać nic nie zostało wyświetlone.

Gdzie zatem znajduje się dzisiejszy błąd?

Jak możemy przeczytać w dokumencie "Oddities of PHP file access in Windows"2 ciąg znaków << przekazywany do funkcji file_get_contents zamieniany jest na gwiazdkę.

Dziwne działanie API

Taki to ciąg jest dalej przekazywany do API FindFirstFile, które to jest odpowiedzialne za poszukiwanie odpowiedniego pliku w systemie.

Tam gwiazdka oznacza symbol wieloznaczny (z ang. wild card).

Zostanie więc wyświetlony pierwszy plik, w którym pasuje reszta znaków.

Zamiast więc podawać w parametrze "sekret.txt" można zatem ominąć filtr zamieniając ostatnie znaki na <<.

Ominięcie filtru

Oprócz * możemy także użyć:

ZnakZnaczeniePrzykład
"zamieniany na . (kropka)secret"jpg
>zamieniany na ? (dowolny jeden znak)secret.jpg>

Oczywiście Windows nie jest najpopularniejszym systemem używanym do wyświetlania plików PHP, dlatego też dla większości skryptów błąd ten ma marginalne znaczenie, bowiem nigdy nie będzie go można użyć.

Sytuacja ta pokazuje jednak, że tak proste i popularne funkcje jak file_get_contents służące do wyświetlanie treści pliku mogą zawierać kruczki, które nie są jasno opisane na stronie dokumentacji i mogą być wykorzystanego przez atakującego.