Path Traversal - o krok od błędu

Path Traversal – o krok od błędu

data: 17 czerwca, 2013
czas czytania: 5 min
autor: Katarzyna Michalczyk

W analizowanej w poniższym artykule aplikacji występuje poważny błąd typu Insecure Direct Object References. Można go wywołać przy pomocy ataku Path Traversal, czyli takim manipulowaniu ścieżką, aby dostać się do teoretycznie niedostępnych plików.

W artykule chcę zademonstrować, jak NIE należy pisać oraz jak łut szczęścia uchronił przed dużo poważniejszym błędem.

Aplikacja, o której mowa, udostępnia zdjęcia, które są przechowywane w jej zasobach. Zdjęcia wyświetlane są w galerii na stronie, a ich bezpośrednia ścieżka wygląda następująco:

https://kariera.future-processing.pl//wp-content/uploads/2013/06/Nameimage01.jpg

k.konieczniak1

Na serwerze zdjęcia przechowywane są w folderze C:webappResourcesImages.

Przy manipulacji wartością parametru okazuje się, że bez problemu można dotrzeć do dowolnego folderu na serwerze i wyświetlić plik, który w nim się znajduje. Pod jednym warunkiem: musi być to plik graficzny.

W przypadku wyświetlania dowolnego innego pliku, wyświetla się czarny obrazek, a po ściągnięciu go na dysk możemy odczytać jedynie śmieci.

Załóżmy, że interesuje nas plik, do którego pełna ścieżka to C:webappjakiskod.cs

http://webapp.com/Files.ashx?Name=../../jakiskod.cs

kkonieczniak2

Jedyne o czym mówi nam czarny kwadrat, to fakt, że plik, do którego próbowaliśmy się dostać rzeczywiście istnieje. Gdyby takiego pliku nie było, otrzymalibyśmy w wyniku zaślepkę noimage.jpg.

Dlaczego nie możemy odczytać pliku, chociaż do „sukcesu” jest już tak blisko? Pora na zajrzenie do kodu.

Public void NaszaMetoda(HttpContext context)
{
           string  ilename = context.Request.QueryString["Name"];
           string virtualPath = "~/Resources/Images";

           if (string.IsNullOrEmpty( ilename))
           {
                     string imageIdentificator = context.Request.QueryString["ImageID"];
                     //...

                     if (string.IsNullOrEmpty(imageIdentificator))
                     {
                                imageIdentificator = context.Request.QueryString["..."];

                                /* Jesli plik nie istnieje, wyswietl noimage.jpg */
                                if (string.IsNullOrEmpty(imageIdentificator))
                                            ilename = "noimage.jpg";
                                else
                                           //...
                                            ilename = PicturePath;
                     }
                     else
                                //...
                                 ilename = PicturePath;
           }

           string filePath = Path.Combine(context.Server.MapPath(virtualPath),  ilename);

           /* Jesli sciezka nie istnieje, zamien na noimage.jpg */
           if (!File.Exists(filePath))
           {
                      ilename = "noimage.jpg";
                     filePath = Path.Combine(context.Server.MapPath(virtualPath),  ilename);
           }

           context.Response.ContentType = "image/jpeg";
           context.Response.AddHeader("content-disposition", "filename=" +       
            + Path.GetFileName( ilename) + ".jpg");

           Image img = new Bitmap(100, 100);

           try
           {
                     img = Image.FromFile(filePath);
           }
           catch(Exception e)
           {
                     Console.Write(e.Message);
           }

           //...
           // rysowanie zdjecia
}

Po analizie metody odpowiadającej za dostęp do zdjęć, widzimy, że nie ma zabezpieczenia, które nie pozwalałoby wyjść parę folderów wyżej i wyświetlić inny plik.

Gdy przyjrzymy się głębiej, naszą uwagę zwraca funkcja w linii 27.

String filePath = Path.Combine(context.Server.MapPath(virtualPath), ilename);

MSDN śpieszy z jej wyjaśnieniem.

Public static string Combine(
         string path1,
         string path2
)

Parameters

Path1

Type: System.String
The first path to combine.

Path2

Type: System.String
The second path to combine.

Return Value

Type: System.String
The combined paths. If one of the specified paths is a zero-length string, this method returns the other path. If path2 contains an absolute path, this method returns path2.

Ostatnie zdanie zapala czerwoną lampkę. If path2 contains an absolute path, this method returns path2.

W takim razie co się stanie, jeśli podamy ścieżkę do pliku znajdującego się, dajmy na to, na innej partycji?

https://kariera.future-processing.pl//wp-content/uploads/2013/06/NameDMojeRysunkirysunek.jpg

kkonieczniak3

Jak można się było tego domyślać, Combine zadziałało zgodnie z założeniami. Z racji, że argument path2 był ścieżką bezwzględną, funkcja nie połączyła dwóch ścieżek, a użyła jedynie tej drugiej.

Pójdźmy dalej. Podajmy ścieżkę bezwzględną do zewnętrznego zasobu.

http://webapp.com/Files.ashx?Name=zasobMoje_dokumentykkonieczniakkotek.jpg

k.konieczniak4

Idąc tym tropem, możemy dostać się w zasadzie wszędzie! Naszą jedyną blokadą jest tylko przekleństwo czarnego kwadratu. Wróćmy na chwilę do podanego wyżej kodu, do linii 40 i 44.

Image img = new Bitmap(100, 100);
img = Image.FromFile(filePath);

Dzięki tym wywołaniom z naszej ścieżki tworzony jest obiekt klasy Image. Klasa ta, przyjmując zły plik (który nie jest obrazem), rzuca wyjątek Out Of Memory. To jednak nie przeszkadza funkcji wykonywać się dalej. Wyłapywane są tylko wyjątki na potrzeby tej jednej funkcji, nie ma żadnej ich obsługi (oprócz logowania błędu). Kod obsługi wyjątku został wygenerowany przez środowisko. Poprawnym rozwiązaniem byłoby „zabicie” dalszej akcji, tuż po wykryciu tego błędu. Nasz aktualny „obraz” wypełniany jest śmieciami i dlatego właśnie widzimy czarny kwadrat.

Dlatego też jesteśmy jedynie krok od poważnego błędu. Co jednak możemy zrobić? Podać ścieżkę do olbrzymiego pliku, by wywołać DoS aplikacji? Sprawdzać na ślepo różne ścieżki, aby czarny kwadrat powiedział nam, czy takie pliki istnieją na serwerze?

Zastanowienie się nad skutkami tego błędu pozostawiam do refleksji Wam :).

Newsletter IT leaks

Dzielimy się inspiracjami i nowinkami z branży IT. Szanujemy Twój czas - obiecujemy nie spamować i wysyłać wiadomości raz na dwa miesiące.

Subscribe to our newsletter

Administratorem Twoich danych osobowych jest Future Processing S.A. z siedzibą w Gliwicach. Twoje dane będziemy przetwarzać w celu przesyłania cyklicznego newslettera dot. branży IT. W każdej chwili możesz się wypisać lub edytować swoje dane. Więcej informacji znajdziesz w naszej polityce prywatności.

Subscribe to our newsletter

Administratorem Twoich danych osobowych jest Future Processing S.A. z siedzibą w Gliwicach. Twoje dane będziemy przetwarzać w celu przesyłania cyklicznego newslettera dot. branży IT. W każdej chwili możesz się wypisać lub edytować swoje dane. Więcej informacji znajdziesz w naszej polityce prywatności.