Testowanie bezpieczeństwa aplikacji mobilnych
Sławomir Jasek
Dzień dobry!
Pentester / konsultant bezpieczeństwa
Sławomir Jasek
Od 2003 roku:Ocena bezpieczeństwa aplikacji, systemów, sieci...Najskuteczniej pomagamy już od etapu projektowania.
Co będzie
● Spojrzenie pentestera (= intruza) na aplikacje mobilne
● Testowanie – na przykładach głównie Android
– Analiza paczki i kodu
– Dane zapisywane w urządzeniu i w logach
– RPC
– Transmisja
– API
● Podsumowanie
Aplikacja mobilna – spojrzenie intruza
RPC
SIEĆ
ZAPIS DANYCH
UŻYTKOWNIK
OS
Jak?Inna aplikacja na urządzeniu
Kradzież, zgubienie urządzenia, przypadkowy dostęp, inna aplikacja...
Podatności systemu
Social engineering,słabości użytkownikównp. słabe hasło, zbyt trudne mechanizmy
Ataki na transmisję -podsłuch, słabości SSL
API – błędy kontroli dostępu, logiczne, konfiguracji...
Analiza paczki
Kto?
„grubszy cwaniak”
„script-kiddie”
Krzysztof Jarzynaze Szczecina
Dorwał się do narzędzi,wali na oślep, zwykle niebardzo rozumiejąc co siędzieje.
Coś mu się przypadkiemudało (lub nie), i aferagotowa.
Ma motywację, zasobyoraz możliwościprzeprowadzenia atakunakierowanego
Po co?
● Jak to po co? Bo może!
● Dla sławy!
● Dla satysfakcji
● Dla pieniędzy
● Dla innych korzyści
● ...https://www.flickr.com/photos/viirok/2498157861
Paczka aplikacji
PLAY / STORE
Paczka aplikacji
● Android
– Aplikacje bez root
np. „My App Sharer”
– APK Leecher
– Playdrone – masowe
pobieranie do chmury
– (nie wspominając root)
● iOS, inne – DRM nie jest problemem
Rozpakowanie, dekompilacja...
Analiza kodu
● Do ataku jakiegoś procesu przydaje się rozumieć jak on działa
● Własna kryptografia, błędy implementacji...
● Hasła, klucze, tokeny zaszyte w aplikacji
Np. tokeny FB, Google, MS, Yahoo i Linkedin aplikacji Airb2b – 10 milionów użytkowników
http://viennot.com/playdrone.pdf
● Tak, znaleźliśmy token FB w aplikacji ;)
Przykład● Przesyłanie mailem danych do „bazy” –
● Założenie : wysyłamy bezpośrednio przez nasz serwer pocztowy – mail.pewnafirma.com, nie angażujemy kont użytkownika
● Serwer oczywiście nie jest open-relayem, do wysłania maila wymaga uwierzytelnienia
● Hasło zaszyte w aplikacji
● Co możemy zrobić? (oprócz wysyłania spamu)
To samo hasło do POP3 = dostęp do skrzynki!
Wytęż wzrok i znajdź klucz „szyfrujący”w zaobfuskowanym kodzie
public final class a
implements b
{
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;
}
}
}
Wytęż wzrok i znajdź klucz „szyfrujący”w zaobfuskowanym kodzie
public final class a
implements b
{
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”
Manifest, analiza uprawnień...
Dane zapisywane na urządzeniu
Kradzież, zgubienie urządzenia, przypadkowy dostęp, inna aplikacja...
Jak to sprawdzić
● Ręcznie: adb pull na różnych etapach pracy aplikacji
• Automaty, skrypty – np. wrzucanie do svn
Uprawnienia plików
Logi, cache...● Dość często zawierają pełne żądania HTTP,
wprowadzane klawisze – np. hasło użytkownika
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, cache...● Dość często zawierają pełne żądania HTTP,
wprowadzane klawisze – np. hasło użytkownikaI/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, cache – 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?
– ...
● Ale to może nie mieć żadnego znaczenia w obliczu klęski wizerunkowej – np. Starbucks, styczeń 2014
Logi, cache – 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?
– ...
● Ale to może nie mieć żadnego znaczenia w obliczu klęski wizerunkowej – np. Starbucks, styczeń 2014
Logi, cache – 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?
– ...
● Ale to może nie mieć żadnego znaczenia w obliczu klęski wizerunkowej – np. Starbucks, styczeń 2014
Logi, cache – 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?
– ...
● Ale to może nie mieć żadnego znaczenia w obliczu klęski wizerunkowej – np. Starbucks, styczeń 2014
Logi, cache – 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?
– ...
● Ale to może nie mieć żadnego znaczenia w obliczu klęski wizerunkowej – np. Starbucks, styczeń 2014
Logi, cache – 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?
– ...
● Ale to może nie mieć żadnego znaczenia w obliczu klęski wizerunkowej – np. Starbucks, styczeń 2014
Logi, cache – 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?
– ...
● Ale to może nie mieć żadnego znaczenia w obliczu klęski wizerunkowej – np. Starbucks, styczeń 2014
RPCInna aplikacja na urządzeniu
BAD INTENTions
<receiver android:name =“MojReceiver”>
<intent -filter>
<action android:name = "android.intent.action.PACKAGE_ADDED"
String action = intent.getAction();if (action...)
BAD INTENTions
<receiver android:name =“MojReceiver”>
<intent -filter>
<action android:name = "android.intent.action.PACKAGE_ADDED"
String action = intent.getAction();if (action...)
Intent intent = new Intent();intent.setComponent (“MojReceiver”); sendBroadcast(intent);
BAD INTENTions
<receiver android:name =“MojReceiver”>
<intent -filter>
<action android:name = "android.intent.action.PACKAGE_ADDED"
String action = intent.getAction();if (action...)
Intent intent = new Intent();intent.setComponent (“MojReceiver”); sendBroadcast(intent);
Nullpointer exceptionCRASH
BAD INTENTions
<receiver android:name =“MojReceiver”>
<intent -filter>
<action android:name = "android.intent.action.PACKAGE_ADDED"
String action = intent.getAction();if (action...)
Intent intent = new Intent();intent.setComponent (“MojReceiver”); sendBroadcast(intent);
String action = intent.getAction();if (action != null ){
if(action...)
Nullpointer exceptionCRASH
BAD INTENTions
<receiver android:name =“MojReceiver”>
<intent -filter>
<action android:name = "android.intent.action.PACKAGE_ADDED"
String action = intent.getAction();if (action != null) ){
Uid = intent.getStringExtra(“android.intent.extra.UID”);
BAD INTENTions
<receiver android:name =“MojReceiver”>
<intent -filter>
<action android:name = "android.intent.action.PACKAGE_ADDED"
String action = intent.getAction();if (action != null) ){
Uid = intent.getStringExtra(“android.intent.extra.UID”);
Intent intent = new Intent (“AKUKU”);intent.setComponent (“MojReceiver”); intent.putExtra (“android.intent.extra.UID”, attackerUID);sendBroadcast(intent);
BAD INTENTions
<receiver android:name =“MojReceiver”>
<intent -filter>
<action android:name = "android.intent.action.PACKAGE_ADDED"
String action = intent.getAction();if (action != null) ){
Uid = intent.getStringExtra(“android.intent.extra.UID”);
Intent intent = new Intent (“AKUKU”);intent.setComponent (“MojReceiver”); intent.putExtra (“android.intent.extra.UID”, attackerUID);sendBroadcast(intent);
String action = intent.getAction();if (action != null && action.equals (“PACKAGE_ADDED”) ){
Uid = intent.getStringExtra(“android.intent.extra.UID”);
BAD INTENTions<permission android:name ="com.dobreprogramy.permission"
android:protectionLevel = "signature" ...
<receiver android:name ="dobryReceiver" android:exported="true"
android:permission="com.dobreprogramy.permission">
...
</receiver>
BAD INTENTions<permission android:name ="com.dobreprogramy.permission"
android:protectionLevel = "signature" ...
<receiver android:name ="dobryReceiver" android:exported="true"
android:permission="com.dobreprogramy.permission">
...
</receiver>
<permission android:name ="com.dobreprogramy.permission" android:protectionLevel="normal" ...>
<uses-permission android:name ="com.dobreprogramy.permission"/>
Intruz może zarejestrować to samo wcześniej
Analiza/atak RPC
● Mnóstwo narzędzi
– Drozer https://www.mwrinfosecurity.com/products/drozer/
– Android Hooker, comdroid, chex, epicc, iSEC intent fuzzer/sniffer...
● Ręcznie
am broadcast -n com.aplikacja/com.aplikacja.BroadcastReceiver
am start -a android.intent.action.CALL -d tel://000-0000
Transmisja
Ataki na transmisję -podsłuch, słabości SSL
Intruz musi mieć dostęp do transmisji – pasywny (podsłuch), lub aktywny –aby modyfikować ruch
Przechwytywanie ruchu
● Local proxy – co się dzieje „na łączu” (np. żądania HTTP)
– Burp: wersja darmowa na początek wystarczy
portswigger.net/burp
– Fiddler – MS
www.telerik.com/fiddler
– wiele innych
● Emulator przez proxy:
emulator -avd emu -http-proxy 127.0.0.1:8080
www.telerik.com/fiddler/
SSL – wróćmy do podstaw
CA
Co zrobi klient?
● Jeśli ten sam certyfikat byłby podpisany innym CA?
[POWINIEN] wyświetlić ostrzeżenie, przerwać transmisję...
Zaakceptuje bez mrugnięcia.
CA nie jest w zaufanych
CA w zaufanych
Certyfikaty CA zaszyte w urządzeniach
● Ćwiczenie: sprawdź jakie CA masz w swoim telefonie
● Np. iOS8 ma m.in. certyfikaty rządów:
Chin: China Internet Network Information Center
Hong Kongu: Hongkong Post e-Cert.
Japonii: 3 CA
Holandii: 3 CA (PKIoverheid)
Taiwanu: Government Root Certification Authority
Turcji: Scientific and Technological Research Council of Turkey
USA: 5 CA, Department of Defense
SSL – „Man in the middle”
CA
?
Verisignwww.pewnafirma.pl
Verisignwww.pewnafirma.pl
Stosunkowo często...
sslcontext = SSLContext.getInstance("TLS");
atrustmanager = new TrustManager[1];
atrustmanager[0] = new EasyX509TrustManager(null);
sslcontext.init(null, atrustmanager, null);
Pusty TrustManager – akceptuje wszystkie certyfikaty
Przechwytywanie ruchu SSL
● Certyfikat CA Burp-a
Instalujemy w urządzeniu
● Aplikacja używa domyślnego truststore urządzenia
– Android > 4 – w interfejsie
– Wrzucamy na kartę SD (plik .crt)
adb push cacert.der /sdcard/cacert.crt
– „Zainstaluj z karty SD”
● Certyfikat zaszyty w aplikacji (pinning)
– Podmieniamy w paczce aplikacji
API
API – błędy kontroli dostępu, logiczne, konfiguracji...
Mobile CAPTCHA
● Proces rejestracji, potwierdzanej SMS
● CAPTCHA w celu ograniczenia masowego nadużycia procesu (koszty SMS, przeciążenie systemu...)
● Należy kliknąć w odpowiedni obrazek (1 z 6)
Mobile CAPTCHA
● Pomysł chybiony już w założeniach
– Prawdopodobieństwo trafienia „na ślepo” bardzo wysokie
● W implementacji jeszcze gorzej
– Każdy obrazek to inny statyczny plik, intruz może je zindeksować i ustalić w którym miejscu jest obrazek przedstawiający żądane słowo
REST API
fragment otrzymanej dokumentacji REST API
Historia rachunku
Żądanie HTTP po przechwyceniu
GET /services/history/account/85101022350445200448009906 HTTP/1.1
SA-DeviceId: 940109f08ba56a89
SA-SessionId: 826175
Accept: application/json
Host: acc
Connection: Keep-Alive
User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)
GET /services/history/account/45101022350445200448005388 HTTP/1.1
SA-DeviceId: 940109f08ba56a89
SA-SessionId: 826175
Accept: application/json
Host: acc
Connection: Keep-Alive
User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)
Podmiana nr rachunku – uzyskujemy cudze dane
Dane użytkownika
Użytkownik 1
GET /services/user/profile HTTP/1.1
SA-DeviceId: d4c79a0fd994b1f8
SA-SessionId: 850071
Accept: application/json
Host: acc
Connection: Keep-Alive
User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)
Dane użytkownika
Użytkownik 1
GET /services/user/profile HTTP/1.1
SA-DeviceId: d4c79a0fd994b1f8
SA-SessionId: 850071
Accept: application/json
Host: acc
Connection: Keep-Alive
User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)
Użytkownik 2
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)
DeviceId jedynym zabezpieczeniem
Historia pewnej aplikacji...
● Mnóstwo błędów kontroli dostępu
● Po zgłoszeniu dostawcy:
„Kontrola dostępu w aplikacji jest, tylko na testowym środowisku wyłączona”
● Pomimo napiętych terminów włączyć się udało dopiero po kilku tygodniach ;)
Przechwytywanie ruchu – utrudnienie
Prawdopodobnie powstrzyma przypadkowych...
http://www.recreateweb.com.au/web-development/respond-2014-what-responsive-web-design-can-learn-from-accessibility-best-practice/
...oraz masowych intruzów
http://www.recreateweb.com.au/web-development/respond-2014-what-responsive-web-design-can-learn-from-accessibility-best-practice/
A Was?
#1 – żeby coś zaatakować trzeba zrozumieć jak to działa
https://www.flickr.com/photos/itspaulkelly/633298765
Zaszyfrowany ruch
Jak się dobrać do transmisji?
KLUCZ PUBLICZNY
LOSOWYKLUCZ SESJI
SESYJNY DO SERWERA
TRANSMISJA ZASZYFROWANA KLUCZEM SESJI
Drobne usprawnienie aplikacji – stały klucz w SMALI
new-array v8, v8, [B
fill-array-data v8, :array_5a
return-object v8
:array_5a
.array-data 1
0x44t
0x2bt
0x72t
(...)
Burp extension
Burp extension
Burp Extension
Burp Extension
Burp Extension
Architektura, środowisko
Znane podatności
Konsole administracyjne
Konsole administracyjne
Niektóre schwytane problemy REST
● Błędy kontroli dostępu
● Nieprawidłowa obsługa sesji
● Błędy uwierzytelnienia i
autoryzacji
● Błędy logiczne
● SQL injection
● Błędy architektury/konfiguracji
● ...
https://www.flickr.com/photos/elycefeliz/6648603999
Część z ryzyk do ogarnięcia
OWASP Mobile Top 10
Czekamy na Was!
Darmowe konsultacje:
www.securing.pl/konsultacje
Pracuj z nami:http://www.securing.pl/pl/kariera.html
Top Related