Testowanie
bezpieczeństwa
aplikacji dedykowanych
na platformę Android
Łukasz Bobrek
Kraków, 27.04.2016
O MNIE
• Analiza ryzyka oraz konsultacje dotyczące bezpieczeństwa w IT
• Testy bezpieczeństwa aplikacji webowych oraz mobilnych
Inżynieria wsteczna złośliwego oprogramowania na Androida
Łukasz Bobrek
Specjalista ds. Bezpieczeństwa IT
1. Wprowadzenie do testowania bezpieczeństwa aplikacji mobilnych
2. Analiza statyczna
• Analiza paczki z aplikacją
• Dekompilacja oraz analiza kodu źródłowego
3. Analiza dynamiczna
• Analiza plików oraz logów zapisywanych w trakcie działania aplikacji
• ataki wykorzystujące oddziaływanie aplikacji z innymi aktywnymi procesami działającymi na urządzeniu
• ataki na komunikację pomiędzy urządzeniem mobilnym, a zdalnym serwerem aplikacji
• ataki na API po stronie serwera
PLAN PREZENTACJI
WPROWADZENIE
PO CO ATAKOWAĆ APLIKACJE NA ANDROIDA?
~ 2 082 700 000 użytkowników urządzeń mobilnych
~ 1 062 177 000 użytkowników mobilnych aplikacji bankowych
~ 3 970 000 aplikacji mobilnych
~ 1 000 000 aplikacji mobilnych sklasyfikowanych jako złośliwe oprogramowanie
www.statista.com, Symantec
JAK ATAKOWAĆ URZĄDZENIA MOBILNE?
?
JAK ATAKOWAĆ URZĄDZENIA MOBILNE?
Inna aplikacja na urządzeniu
Podatności systemu
Kradzież, zgubienie urządzenia, przypadkowy dostęp, inna aplikacja...
Ataki na transmisję -podsłuch, słabości SSL
Social engineering,słabości użytkownikównp. słabe hasło, zbyt trudne mechanizmy
API – błędy kontroli dostępu, logiczne, konfiguracji...
Analiza paczki
PACZKA APLIKACJI
Archiwum zip zawierające skompilowany kod źródłowy
w formie .dex oraz pozostałe zasoby wchodzącew skład aplikacji w formie zakodowanej:
• plik AndroidManifest.xml - określa podstawowecharakterystyki aplikacji oraz określa jej komponenty
• pozostałe pliki z rozszerzeniem .xml, zawierającem.in. kolekcje danych oraz definicje szablonów
• wszelkie pliki graficzne oraz multimedialnepotrzebne do prawidłowego działania aplikacji
PACZKA APLIKACJI
• Jak zdobyć paczkę z aplikacją?
• Każdą aplikację można wyciągnąć z urządzeniaadb pull /data/app/nazwa-aplikacji.apk (root)
• Każdą aplikację dostępną w Google Play można pobrać w formie pliku .apkwww.apkpure.com
ANALIZA STATYCZNA
ANALIZA STATYCZNA
DEKODWANIE APLIKACJI
• apktool - http://ibotpeaches.github.io/Apktool/
• # apktool decode aplikacja.apk
• Otrzymujemy:
• AndroidManifest.xml
• Definicje szablonów, stringi, widoki…
• Elementy graficzne
• pliki smali – coś pomiędzy kodem źródłowym,a kodem maszynowym – odpowiednik Assemblera
DEKODOWANIE APLIKACJI
• Aplikacja Airbnb, rok 2012
• Plik strings.xml --> /res/values/strings.xml
• Tak, to naprawdę tokeny OAUTH do linkedina, microsoftuoraz facebooka !
CO MOŻNA ZNALEŹĆ W APLIKACJI?
API
API
API
REKOMPILACJA APLIKACJI
• Smali
invoke-virtual {v0}, Ljava/lang/ref/WeakReference;
get()Ljava/lang/Object;
move-result-object v0
check-cast v0, Lcompany/appname/d/b;
if-eqz v0, :cond_0
invoke-virtual {v0, p1, p2},
• # apktool b aplikacja
• # d2j-apk-sign /dist/aplikacja.apk
REKOMPILACJA APLIKACJI
• Smali
invoke-virtual {v0}, Ljava/lang/ref/WeakReference;
get()Ljava/lang/Object;
move-result-object v0
check-cast v0, Lcompany/appname/d/b;
if-eqz v0, :cond_0 --> if-neq v0, :cond_0 ?
invoke-virtual {v0, p1, p2},
• # apktool b aplikacja
• # d2j-apk-sign /dist/aplikacja.apk
ANALIZA STATYCZNA
REKONSTRUKCJA KODU ŹRÓDŁOWEGO
• Dex2jar – https://sourceforge.net/projects/dex2jar/
• Jd-gui - http://jd.benow.ca/
1. rozpakowujemy plik .apk (bez dekodowania)
2. # d2j-dex2jar classes.dex
3. Rozpakowujemy plik classes-dex2jar.jar
4. Otrzymujemy pliki klas z rozszerzeniem .class
5. Dekompilacja do kodu JAVA (jd-gui)
ANALIZA KODU ŹRÓDŁOWEGO
• Pozwala na zrozumienie działania aplikacji,
co ułatwia dalsze ataki
• Identyfikacja błędów w implementacji różnych funkcjonalności
• Komentarze pozostawione przez programistów ;)
• Hasła, klucze, tokeny…
//When I wrote this, only God and I understood what I was doing //Now, God only knows
ANALIZA KODU ŹRÓDŁOWEGO
• Aplikacja Snapchat, rok 2011
Klucze szyfrujące na stałe zaszyte w kodzie źródłowym
ZACIEMNIANIE KODU ŹRÓDŁOWEGO
Zaciemnianie kodu polega na jego modyfikacji w celu
utrudnienia jego interpretacji.
Najczęściej wykorzystywanymi metodami zaciemniania kodu są:
• zmiany nazw parametrów oraz metod
• zmiany przebiegu kodu (zmiany warunków pętli,
dublowanie metod…)
• zmiany kodowania, zmiany długości życia zmiennych…
ZACIEMNIANIE KODU ŹRÓDŁOWEGO
public final class a
{
private static final char[] a = { 67,72,65,82,84,79,83,67,72,76,
85,68,78,73,69 };
private static void a(char[] paramArrayOfChar, char paramChar)
{
paramArrayOfChar[0] = paramChar; int i = 0;
if (i < paramArrayOfChar.length)
{
if (i % 2 == 0) { paramArrayOfChar[i] = a[(i % a.length)];
}
for (;;)
{
i++; break; paramArrayOfChar[0] = paramChar;
(...)
ZACIEMNIANIE KODU ŹRÓDŁOWEGO
public final class a
{
private static final char[] a = { 67,72,65,82,84,79,83,67,72,76,
85,68,78,73,69 };
private static void a(char[] paramArrayOfChar, char paramChar)
{
paramArrayOfChar[0] = paramChar; int i = 0;
if (i < paramArrayOfChar.length)
{
if (i % 2 == 0) { paramArrayOfChar[i] = a[(i % a.length)];
}
for (;;)
{
i++; break; paramArrayOfChar[0] = paramChar;
(...)
„Charschludnie”
ANALIZA DYNAMICZNA
ANALIZA DYNAMICZNA
• Analiza funkcjonalności dostępnych w aplikacji
• Sprawdzenie logów oraz cache zapisywanych przez aplikację
• Sprawdzenie jakie aplikacja uruchamia procesy oraz jakie pliki są przez nią zapisywane
• Obserwacja ruchu sieciowego generowanego przez aplikację
• Analiza IPC (ang. inter-proces communication)
• Weryfikacja poprawności konfiguracji SSL
• Testy API serwera aplikacji
ANALIZA DYNAMICZNA
LOGI SYSTEMOWE
• Dosyć często zawierają pełne żądania HTTP, a w nich np. dane uwierzytelniające użytkowników
INSERT INTO "cfurl_cache_response" VALUES(2,0,1594297610,0,'http://dev/service/auth/createFirstSession?password=35971831&sessionId=857006 &userId=24384344','1970-01-21 23:03:36');
LOGI SYSTEMOWE
$ adb logcatI/System.out( 1098): BaseActivity calling: /login onResponseData: {"response":{"mask":"c794ffa2ffbdffc180ff41ff","phi":"/(...)D/InputEventConsistencyVerifier( 1098): 0: sent at 6529438000000, KeyEvent { action=ACTION_UP, keyCode=KEYCODE_3, scanCode=4, metaState=0, flags=0x8, repeatCount=0, eventTime=6529438, downTime=6529371, deviceId=0, source=0x301 } D/InputEventConsistencyVerifier( 1098): 0: sent at 6532144000000, KeyEvent { action=ACTION_UP, keyCode=KEYCODE_5, scanCode=6, metaState=0, flags=0x8, repeatCount=0, eventTime=6532144, downTime=6532032, deviceId=0, source=0x301 } D/InputEventConsistencyVerifier( 1098): 0: sent at 6534378000000, KeyEvent { action=ACTION_UP, keyCode=KEYCODE_7, scanCode=8, metaState=0, flags=0x8, repeatCount=0, eventTime=6534378, downTime=6534277, deviceId=0, source=0x301 } D/InputEventConsistencyVerifier( 1098): 0: sent at 6536876000000, KeyEvent { action=ACTION_UP, keyCode=KEYCODE_0, scanCode=11, metaState=0, flags=0x8, repeatCount=0, eventTime=6536876, downTime=6536811, deviceId=0, source=0x301 } I/System.out( 1098): BaseActivity calling: /login/maskedPassword onResponseData: {"response":{"state":"A","authenticated":true},"msgId":"1344674218830418930","errorCode":0,"time":1351588394408,"errorDesc":""}
LOGI SYSTEMOWE
$ adb logcatI/System.out( 1098): BaseActivity calling: /login onResponseData: {"response":{"mask":"c794ffa2ffbdffc180ff41ff","phi":"/(...)D/InputEventConsistencyVerifier( 1098): 0: sent at 6529438000000, KeyEvent { action=ACTION_UP, keyCode=KEYCODE_3, scanCode=4, metaState=0, flags=0x8, repeatCount=0, eventTime=6529438, downTime=6529371, deviceId=0, source=0x301 } D/InputEventConsistencyVerifier( 1098): 0: sent at 6532144000000, KeyEvent { action=ACTION_UP, keyCode=KEYCODE_5, scanCode=6, metaState=0, flags=0x8, repeatCount=0, eventTime=6532144, downTime=6532032, deviceId=0, source=0x301 } D/InputEventConsistencyVerifier( 1098): 0: sent at 6534378000000, KeyEvent { action=ACTION_UP, keyCode=KEYCODE_7, scanCode=8, metaState=0, flags=0x8, repeatCount=0, eventTime=6534378, downTime=6534277, deviceId=0, source=0x301 } D/InputEventConsistencyVerifier( 1098): 0: sent at 6536876000000, KeyEvent { action=ACTION_UP, keyCode=KEYCODE_0, scanCode=11, metaState=0, flags=0x8, repeatCount=0, eventTime=6536876, downTime=6536811, deviceId=0, source=0x301 } I/System.out( 1098): BaseActivity calling: /login/maskedPassword onResponseData: {"response":{"state":"A","authenticated":true},"msgId":"1344674218830418930","errorCode":0,"time":1351588394408,"errorDesc":""}
LOGI SYSTEMOWE - SKUTKI
• Warunki wykorzystania trudne do spełnienia
• Kto może te logi czytać?
• Jak długo są przetrzymywane?
• Czy problem dotyczy tylko jednego feralnego builda?
• Czy problem występuje na wszystkich wersjach OS?
• Jakie dodatkowe warunki muszą być spełnione?
• Czy podatność została wykorzystana w praktyce?
• Ale to może nie mieć żadnego znaczenia w obliczu klęski
wizerunkowej – np. Starbucks, styczeń 2014
LOGI SYSTEMOWE - SKUTKI
DANE OFFLINE
• Pewne funkcje aplikacji (np. historia transakcji) działają również
offline. Aplikacja musi więc przechowywać lokalnie część danych
pobranych z serwera
• Aplikacja bankowości mobilnej, do uwierzytelnienia i autoryzacji
wymagany jest kod PIN
• Po 3-krotnym wprowadzeniu błędnego PIN-u dostęp do aplikacji
jest blokowany
• Dane te są trzymane w formie zaszyfrowanej, w prywatnym
katalogu dostępnym jedynie dla tej aplikacji. Do odszyfrowania
konieczne jest podanie PIN-u użytkownika
• Nie użyto stałego klucza zaszytego w aplikacji
SPOJRZENIE ATAKUJĄCEGO
• Aby uzyskać dostęp do danych potrzebujękodu PIN
• Załóżmy, że udało mu się przejąć pełnąkontrolę nad urządzeniem mobilnym(np. kradzież, malware...)
• Jednak nie może podsłuchać kodu PIN – nie ma możliwości kontroli nad urządzeniem w trakcie gdyużytkownik korzysta z bankowości
• Jak może uzyskać PIN?
BRUTE-FORCE OFFLINE
• Kod PIN jest używany również do odszyfrowania danych trzymanych lokalnie.
• Jest to funkcja, która działa bez połączenia do Internetu, więc kod PIN nie
może być zweryfikowany po stronie serwera.
• Nawet jeśli aplikacja się zablokuje po 3 nieudanych próbach, jest to proces
offline. Konto nie zablokuje się na serwerze, a intruz może odtworzyć stan
aplikacji sprzed zablokowania i próbować ponownie.
• Czyli - intruz może bez ograniczeń łamać kod PIN offline. Prawidłowy kod
pozna po tym, iż po rozszyfrowaniu uzyska sensowne dane.
• Nawet jeśli kod jest złożony (a w praktyce najczęściej to kilka cyfr), złamanie
zajmie mu maksymalnie kilka godzin.
JAK TO ZROBIĆ POPRAWNIE?
• Wszystkie próby użycia hasła (np. w celu uwierzytelnienialub autoryzacji) powinny być weryfikowane na serwerze, nie lokalnie na urządzeniu.
• Poprawne użycie kryptografii – uwaga na błędypozwalające na łamanie siłowe offline.
• Najlepiej nie przechowywać żadnych danych wrażliwych naurządzeniu, nawet w formie zaszyfrowanej
IPC – KOMUNIKACJA MIĘDZYPROCESOWA
• Podstawowe komponenty aplikacji Android:
• Widoki
• Dostawcy treści
• Serwisy
• Odbiorca komunikatów
• Wywołania wewnętrzene oraz zewnętrzne
• AndroidManifest.xml !
IPC – KOMUNIKACJA MIĘDZYPROCESOWA
<activity android:label="@7F050009" android:name=".PWList"android:exported="true" android:finishOnTaskLaunch="true"android:clearTaskOnLaunch="true"android:excludeFromRecents="true">
</activity>
• Fragment pliku AndroidManifest.xml definiujący widok PWList (lista zapisanych haseł)
IPC – KOMUNIKACJA MIĘDZYPROCESOWA
• # adb shell am start –n com.mwr.example.sieve.PWList
SSL (ang. secure socket layer)
• Protokół zapewniający poufność oraz integralność przesyłanych danych
• Kryptografia asymetryczna do wymiany klucza szyfrującego
• Zawartość transmisji jest szyfrowana przy użyciu
kryptografi symetrycznej
SSL (ang. secure socket layer)
MAN-IN-THE-MIDDLE
KONFIGURACJA SSL PO STRONIE SERWERA
• www.ssllabs.com
• OWASP Testing for TLS-SSL https://www.owasp.org/index.php/Testing_for_SSL-TLS_(OWASP-CM-001)
CERTIFICATE PINNING
• Walidacja w aplikacji czy serwer przedstawia się swoim certyfikatem
PRZECHWYTYWANIE RUCHU HTTP
• # emulator –avd emulator_name –http-proxy 127.0.0.1:8080
• Lokalne PROXY
• Burp
• Fiddler
• Charles PROXY
PRZECHWYTYWANIE RUCHU HTTP
• Pozostaje tylko dodać niezaufany certyfikat do trustsotra
na urządzeniu
1. Eksport certyfikatu
PRZECHWYTYWANIE RUCHU HTTP
2. Przeniesienie certyfikatu na urządzenie / emulator
# adb push burp.cer /storage/sdcard
3. Przeniesienie certyfikatu na urządzenie
Dodanie certyfikatu do zaufanych certyfikatów na urządzeniu
Ustawienie -> Zabezpieczenia -> Zainstaluj certyfikat z karty SD
PRZECHWYTYWANIE RUCHU HTTP
ANALIZA DYNAMICZNA
TESTY API PO STRONIE SERWERA
• Błędy kontroli dostępu
• Nieprawidłowa obsługa sesji
• Błędy uwierzytelnienia i autoryzacji
• Błędy logiczne
• SQL Injection
• i wiele, wiele innych….
KONTROLA DOSTĘPU
Jedna z aplikacji mobilnych realizujących płatności bezgotówkowych
1. Dostęp do aplikacji jest chroniony kodem PIN
2. W aplikacji można wybrać funkcjonalność „Zapłać kodem”
3. Serwer odsyła specjalny kod
4. Wprowadzenie kodu do terminalu płatniczego potwierdza dokonanie transakcji
KONTROLA DOSTĘPU
POST pay/generate_token HTTP/1.1
Host: acc
X-Client-Time: 1457090926000
(…)
{"session_id":"I000080Vz2WS3nPH5gmsYhiwMkyv8","customer_id":
„iAjU765cxVDOjauJrO0s7g","imsi":"CE0BC1B4-CC54-464C-A131-
74C25DFDDF5A"}
KONTROLA DOSTĘPU
POST pay/generate_token HTTP/1.1
Host: acc
X-Client-Time: 1457090926000
(…)
{"session_id":"","customer_id":„iAjU765cxVDOjauJrO0s7g","imsi":"CE0
BC1B4-CC54-464C-A131-74C25DFDDF5A"}
A co się stanie jeśli wyślemy pusty identyfikator sesji?
KONTROLA DOSTĘPU
HTTP/1.1 200 OK
Date: Fri, 04 Mar 2016 11:29:17 GMT
(...)
{„code": "12807521", „secret": "2e4dee5a-6d26-43d4-bcc2-
958485533a15", "expiration": "2016-03-04 12:30:46.023095"}
Serwer zwraca aktywny kod do płatności jedynie w oparciuo parametr customer_id = nie musimy znać PINu do
aplikacji, żeby dokonywać płatności
OBSŁUGA SESJI
GET /services/user/profile HTTP/1.1
SA-DeviceId: 940109f08ba56a89
SA-SessionId: 850075
Accept: application/json
Host: acc
Connection: Keep-Alive
User-Agent: Apache-HttpClient/UNAVAILABLE (java
1.4)
Jedna z bankowości mobilnych:
BŁĘDY LOGICZNE
Jeszcze jedna bankowość mobilna:
• Mobilna CAPTCHA
• Proces rejestracji konta, potwierdzany CAPTCHA oraz kodem SMS
• Należy kliknąć w odpowiedni obrazek (1 z 6)
BŁĘDY LOGICZNE
BŁĘDY LOGICZNE
• Bardzo wysokie prawdopodobieństwo trafienia „na ślepo”
• A w implementacji jeszcze gorzej
• Każdy obrazek to plik statyczny, który można zindeksować i zautomatyzować omijanie CAPTCHA
OWASP MOBILE TOP 10
KONIEC
Dziękuję,zapraszam do kontaktu