31-01-2019 / Od 0 do pentestera

CSRF - Cross Site Request Forgery

W dzisiejszym odcinku postaram się wytłumaczyć popularny błąd CSRF - czyli Cross Site Request Forgery, który często jest mylony z atakiem XSS.

Spróbujemy zrozumieć ten rodzaj podatności na podstawie WordPressa, czyli najpopularniejszego systemu blogowego.

Zobaczysz jak atakujący mógłby stworzyć nowe konto administratora i wykorzystać je do przejęcia całej strony, jeżeli WordPress nie posiadałby odpowiedniego mechanizmu chroniącego przed tym atakiem.

Oto nasz system blogowy. Na poczet dzisiejszego demo zaloguję się teraz jako administrator.

Spróbujmy dodać nowego administratora.

Jak widzisz, aby stworzyć nowego użytkownika wysyłamy żądanie POST, w którym podajemy jego nazwę i hasło.

WordPress sprawdza czy posiadamy uprawnienia do tworzenia nowych użytkowników i jeżeli wszystko się zgadza, tworzy nowy profil.

Nowe konto administratora

Przy pomocy tego formularza możemy stworzyć kolejnego użytkownika.

Wystarczy tylko zmienić login i jak widzisz nowy użytkownik pojawił się w systemie.

Ale to nie jest takie proste.

W formularzu tym bowiem znajduje się pole nonce.

To pole jest generowane przez skrypt za każdym razem gdy wchodzimy na stronę z formularzem do tworzenia nowego użytkownika i to właśnie ono chroni przed atakami CSRF.

Wartość, która jest w tym polu jest wyliczana przez specjalny algorytm oparty na czasie oraz pewnej sekretnej, nieznanej nam wartości.

Ta wartość jest natomiast znana serwerowi i tylko on może wygenerować prawidłowy klucz.

Oprócz sprawdzania loginu i hasła oraz naszych uprawnień, serwer sprawdza również czy nasza wartość nonce jest prawidłowa.

Możemy to w prosty sposób przetestować.

Wystarczy, że zmienimy wartość tego pola na jakąś inną i tym razem - zamiast nowego użytkownika, otrzymaliśmy komunikat o błędzie.

Dlaczego ta wartość jest taka kluczowa?

Spróbujmy na moment usunąć z kodu WordPressa zabezpieczenie przed tym atakiem.

Jest za to odpowiedzialna funkcja wp_verify_nonce.

wp_verify_nonce

Dla naszych testów ta funkcja będzie zawsze zwracała 1, przez co serwer będzie myślał, że klucz jest prawidłowy - nawet jeżeli go nie podamy.

Wiemy już jaki formularz jest odpowiedzialny za tworzenie nowego użytkownika.

Ale taki formularz może znajdować się na dowolnej stronie na dowolnej domenie - nie tylko w obrębie naszego bloga.

Stwórzmy więc taki sam formularz na stronie atakującego, która znajduje się na zupełnie innej domenie.

Jeżeli teraz administrator bloga zostanie przekonany do wejścia na taką stronę i kliknięcia w dany formularz - nowy administrator zostanie prawidłowo stworzony.

CSRF

Ale jak to? Przecież nie jesteśmy zalogowani na złej domenie. Skąd ona znała nasze dane do logowania?

Odpowiedź jest prosta. Nie musiała znać naszych danych do logowania.

Podczas przesyłania formularza przeglądarka sprawdza do jakiej domeny jest on wysyłany.

W naszym wypadku ten formularz prowadzi do domeny bloga.

W tym momencie Chrome sprawdziło czy bieżący użytkownik przeglądarki posiada jakieś ciasteczka powiązane z tą stroną.

Ciasteczko

Tak się akurat składa, że byliśmy w tym samym momencie zalogowani na blogu jako administrator - więc w przeglądarce było nasze ciasteczko administratora.

Zostało ono więc dołączone do formularza razem z danymi odpowiedzialnymi za stworzenie nowego użytkownika.

Dzieje się to automatycznie - bez naszej wiedzy.

To ciasteczko jest przesyłane jedynie do domeny bloga - zła domena nie może pobrać lub zmodyfikować jego treści.

System blogowy na podstawie tego ciasteczka stwierdził, że jesteśmy administratorem i pozwolił na wykonanie danej akcji.

Tutaj wymagaliśmy jednak, aby administrator kliknął w formularz na naszej stronie.

Ale niekoniecznie musi tak być.

Przy pomocy odrobiny kodu JavaScript możemy automatycznie wysłać taki formularz na serwer.

Aby zatem zaatakować ten blog wystarczy przekonać zalogowanego administratora do wejścia na nasza złośliwą witrynę.

JavaScript onload

I tu do gry wchodzi ochrona przed atakiem CSRF.

Serwer podczas tworzenia formularza generuje również unikalny token powiązany z danym użytkownikiem, który to token jest wysyłany razem z danymi od użytkownika.

System blogowy porównuje wartość tego tokena z tą oczekiwaną i jedynie jeżeli się ona zgadza przetwarza dane dalej.

Sekretna wartość token

My jako atakujący nie możemy stworzyć formularza z prawidłową wartością tego tokenu, ponieważ nie znamy jego wartości i nie możemy jej wyliczyć.

Dlatego też, nawet jeżeli zalogowany administrator wejdzie na naszą stronę i wyśle nasz formularz, będzie on zawierał błędny token CSRF.

Dzięki temu serwer będzie wiedział, że ten formularz jest nieprawidłowy i nie będzie go obsługiwał.

Widać to na kolejnym przykładzie, gdzie przywracam ochronę przed CSRF.

Tym razem serwer odrzucił nasze żądanie - ponieważ nie przesłaliśmy prawidłowego tokenu do serwera.

Teraz już wiesz dlaczego formularze na stronach internetowych zawierają pole z losowymi wartościami.

Icon made by Freepik, Smashicons, Pixel perfect from www.flaticon.com