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

I just hacked your app - TakeOff 2016

I just hacked your app - TakeOff 2016

Android security is nowhere near where it should be. I have been able to hack and get sensitive information from a few different apps and I’m just an amateur hacker at best.

In this session we will explore a number of ways an Android app can be exploited and most importantly methods that we can use to avoid these attacks.

Marcos Placona

October 20, 2016
Tweet

More Decks by Marcos Placona

Other Decks in Programming

Transcript

  1. I just hacked
    your app

    View Slide

  2. View Slide

  3. PWNED

    View Slide

  4. Marcos Placona
    @marcos_placona
    placona.co.uk
    [email protected]

    View Slide

  5. NOT

    View Slide

  6. View Slide

  7. View Slide

  8. View Slide

  9. View Slide

  10. Kuba Gretzki
    http://bit.ly/hack4beer

    View Slide

  11. loyalty
    \ˈlȯi(-ə)l-tē\

    View Slide

  12. loyalty
    + =

    View Slide

  13. loyalty
    HTTP Proxy

    View Slide

  14. POST /users/461845f5d03e6c052a43afbc/points
    Accept: application/json
    Accept-Language: en-gb
    X-App-Version: 1.28.0
    User-Agent: Dalvik/2.1.0 (Linux; U; Android 6.0.1;)
    ...
    Content-Type: application/json; charset=UTF-8
    Content-Length: 375
    Host: api.eatapp.com
    Connection: Keep-Alive
    Accept-Encoding: gzip
    {
    "authentication_token":"boKUp9vBHNAJp7XbWZCK",
    "latitude":...,
    "longitude":...,
    "point":{
    "isDoneByGesture":false,
    "main_beacon":{
    "major":38995,
    "minor":12702,
    "uuid":"2C75E74B-41B7-49E3-BD26-CE86B2F569F8"
    },
    "place_id":"450",
    "promoted_products_ids":[
    {"id":"647035946536601578040000"},
    {"id":"647035946536601578040000"},
    {"id":"647035946536601578050000"}
    ]
    }
    }

    View Slide

  15. POST /users/461845f5d03e6c052a43afbc/points
    Accept: application/json
    Accept-Language: en-gb
    X-App-Version: 1.28.0
    User-Agent: Dalvik/2.1.0 (Linux; U; Android 6.0.1;)
    ...
    Content-Type: application/json; charset=UTF-8
    Content-Length: 375
    Host: api.eatapp.com
    Connection: Keep-Alive
    Accept-Encoding: gzip
    {
    "authentication_token":"boKUp9vBHNAJp7XbWZCK",
    "latitude":...,
    "longitude":...,
    "point":{
    "isDoneByGesture":false,
    "main_beacon":{
    "major":38995,
    "minor":12702,
    "uuid":"2C75E74B-41B7-49E3-BD26-CE86B2F569F8"
    },
    "place_id":"450",
    "promoted_products_ids":[
    {"id":"647035946536601578040000"},
    {"id":"647035946536601578040000"},
    {"id":"647035946536601578050000"}
    ]
    }
    }

    View Slide

  16. POST /users/461845f5d03e6c052a43afbc/points
    Accept: application/json
    Accept-Language: en-gb
    X-App-Version: 1.28.0
    User-Agent: Dalvik/2.1.0 (Linux; U; Android 6.0.1;)
    ...
    Content-Type: application/json; charset=UTF-8
    Content-Length: 375
    Host: api.eatapp.com
    Connection: Keep-Alive
    Accept-Encoding: gzip
    {
    "authentication_token":"boKUp9vBHNAJp7XbWZCK",
    "latitude":...,
    "longitude":...,
    "point":{
    "isDoneByGesture":false,
    "main_beacon":{
    "major":38995,
    "minor":12702,
    "uuid":"2C75E74B-41B7-49E3-BD26-CE86B2F569F8"
    },
    "place_id":"450",
    "promoted_products_ids":[
    {"id":"647035946536601578040000"},
    {"id":"647035946536601578040000"},
    {"id":"647035946536601578050000"}
    ]
    }
    }

    View Slide

  17. View Slide

  18. View Slide

  19. stop!

    View Slide

  20. • Encrypt all the values
    • Utilise security features when they exist
    • Certificate pinning
    • DO NOT TRUST THE DEVICE

    View Slide

  21. // Sending side
    byte[] data = text.getBytes("UTF-8");
    String base64 = Base64.encodeToString(data, Base64.DEFAULT);
    // Receiving side
    byte[] data = Base64.decode(base64, Base64.DEFAULT);
    String text = new String(data, "UTF-8");
    Encrypt all the values

    View Slide

  22. Your keys will end up in GitHub

    View Slide

  23. • Encrypt all the values
    • Utilise security features when they exist
    • Certificate pinning
    • DO NOT TRUST THE DEVICE

    View Slide

  24. Utilise security features when they exist

    View Slide

  25. • Encrypt all the values
    • Utilise security features when they exist
    • Certificate pinning
    • DO NOT TRUST THE DEVICE

    View Slide

  26. public class KeyPinStore {
    private static KeyPinStore instance = null;
    private SSLContext sslContext = SSLContext.getInstance("TLS");
    public static synchronized KeyPinStore getInstance() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException{
    if (instance == null){
    instance = new KeyPinStore();
    }
    return instance;
    }
    private KeyPinStore() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException{
    // Load CAs from an InputStream
    // (could be from a resource or ByteArrayInputStream or ...)
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    // randomCA.crt should be in the Assets directory
    InputStream caInput = new BufferedInputStream(MainActivity.context.getAssets().open("randomCA.crt"));
    Certificate ca;
    try {
    ca = cf.generateCertificate(caInput);
    System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
    } finally {
    caInput.close();
    }
    // Create a KeyStore containing our trusted CAs
    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);
    // Create a TrustManager that trusts the CAs in our KeyStore
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);
    // Create an SSLContext that uses our TrustManager
    // SSLContext context = SSLContext.getInstance("TLS");
    sslContext.init(null, tmf.getTrustManagers(), null);
    }
    public SSLContext getContext(){
    return sslContext;
    }
    }
    Certificate pinning
    https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#Android

    View Slide

  27. • Encrypt all the values
    • Utilise security features when they exist
    • Certificate pinning
    • DO NOT TRUST THE DEVICE

    View Slide

  28. Someone will decompile your app

    View Slide

  29. And when they do…

    View Slide

  30. –Every Developer
    “But I need magic strings”

    View Slide

  31. Options
    • Make sure you encrypt them
    • Protect them with tools like DexGuard and
    ProGuard
    • Get them off a server
    http://bit.ly/SafeKey

    View Slide

  32. start!

    View Slide

  33. Tampering detection
    // myPackageName should decode at runtime to "com.yourpackagename"
    // google should decode at runtime to "com.android.vending";
    // amazon should decode at runtime to "com.amazon.venezia";
    public boolean isHacked(Context context, String myPackageName, String google, String amazon)
    {
    //Crooks renamed your app?
    if (context.getPackageName().compareTo(myPackageName != 0)
    return true; // BOOM!
    //Rogues relocated your app?
    String installer = context.getPackageManager().getInstallerPackageName(myPackageName);
    if (installer == null)
    return true; // BOOM!
    if (installer.compareTo(google) != 0 && installer.compareTo(amazon) != 0)
    return true; // BOOM!
    return false;
    }
    http://bit.ly/isHacked

    View Slide

  34. Tampering detection
    // myPackageName should decode at runtime to "com.yourpackagename"
    // google should decode at runtime to "com.android.vending";
    // amazon should decode at runtime to "com.amazon.venezia";
    public boolean isHacked(Context context, String myPackageName, String google, String amazon)
    {
    //Crooks renamed your app?
    if (context.getPackageName().compareTo(myPackageName != 0)
    return true; // BOOM!
    //Rogues relocated your app?
    String installer = context.getPackageManager().getInstallerPackageName(myPackageName);
    if (installer == null)
    return true; // BOOM!
    if (installer.compareTo(google) != 0 && installer.compareTo(amazon) != 0)
    return true; // BOOM!
    return false;
    }
    http://bit.ly/isHacked

    View Slide

  35. • Check your app’s signature
    • Check for rooted device
    • Check for emulator
    • Check if the app is debuggable

    View Slide

  36. private static final int VALID = 0;
    private static final int INVALID = 1;
    private static final String APP_SIGNATURE = "1038C0E34658923C4192E61B16846";
    public static int checkAppSignature(Context context) {
    try {
    PackageInfo packageInfo = context.getPackageManager()
    .getPackageInfo(context.getPackageName(),
    PackageManager.GET_SIGNATURES);
    for (Signature signature : packageInfo.signatures) {
    byte[] signatureBytes = signature.toByteArray();
    MessageDigest md = MessageDigest.getInstance("SHA");
    md.update(signature.toByteArray());
    //compare signatures
    if (SIGNATURE.equals(APP_SIGNATURE)){
    return VALID;
    };
    }
    } catch (Exception e) {
    //assumes an issue in checking signature., but we let the caller decide on what to do.
    }
    return INVALID;
    }
    Check your app’s signature
    http://bit.ly/AndroidTampering

    View Slide

  37. • Check your app’s signature
    • Check for rooted device
    • Check for emulator
    • Check if the app is debuggable

    View Slide

  38. private static boolean canExecuteCommand(String command) {
    try {
    int exitValue =
    Runtime.getRuntime().exec(command).waitFor();
    if (exitValue != 0) return false;
    else return true;
    } catch (Exception e) {
    return false;
    }
    }
    Check for rooted device

    View Slide

  39. • Check your app’s signature
    • Check for rooted device
    • Check for emulator
    • Check if the app is debuggable

    View Slide

  40. Build.FINGERPRINT.startsWith("generic")
    Check for emulator

    View Slide

  41. • Check your app’s signature
    • Check for rooted device
    • Check for emulator
    • Check if the app is debuggable

    View Slide

  42. public static boolean isDebuggable(Context context){
    return (context.getApplicationInfo().flags &
    ApplicationInfo.FLAG_DEBUGGABLE) != 0;
    }
    Check if the app is debuggable

    View Slide

  43. Debuggable app

    View Slide

  44. View Slide

  45. View Slide

  46. Marcos Placona
    @marcos_placona
    placona.co.uk
    [email protected]
    Thanks

    View Slide