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

RAUG S02E04 - Outils et bonnes pratiques de développement d'applications Android sécurisées

RAUG S02E04 - Outils et bonnes pratiques de développement d'applications Android sécurisées

A quick tour on common tools and best practices for secured Android app development

Alain Muller

June 05, 2018
Tweet

More Decks by Alain Muller

Other Decks in Technology

Transcript

  1. Outils et bonnes SORTEZ COUVERTS ! pratiques de développement Android

    d’applications sécurisées @psyckoz Alain Muller
  2. SÉCURITÉ = PROTECTION ▸ Propriété Intellectuelle Code Source ▸ Données

    utilisateur Stockage interne ▸ Backend Communication serveur
  3. “ The Attack Surface describes all of the different points

    where an attacker could get into a system, and where they could get data out. [owasp.org]
  4. “ Obfuscation is the obscuring of the intended meaning of

    communication by making the message difficult to understand, usually with confusing and ambiguous language. [wikipedia]
  5. DÉMO STEP 0 : values/strings.xml STEP 1 : hardcoded constant

    STEP 2 : enable Proguard Projet : Jancsoro/SimpleWeatherApp Place your screenshot here
  6. NetworkService.kt package com.designhumanist.faragojanos.weaterforecast.nework companion object Factory { fun create(context: Context)

    = NetworkService(context) // Load native library init { System.loadLibrary("native-lib") } } // Link to native function private external fun invokeNativeFunction(): String native-lib.cpp #include <jni.h> extern "C" { JNIEXPORT jstring JNICALL Java_com_designhumanist_faragojanos_weaterforecast_nework_NetworkService _invokeNativeFunction(JNIEnv *env, jobject instance) { return env->NewStringUTF("d2af3044bfa40b5bd5ff40cf8ee8034c"); } }
  7. CMakeLists.txt cmake_minimum_required(VERSION 3.4.1) add_library( # Specifies the name of the

    library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). main/cpp/native-lib.cpp )
  8. SharedPreferences = XML Lisible Émulateur : possibilité d’accéder en root

    à la mémoire interne! The common location where SharedPreferences are stored in Android apps is: /data/data/<package name>/shared_prefs/<filename.xml>
  9. $ adb root restarting adbd as root $ adb shell

    generic_x86_64:/ # cat /data/data/com.designhumanist.faragojanos.weaterforecast/ shared_prefs/WeatherForecast.xml <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <map> <string name="LOGIN">alain</string> <string name="PASS">plop</string> </map> private fun saveCredentials(login: String, pass: String) { val sharedPreferences = getSharedPreferences("WeatherForecast", Context.MODE_PRIVATE) val editor = sharedPreferences.edit() editor.putString("LOGIN", login) editor.putString("PASS", pass) editor.apply() }
  10. generic_x86_64:/ # cat /data/data/com.designhumanist.faragojanos.weaterforecast/shared_prefs/Hawk2.xml <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <map>

    <string name="PASS"> java.lang.String##0V@AQJRCdjCn9HHTNtXdFoW49XSTO9Kk4a0+qnGCLz+xwMXzzu2 </string> <string name="LOGIN"> java.lang.String##0V@AQL7/rang0Ww4RSIrBZZ8TK9md9bAgd5bKiK0S0KHKyTQGS/NA== </string> </map> private fun saveCredentials(login: String, pass: String){ Hawk.init(this).build() Hawk.put("LOGIN", login) Hawk.put("PASS", pass) }
  11. Stockage interne = Exploitable! Même sur device non rooté! Carte

    SD -> n’en parlons même pas! DÉMO STEP 8 : Add realm encryption adb backup com.designhumanist.faragojanos.weaterforecast java -jar ../android-backup-extractor/build/libs/abe-all.jar unpack backup.ab backup.tar tar -xvf backup.tar open apps/com.designhumanist.faragojanos.weaterforecast/f/ WeatherForecast.realm
  12. “ The man-in-the middle attack intercepts a communication between two

    systems. Once the TCP connection is intercepted, the attacker acts as a proxy, being able to read, insert and modify the data in the intercepted communication. [owasp.org]
  13. “ Certificate Pinning is the process of associating a host

    with their expected X509 certificate. Once a certificate is known or seen for a host, the certificate is associated or 'pinned' to the host. [owasp.org] Warning: Certificate Pinning is Dangerous! Do not use certificate pinning without the blessing of your server's TLS administrator! [square]
  14. companion object Factory { private val HOSTNAME = "api.openweathermap.org" private

    val BASE_URL = "https://$HOSTNAME/data/2.5/" fun create(): WeatherApiService { val okHttpClient = OkHttpClient.Builder() .addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY }) .certificatePinner(CertificatePinner.Builder() .add(HOSTNAME, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") .build()) .build() return Retrofit.Builder() .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .baseUrl(BASE_URL) .client(okHttpClient) .build() .create(WeatherApiService::class.java) } } .certificatePinner(CertificatePinner.Builder() .add(HOSTNAME, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") .build()) .client(okHttpClient)
  15. --> GET https://api.openweathermap.org/data/2.5/weather?q=paris&units=metric&APPID=ade0c9f95 63238c309e0bbf92c5075ec --> END GET <-- HTTP FAILED:

    javax.net.ssl.SSLPeerUnverifiedException: Certificate pinning failure! Peer certificate chain: sha256/0yOBPqOzhyp7U/418MLiLzURUneGendsdgs9G2+I2CA=: CN=*.openweathermap.org,OU=EssentialSSL Wildcard,OU=Domain Control Validated sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=: CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=: CN=COMODO RSA Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB Pinned certificates for api.openweathermap.org: sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  16. “ Anti-tamper software (or tamper- resistant software) is software which

    makes it harder for an attacker to modify it. [wikipedia]
  17. Qu’est ce que le tampering / debugging / instrumentation ->

    https://www.androidsecurity.info/tampering-detection-in-android/ Outils de détection : • RootTools -> https://github.com/Stericson/RootTools beaucoup d’outils, overkill pour juste détecter le root • Code natif -> https://stackoverflow.com/a/37237473/5664885 fail le RootCloak • SafetyNet API -> https://stackoverflow.com/a/45363495/5664885 Made by Google, validation côté serveur… • Crashlytics -> https://stackoverflow.com/a/35628977/5664885 Solution simple et efficace TODO
  18. BONUS Parcourir les diff d’un code source pour trouver les

    éventuelles clé d’API qui auraient été ensuite supprimées : git log -S<expression>
  19. commit ccaaf0aafa4975b0cbd9fc93e9bf63c04e9c2658 (tag: STEP1) Author: Alain Muller <[email protected]> Date: Tue

    May 29 11:42:13 2018 +0200 Remove API_KEY from XML res diff app/src/main/java/com/designhumanist/faragojanos/weaterforecast/nework/Netwo rkService.kt ... class NetworkService(private val context: Context) { + val API_KEY = "d2af3044bfa40b5bd5ff40cf8ee8034c" val DAYS: Int = 4 fun getWeather(city: String): Single<CurrentWeather> { return WeatherApiService.create().getCurrentWeather(city, context.getString(R.string.metric), - context.getString(R.string.APIKEY)) + API_KEY) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .toSingle() ... diff app/src/main/res/values/strings.xml <resources> <string name="app_name">WeaterForecast</string> - <string name="APIKEY">d2af3044bfa40b5bd5ff40cf8ee8034c</string> <string name="metric">metric</string>