Читать книгу Na tropie błędów. Przewodnik hakerski - Peter Yaworski - Страница 19
3.
HTTP PARAMETER POLLUTION
HPP po stronie serwera
ОглавлениеW przypadku HPP po stronie serwera, do serwera wysyła się nieoczekiwane informacje w zamiarze otrzymania od niego nieoczekiwanych rezultatów. Kiedy wykonujesz żądanie do strony internetowej, serwer tej strony przetwarza żądanie i zwraca odpowiedź, tak jak omawialiśmy to w rozdziale 1. W niektórych przypadkach serwery nie zwracają zwyczajnie strony internetowej, ale również uruchamiają kod, bazując na informacji, którą otrzymali z odebranego URL-a. Kod ten jest uruchamiany tylko na serwerze, jest więc niewidoczny dla ciebie; możesz zobaczyć wysłaną informację i zwrócony rezultat, lecz pośredniczący kod jest nieosiągalny. W związku z tym możesz jedynie wywnioskować to, co się dzieje. Ponieważ nie widzisz tego, jak kod serwera funkcjonuje, HPP po stronie serwera zależy od Twojej zdolności do identyfikacji potencjalnie podatnych parametrów i eksperymentowania z nimi.
Spójrzmy na przykład: HPP po stronie serwera mógłby wystąpić wtedy, gdy Twój bank inicjowałby przelew za pomocą swojej strony przez akceptację parametrów URL, które są przetwarzane na jego serwerach. Wyobraź sobie, że mógłbyś zrobić przelew przez wpisanie trzech wartości w trzech parametrach URL: from, to i amount. Parametry te określają kolejno numer konta, z którego ma zostać wykonany przelew, numer konta docelowego i kwotę pieniędzy do przesłania. Adres URL z tymi parametrami, który przesyła 5000 $ z konta o numerze 12345 na konto 67890, wyglądałby następująco:
https://www.bank.com/transfer?from=12345&to=67890&amount=5000
Możliwe jest, że bank zakładałby, że otrzyma tylko jeden parametr from. Co jednak jeśli otrzyma dwa, tak jak tutaj:
https://www.bank.com/transfer?from=12345&to=67890&amount=5000&from=ABCDEF
Ten URL jest umyślnie zbudowany tak samo jak poprzedni z tą różnicą, że zawiera dodatkowy parametr from, który określa inne konto nadawcy, ABCDEF. W tej sytuacji atakujący mógłby wysłać dodatkowy parametr w nadziei, że aplikacja zweryfikuje transfer, używając pierwszego parametru from, ale pobierze pieniądze, używając drugiego. Zatem atakujący byłby w stanie wykonać transfer pieniędzy z konta, do którego nie ma dostępu, jeżeli tylko bank akceptowałby ostatni parametr from, który otrzymał. Zamiast wysyłać 5000 $ z konta 12345 na 67890, kod serwera użyłby drugiego parametru i wysłał pieniądze z konta ABCDEF na 67890.
Kiedy serwer dostaje kilkukrotne parametry z tą samą nazwą, może odpowiedzieć na wiele sposobów. Na przykład PHP i Apache używają ostatniego wystąpienia, Apache Tomcat używa pierwszego, ASP i IIS używają wszystkich i tak dalej. Dwóch badaczy, Luca Carettoni i Stefano di Paola, udostępnili dokładną prezentację wielu różnic między technologiami serwerów podczas konferencji AppSec EU 09; informacja ta jest teraz dostępna na stronie OWASP na https://www.owasp.org/images/b/ba/AppsecEU09_CarettoniDiPaola_v0.8.pdf (zob. slajd 9). W wyniku tego nie ma jednego gwarantowanego procesu do obsługi wielokrotnych parametrów z tą samą nazwą, więc znalezienie podatności HPP wymaga nieco kombinowania, by przekonać się o tym, jak działa strona, którą sprawdzasz.
Przykład z bankiem używa parametrów, które są oczywiste. Czasami jednak podatności HPP objawiają się jako rezultat ukrytego zachowania po stronie serwera, wynikającego z kodu, który nie jest bezpośrednio widoczny. Powiedzmy na przykład, że Twój bank zadecydował ulepszyć sposób, w jaki przetwarza przelewy, i zmienia kod w backendzie tak, aby nie używał parametru from z URL-a. Tym razem bank użyje dwóch parametrów, jednego do konta, na które ma zostać wykonany przelew, a drugiego do kwoty do przelania. Przykładowy link mógłby wyglądać tak:
https://www.bank.com/transfer?to=67890&amount=5000
Zazwyczaj kod na serwerze byłby dla nas zagadką, lecz ze względu na potrzeby tego przykładu wiemy, że kod Ruby serwera (nadzwyczaj brzydki i bezużyteczny) wygląda następująco:
user.account = 12345
def prepare_transfer(params)
params << user.account
transfer_money(params) #user.account (12345) becomes params[2]
end
def transfer_money(params)
to = params[0]
amount = params[1]
from = params[2]
transfer(to,amount,from)
end
Ten kod tworzy dwie funkcje, prepare_transfer i transfer_money. Funkcja prepare_transfer używa tablicy o nazwie params , która zawiera parametry to i amount pochodzące z URL-a. Tablicę stanowiłoby [67890,5000], gdzie jej wartości są wciśnięte między nawiasy, a każda wartość jest oddzielona przecinkiem. Pierwsza linia funkcji dodaje informacje o koncie użytkownika, które zostały zdefiniowane wcześniej w kodzie, na końcu tablicy. Dostajemy zatem tablicę params [67890,5000,12345], która następnie jest przekazana do transfer_money . Zauważ to, że w odróżnieniu od parametrów tablice nie mają nazw powiązanych z ich wartościami, więc kod podlega tablicy zawierającej zawsze każdą wartość w następującej kolejności: konto odbiorcy jako pierwsze, kwota przelewu druga i konto, z którego wychodzi przelew, jako następne. W transfer_money kolejność wartości staje się oczywista z racji, że funkcja przypisuje każdą wartość tablicy do zmiennej. Ze względu na to, że tablice są numerowane od 0, params[0] przyjmuje pierwszą wartość w tablicy, którą w tym przypadku jest 67890 i przypisuje ją do zmiennej to . Pozostałe wartości są również przypisywane zmiennym w wierszach i . Wtedy nazwy zmiennych są przekazane do funkcji transfer, niepokazanej w tym fragmencie, która przyjmuje wartości i wykonuje przelew.
W najlepszej sytuacji parametry URL byłyby zawsze formatowane w sposób, jakiego kod oczekuje. Jednakże atakujący mógłby zmienić wynik tego procesu przez podanie w from wartości dla params, tak jak z następującym URL-em:
https://www.bank.com/transfer?to=67890&amount=5000&from=ABCDEF
W tej sytuacji parametr from jest również włączony do tablicy params przekazanej funkcji prepare_transfer; co za tym idzie, wartościami tablicy mogłyby być [67890,5000,ABCDEF], a podanie konta użytkownika w dawałoby rezultat w postaci [67890,5000,ABCDEF,12345]. W wyniku tego w funkcji transfer_money wywołanej w prepare_tranfer wartość from stałaby się trzecim parametrem, zamieniając oczekiwaną wartość 12345 na wartość atakującego ABCDEF .