Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Актуальные вопросы безопасности Android-приложений

Актуальные вопросы безопасности Android-приложений

Доклад Дмитрия Терешина (Tinkoff) для PDUG-секции на форуме PHDays 9.

Transcript

  1. Заголовок ptsecurity.com Pressing security issues of Android applications Tinkoff Терёшин

    Дмитрий
  2. Заголовок 2 • Bad design • Need to support old

    Android versions • Incorrect use of Android API Reasons
  3. Заголовок 3 • Auth sharing • SSL pinning • Token

    encryption • Android wear • Push notifications Agenda
  4. Заголовок Auth sharing 4

  5. Заголовок 5 • 2 Android applications (master, slave) • common

    API • API access token Objective: seamless transition between applications Objective
  6. Заголовок 6 Variant 1: DeepLinks slave://main?sessionId=686A885A4FB644053C584B9BE2A70C7D Problem 1: DeepLink Hijacking

  7. Заголовок 7 • AppLinks – based on your website HTTP

    URL that has been verified to belong to your website Problem: need Android 6.0+ • Intent URL – add application id intent://main/#Intent;scheme=slave;package=com.example.slave.clie nt.android;end” Problem: application id forgering Problem 1: How to resolve
  8. Заголовок 8 Mistake 1: Session Fixation

  9. Заголовок 9 Variant 2: Content Provider Problem 2: unprotected provider

  10. Заголовок 10 Protection Level <permission android:name="com.example.contentprovider.access" android:protectionLevel="signature"/> <application> <provider ...

    android:readPermission="com.example.contentprovider.access"> </application> Problem 3: Permission forgering
  11. Заголовок 11 Problem 4: Different Signatures String pkg = this.getCallingPackage();

    PackageInfo pkgInfo = pkgmgr.getPackageInfo(pkg, GET_SIGNATURES); Signatures[] signatures = pkgInfo.signatures; for (Signature sig: signatures) { if (sig.equals(TRUSTED_SIGNATURE)) { // trusted signature found, trust the application } }
  12. Заголовок 12 Variant 3: Content Provider with signature checks

  13. Заголовок 13 Problem 4: Fake id vulnerability How to resolve:

    up minSDKLevel to 19 (Android 4.4)
  14. Заголовок SSL pinning 14

  15. Заголовок 15 • Rogue CAs • Compromised certificates • Phished

    users Goal Note: added in Android 7.0+ (Network Security Configuration) Protection against certificate forgery:
  16. Заголовок 16 X509TrustManager and HostnameVerifier customtrustManager = new X509TrustManager() {

    @Override public void checkClientTrusted(final X509Certificate[] chain, final String authType) { } @Override public void checkServerTrusted(final X509Certificate[] chain, final String authType) {} @Override public X509Certificate[] getAcceptedIssuers() {} }; HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) {} });
  17. Заголовок 17 Mistake 1: custom trust manager private static class

    X509CertPinningTrustManager implements X509TrustManager { public void checkServerTrusted(X509Certificate[] chain, String authType) throwsCertificateException List pinsInfo = AppConfig.getPinningInfo(); boolean validCertFound = false; for (pinnedCert: pinsInfo) { byte[] serverCertFingerprint = digest(chain[pinnedCert.chainPosition]); if (java.util.Arrays.equals(serverCertFingerprint, pinnedCert.fingerprint)){ validCertFound = true; break; } } if (!validCertFound) { throw new CertificateException("Invalid X509Cert used");} }
  18. Заголовок 18 Mistake 1: custom trust manager CVE-2016-2402: OkHttp before

    2.7.4 and 3.x before 3.1.2 allows man-in- the-middle attackers to bypass certificate pinning
  19. Заголовок 19 Mistake 1: attack mitmproxy --set add_upstream_certs_to_client_chain=true --set ssl_insecure=true

  20. Заголовок 20 Mistake 2: custom hostname verifier HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

    public boolean verify(String hostname, SSLSession session) { return hostname.equals("www.bank.com"); } }); Pin intermediate certificate &
  21. Заголовок 21 Mistake 2: attack https://github.com/ChrisMcMStone/Spinner

  22. Заголовок 22 • How to support low levels API •

    What exactly pin • How to deploy • Rotate certificate or public key • Pin failures Decisions
  23. Заголовок 23 create pin-server Good implementation use internal CA pinning

    for pin-server request pins from pin-server establish connection
  24. Заголовок Token encryption 24

  25. Заголовок 25 • Send pin-code & RefreshToken to server •

    Local auth by pin-code, send RefreshToken to server • Encrypt RefreshToken with pin-code Mistakes
  26. Заголовок 26 Objective RefreshToken: aec27f0f-b8a3-43cb-b076-e075a095abfe Cipher Suite: AES/CBC/PKCS5Padding PIN: 1234

    Note: avoid local validation of decryption result
  27. Заголовок 27 Problem 1: padding 01 02 02 03 03

    03 04 04 04 04 05 05 05 05 05 06 06 06 06 06 06 … … | 61 62 66 65 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C | For our token:
  28. Заголовок 28 Problem 2: predictable token format aec27f0f-b8a3-43cb-b076-e075a095abfe xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

  29. Заголовок 29 Token Format public String createRefreshToken() { byte[] refreshToken

    = new byte[64]; final SecureRandom secureRandom = new SecureRandom(); secureRandom.nextBytes(refreshToken); return Base64.getUrlEncoder() .withoutPadding().encodeToString(refreshToken); }
  30. Заголовок 30 Encryption Algorithm private static final String ALGORITHM =

    "AES"; private static final String CIPHER_SUITE = "AES/CBC/NoPadding"; private static final int AES_KEY_SIZE = 16; public byte[] encryptToken(String token, String pin, byte[] iv, byte[] salt) { byte[] decodedToken = decodeToken(token); byte[] rawPin = pin.getBytes(); byte[] key = kdf.deriveKey(rawPin, salt, AES_KEY_SIZE); Cipher cipher = Cipher.getInstance(CIPHER_SUITE); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, ALGORITHM), new IvParameterSpec(iv)); return cipher.doFinal(decodedToken); }
  31. Заголовок Android wear 31

  32. Заголовок 32 Communication between watch and phone Wearable.MessageApi.sendMessage(mGoogleApiClient, nodeId, COMMAND_APP_LAUNCH,

    new byte[3] ); <service android:name="WearableListenerService" android:exported="true"> <intent-filter> <action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED"/> <data android:scheme="wear" android:host="*" android:path="/COMMAND_APP_LAUNCH"/> </intent-filter> </service>
  33. Заголовок 33 Problem 1: Bluetooth HCI snoop log /etc/bluetooth/bt_stack.conf: all

    bluetooth data is written to /sdcard/btsnoop_hci.log (Android < 8)
  34. Заголовок 34 Problem 1: how to resolve try { Log.d("Bluetooth

    log", String.valueOf( Settings.Secure.getInt(getContentResolver(), "bluetooth_hci_log"))); } catch (Settings.SettingNotFoundException e) { e.printStackTrace(); }
  35. Заголовок 35 Mistake 1: hijacking in WearableListenerService public class MyWearableListenerService

    extends WearableListenerService { private static final String COMMAND_APP_LAUNCH = "/COMMAND_APP_LAUNCH"; @Override public void onMessageReceived(MessageEvent messageEvent) { if (messageEvent.getPath().equals(COMMAND_APP_LAUNCH)) { Intent intent = WearSplashActivity.newIntent(this); intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } } }
  36. Заголовок 36 Mistake 1: How to resolve public class MyWearableListenerService

    extends WearableListenerService { private static final String COMMAND_APP_LAUNCH = "/COMMAND_APP_LAUNCH"; @Override public void onMessageReceived(MessageEvent messageEvent) { if (messageEvent.getPath().equals(COMMAND_APP_LAUNCH)) { Intent intent = WearSplashActivity.newIntent(this); intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(intent); } } }
  37. Заголовок Push notifications 37

  38. Заголовок 38 Message receiving public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override public void onMessageReceived(RemoteMessage remoteMessage) { sendNotification(remoteMessage.getNotification().getBody()); } private void sendNotification(String messageBody) { NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId) .setSmallIcon(R.drawable.logo_22) .setColor(getResources().getColor(R.color.logo_green)) .setContentTitle(“Пополнение. Счет RUB…“) .setContentText(messageBody) .setAutoCancel(true) .setSound(defaultSoundUri); } }
  39. Заголовок 39 Problem 1: notification forgering How to resolve: сreate

    unique UI fingerprint for application instance
  40. Заголовок 40 • move to iOS • move to Fuchsia

    • move to the dark side • use Android API safely Conclusions
  41. Заголовок 41 Links & contacts dm.teryoshin@gmail.com @dtereshin

  42. Заголовок ptsecurity.com Спасибо! Спасибо!