Konkurs na najbardziej niebezpieczną aplikację bankową 2016 rozstrzygnięty

dodał 16 maja 2016 o 20:53 w kategorii Błędy  z tagami:
Konkurs na najbardziej niebezpieczną aplikację bankową 2016 rozstrzygnięty

Wyobraźcie sobie mobilną aplikację bankową, za pomocą której każdy użytkownik może zalogować się jako ktokolwiek, dokonać przelewu z dowolnego, cudzego konta oraz ukryć wiadomość SMS informującą o transakcji.

Wydawało się nam, że takie rzeczy znaleźć można w trakcie warsztatów poświęconych bezpieczeństwu aplikacji mobilnych, gdy prowadzący dla potrzeb analizy specjalnie tworzy najbardziej dziurawą aplikację na świecie. Życie wyprzedza jednak naszą wyobraźnię.

Błąd za błędem

Hinduski badacz bezpieczeństwa, Sathya Prakash Kadhirvelan, postanowił przyjrzeć się bezpieczeństwu aplikacji mobilnej jednego z największych hinduskich banków. Aplikacja została udostępniona pod koniec roku 2015, gdy bank postanowił pójść z duchem czasu. Niestety duchowi czasu nie towarzyszył w tej drodze duch bezpieczeństwa.

Sathya najpierw zainstalował certyfikat Burpa na swoim iPhonie a następnie ustawił serwer proxy na komputerze, by spróbować przechwycić zaszyfrowany ruch aplikacji. Udało mu się to bez problemów – aplikacja nie identyfikowała prawidłowego certyfikatu, lecz radośnie akceptowała każdy jaki się trafił. Punkt dla Sathya.

Pierwsze żądanie do serwera weryfikowało czy jest dostępna aktualizacja aplikacji. Żądanie to było wysyłane przed zalogowaniem użytkownika, lecz zawierało jego identyfikator. W odpowiedzi aplikacja dostawała identyfikator sesji. Identyfikator sesji, który pozwalał na wykonywanie operacji na koncie użytkownika, takich jak np. odczyt listy produktów czy salda rachunków. Przed weryfikacją hasła. A do tego identyfikatory sesji były nieśmiertelne – z raz otrzymanego można było korzystać do końca wszechświata. Zatem sama znajomość szkolnych błędów w obsłudze sesji pozwalała na pogląd dowolnego rachunku w banku bez znajomości hasła – wystarczał identyfikator użytkownika i Burp. 3:0 dla Sathya. A to dopiero początek…

Przykład nieautoryzowanego żądania

Przykład nieautoryzowanego żądania

Bank umożliwiał przelewy na zaufane, wcześniej zdefiniowane konta. Weryfikacja, czy konto znajdowało się na liście zaufanych, była przeprowadzana na poziomie aplikacji klienta. Wystarczyło odpowiednio spreparowane żądanie do serwera by wysłać ze swojego rachunku przelew na dowolny, niezaufany cudzy rachunek. 4:0 dla Sathya, trener banku patrzy na swojego zawodnika wzrokiem pełnym niepokoju. Sathya nie testował już, czy aplikacja nie odpowiada też przypadkiem za weryfikację wysokości dostępnego salda – nie mógł tego sprawdzić bez łamania prawa.

Choć Sathya mógł sprawdzić wysokość salda na cudzym rachunku i przesłać ze swojego konta pieniądze na rachunek niezaufany, to przeciwnik w tej walce jeszcze całkiem nie opuścił gardy i choć chwiejnie, to jednak ciągle stał na nogach. Czas zatem było zadać decydujący cios. W żądaniu przelewu wysyłanym do serwera klient przekazywał konto źródłowe, konto docelowe oraz identyfikator nadawcy oraz skojarzony z nim stały kod MPIN. Serwer banku weryfikował, czy kod MPIN pasuje do identyfikatora nadawcy, ale nie weryfikował, czy identyfikator nadawcy pasuje do numeru konta źródłowego. Dzięki temu Sathya mógł, używając swojego ID oraz kodu MPIN, przelać pieniądze między dwoma dowolnymi kontami. 5:0 dla Sathya oraz nokaut przeciwnika. Kod wykonujący przelew wygląda na przykład tak:

echo "Enter Victim's CIF"
read vcif
fetchVictimAccInfo=accountInfo=$(curl --data "channel=rc&entityId=XXX&clientAppVer=XXX&appID=XXXXXXXX&customerId=$vcif&
             serviceID=fetchAllAccounts&mobPlatform=iPhone" -v -k https://mobile.xxxxxxxxxx.com:8444/middleware/MWServlet)
             victimSbAccountNo=$(echo $accountInfo | jq -r '.SB' | jq '.[0].accountno' | tr -d '"')
echo "Obtained Victim's Savings Account Number: $victimSbAccountNo"
echo "Enter Account Number to transfer the funds to: "
read attackerAccountNo
echo "Enter the amount to Siphon"
read amount
request="mobileAppVersion=1.1.2&MTPIN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&channel=rc"\
        "&entityId=xxx&beneficiaryAccount=$attackerAccountNo&serviceID=fundTransfer"\
        "&appID=XXXXXXX&txn_amount=$amount&customerId=XXXXXXXXXXX&transferType=XXXX"\
        "&appver=1.1.2&platform=iPhone&mobPlatform=iPhone&remarks=FreeCharge"\
        "&accountno=$victimSbAccountNo"
dotransaction=$(curl --data $request -v -k https://mobile.xxxxxxxxxxx.com:8444/middleware/MWServlet)
echo $dotransaction

Skoro przeciwnik leży już na deskach, to czas na kopanie leżącego. Teoretycznie nieautoryzowany przelew powinien być szybko wykryty, ponieważ bank informuje za pomocą wiadomości SMS o każdej zleconej transakcji. Kawał polega jednak na tym, że SMSa wysyła posiadaczowi identyfikatora autoryzującego transakcję, a nie posiadaczowi rachunku, z którego transakcja została wykonana. Zatem właściciel rachunku może nie dowiedzieć się o problemie dopóki sam nie sprawdzi co słychać z jego pieniędzmi.

Epilog

Sathya wysłał swoje znaleziska do pracowników banku. Już po 12 (!) dniach otrzymał odpowiedź z informacją, że bank wdroży rekomendowane przez niego poprawki. Gdy zapytał o program bug bounty, komunikacja się urwała. Bankowi i jego dostawcy za całokształt należy się nagroda za najbardziej niebezpieczną aplikację bankową roku 2016 – nie spodziewamy się, by komuś udało się ten wynik pobić (a na pewno nie będzie to łatwe).

A skoro już o bezpieczeństwie aplikacji mobilnych mowa, to czas uchylić rąbka tajemnicy – już wkrótce pod marką Zaufanej Trzeciej Strony ruszą szkolenia, w tym także dotyczące tego obszaru.