Guida Android Application Penetration Testing - Reversing & Static Analysis

Reversing & Static Analysis - Guida

0xbro

Moderatore
24 Febbraio 2017
3,953
151
2,881
1,525
Ultima modifica:
Guida dedicata alle tecniche di base per il reverse engineering e l'analisi statica delle applicazioni mobile su dispositivi Android.​

android_pentesting.png

Android Application Penetration Testing - Reversing & Static Analysis​

Tempo di lettura stimato: 13 min​








1    Discussioni correlate


2    Introduzione

Come accennato nella discussione relativa ai concetti di base dell'application penetration testing su dispositivi mobile, durante tale attività non è solo fondamentale incentrarsi sulla sicurezza dei dati dell'app ("data in motion" e "data at rest"), ma anche sulla sicurezza e qualità del codice sorgente e delle relative configurazioni.

Per identificare queste falle è necessario ricorrere alla Static Analysis (SAST), ma anche e soprattutto al Reversing delle applicazioni di cui non si dispone quasi mai del codice sorgente "originale" ma solo del rispettivo file APK - che dovrà quindi prima venir scompattato e, successivamente, de-compilato in pseudo-codice Java.
Durante il processo di SAST inoltre l'applicazione non viene installata sul device ma è invece analizzata in locale.

I principali compiti della SAST possono quindi essere suddivisi in:​
  • Reverse Engineering (se necessario)​
  • Analisi del codice sorgente​
  • Analisi delle impostazioni di sicurezza​
  • Ricerca di pattern di codice insicuro o vulnerabile​
  • Analisi dell'archivhiazione dei dati sulla memoria fisica del device​

3    Reverse Engineering di un APK

Il Reverse Engineering è il processo per convertire un'applicazione compilata in codice sorgente leggibile dall'uomo. Di solito tale processo viene eseguito per identificare e comprendere le funzionalità interne dell'applicazione e per cercare vulnerabilità in essa, però il reversing è utile anche al fine di patchare l'APK da eventuali implementazioni di sicurezza, rendendo quindi più facile la successiva analisi dinamica.

I principali steps per reversare con successo un'applicazione Android sono i seguenti:​
  • Ottenere l'APK dell'applicazione​
  • Ottenere il file .dex dall'archivio .apk​
  • Convertire il file .dex in un file .jar​
  • Decompilare il file .jar ed analizzarne il contenuto​

3.1    Ottenere l'APK dell'applicazione

Per ottenere l'APK interessata esistono diversi modi e posti in cui guardare.
  • Se si tratta di un'applicazione ancora in beta/in sviluppo l'unico modo e farsi passare il file dagli sviluppatori
  • Se l'applicazione è già stata installata sul device è possibile recuperare il file APK tramite adb all'interno del path /data/app o /data/app-private (il device deve avere i privilegi di root)
  • Se l'app è stata installata ma non si posseggono i privilegi di root è possibile usare dei tools come Chrome APK Packager
  • Utilizzare le Android Market API

3.2    Ottenere il file .dex

Ricordiamo che un APK non è nient'altro che un archivio, firmato, composto da diversi file, per cui può essere tranquillamente scompattato e disassemblato in modo tale da leggerne il contenuto.

RSXD3ue.png

Per fare ciò possiamo utilizzare APKTool, uno strumento creato apposta per estrarre da un Android Package tutte le risorse che lo compongono o per assemblare un APK partendo da una cartella di risorse.
Bash:
# Disassembling an APK into its different pieces
$ apktool d test.apk
I: Using Apktool 2.6.1 on test.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: 1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...

# Assembling all the files into an APK
$ apktool b test
I: Using Apktool 2.6.1 on test
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether resources has changed...
I: Building resources...
I: Building apk file...
I: Copying unknown files/dir...

Così facendo possiamo estrarre dall'APK tutti i principali file, tra cui l' AndroidManifest.xml, il codice sorgente in formato smali (il corrispettivo di Assembly per Android) e tutte le risorse che compongono l'applicazione finale.

Tra i file estratti da apktool però non è presente il file classes.dex (formato Dalvik Executable) poichè è già stato disassemblato nei rispettivi file smali. Per recuperarlo è sia possibile assemblare nuovamente i file oppure, molto più facilmente, scompattare una copia dell'APK originale tramite unzip ed estrarre da qui il file classes.dex.
Bash:
$ unzip APKrypt.apk
Archive:  APKrypt.apk
  inflating: META-INF/MANIFEST.MF
  inflating: META-INF/JOHN.SF
  inflating: META-INF/JOHN.DSA
...
$ ls
AndroidManifest.xml  APKrypt.apk  classes.dex  META-INF  res  resources.arsc

3.3    Decompilare il file .dex in un file .jar

Questa fase è fondamentale per riuscire ad ottenere del codice facilmente leggibile rispetto al complicato .smali.
1*lH0ViR8YZ1l-G5nZEJMi0A.png

Per decompilare un file .dex in un file .jar esistono diversi tools e decompilatori che possono essere interscambiati tra loro (i cui risultati variano gli uni dagli altri), tra cui i seguenti:​

3.3.1    jadx

jadx è un tool da riga di comando che permette di generare del codice Java partendo da diverse estensioni di file, tra cui .dex, .apk o .zip. Permette di decompilare anche l'AndroidManifest.xml e di de-offuscare i codici sorgente.​

Codice:
jadx[-gui] [options] <input files> (.apk, .dex, .jar, .class, .smali, .zip, .aar, .arsc, .aab)
options:
  -d, --output-dir                    - output directory
  -ds, --output-dir-src               - output directory for sources
  -dr, --output-dir-res               - output directory for resources
  -r, --no-res                        - do not decode resources
  -s, --no-src                        - do not decompile source code
  --single-class                      - decompile a single class, full name, raw or alias
  --single-class-output               - file or dir for write if decompile a single class
  --output-format                     - can be 'java' or 'json', default: java
  -e, --export-gradle                 - save as android gradle project
  -j, --threads-count                 - processing threads count, default: 4
  --show-bad-code                     - show inconsistent code (incorrectly decompiled)
  --no-imports                        - disable use of imports, always write entire package name
  --no-debug-info                     - disable debug info
  --add-debug-lines                   - add comments with debug line numbers if available
  --no-inline-anonymous               - disable anonymous classes inline
  --no-inline-methods                 - disable methods inline
  --no-replace-consts                 - don't replace constant value with matching constant field
  --escape-unicode                    - escape non latin characters in strings (with \u)
  --respect-bytecode-access-modifiers - don't change original access modifiers
  --deobf                             - activate deobfuscation
  --deobf-min                         - min length of name, renamed if shorter, default: 3
  --deobf-max                         - max length of name, renamed if longer, default: 64
  --deobf-cfg-file                    - deobfuscation map file, default: same dir and name as input file with '.jobf' extension
  --deobf-cfg-file-mode               - set mode for handle deobfuscation map file:
                                         'read' - read if found, don't save (default)
                                         'read-or-save' - read if found, save otherwise (don't overwrite)
                                         'overwrite' - don't read, always save
                                         'ignore' - don't read and don't save
  --deobf-rewrite-cfg                 - set '--deobf-cfg-file-mode' to 'overwrite' (deprecated)
  --deobf-use-sourcename              - use source file name as class name alias
  --deobf-parse-kotlin-metadata       - parse kotlin metadata to class and package names
  --use-kotlin-methods-for-var-names  - use kotlin intrinsic methods to rename variables, values: disable, apply, apply-and-hide, default: apply
  --rename-flags                      - fix options (comma-separated list of):
                                         'case' - fix case sensitivity issues (according to --fs-case-sensitive option),
                                         'valid' - rename java identifiers to make them valid,
                                         'printable' - remove non-printable chars from identifiers,
                                        or single 'none' - to disable all renames
                                        or single 'all' - to enable all (default)
  --fs-case-sensitive                 - treat filesystem as case sensitive, false by default
  --cfg                               - save methods control flow graph to dot file
  --raw-cfg                           - save methods control flow graph (use raw instructions)
  -f, --fallback                      - make simple dump (using goto instead of 'if', 'for', etc)
  --use-dx                            - use dx/d8 to convert java bytecode
  --comments-level                    - set code comments level, values: error, warn, info, debug, user-only, none, default: info
  --log-level                         - set log level, values: quiet, progress, error, warn, info, debug, default: progress
  -v, --verbose                       - verbose output (set --log-level to DEBUG)
  -q, --quiet                         - turn off output (set --log-level to QUIET)
  --version                           - print jadx version
  -h, --help                          - print this help

Plugin options (-P<name>=<value>):
  1) dex-input (Load .dex and .apk files)
    -Pdex-input.verify-checksum       - Verify dex file checksum before load, values: [yes, no], default: yes
  2) java-convert (Convert .jar and .class files to dex)
    -Pjava-convert.mode               - Convert mode, values: [dx, d8, both], default: both
    -Pjava-convert.d8-desugar         - Use desugar in d8, values: [yes, no], default: no

Examples:
  jadx -d out classes.dex
  jadx --rename-flags "none" classes.dex
  jadx --rename-flags "valid, printable" classes.dex
  jadx --log-level ERROR app.apk
  jadx -Pdex-input.verify-checksum=no app.apk

3.3.2    dex2jar

dex2jar è una suite di strumenti che permette di operare su file .dex e .class, offrendo tra le altre cose la possibilità di convertire gli uni negli altri. Permette di decompilare sia file in .dex sia direttamente files in formato .apk
Codice:
$ d2j-dex2jar -f -o classes.jar diva-beta.apk

3.4    Decompilare il file .jar

Una volta ottenuto il file .jar è possibile analizzarlo tramite diversi tool in modo tale da leggerne il codice sorgente Java (con estensione .class). Ci sono molti programmi utili per questo scopo, alcuni (come bytecode viewer) addirittura in grado di prendere in input direattamente un file APK e ottimizzare tutto il processo di decompilazione. Tra i principali tools troviamo:

3.4.1    JD-GUI

JD-GUI è un'utilità grafica indipendente che visualizza i codici sorgente Java dei file ".class" partendo da un file .jar, .java, .class o .zip. È possibile sfogliare il codice sorgente ricostruito con JD-GUI per un accesso immediato a metodi e campi.
jd-gui.png

3.4.2    jadx-gui

jadx-gui è una versione grafica del sopra menzionato jadx. Permette di importare diversi tipi di file, tra cui .apk, .dex e .jar, ed ispezionarne il codice sorgente decompilato. E' uno strumento molto potente e preciso, sicuramente tra i migliori della categoria.
142730720-839f017e-38db-423e-b53f-39f5f0a0316f.png


3.4.3    bytecode-viewer

bytecode viewer è un tool grafico molto potente che permette di importare file .apk, .zip, .jar, .dex, ecc. e di decompilarne il contenuto utilizzando 6 diversi decompilatori (DJ-GUI/Core, Procyon, CFR, Fernflower, Krakatau, and JADX-Core). Purtroppo ha delle piccole limitazioni tecniche, come l'assenza delle classiche funzionalità "vai alla dichiarzione" o di un meccanismo di ricerca dettagliato come quello di jadx, ma la possibilità di avere 6 decompilatori all'interno dello stesso strumento è un'enorme comodità.
bytecode-viewer.jpg

4    Analisi del Manifest e del codice sorgente

Arrivati a questo punto abbiamo tutto ciò che ci serve per poter analizzare in maniera esaustiva la nostra applicazione, partendo dalle configurazioni di base fino ad arrivare ad indagare le procedure più complesse e particolari.​

4.1    Analisi dell'AndroidManifest.xml

Come già accennato nella guida "Android Application Penetration Testing - Concetti e Basi", il file AndroidManifest.xml fornisce informazioni complete su un'applicazione Android, tra cui tutti i suoi componenti, i privilegi, le librerie, le API necessarie per eseguire l'app e tanto altro. Tante informazioni utili che però, se implementate impropriamente, possono portare a problemi di sicurezza.​

Tra le problematiche più comuni legate alle configurazioni del Manifest troviamo:
  • Applicazioni con permessi eccessivi: molte applicazioni assegnano molti più privilegi di quelli richiesti (per esempio un' app che fa da calcolatrice non deve aver bisogno dell'accesso alla fotocamera o alla galleria)​
VabO6.png
  • Configurazioni insicure dei componenti: certe applicazioni "esportano" i componenti di cui sono composte (exported="true"). "Esportare" un componente significa renderlo accessibile a chiunque, applicazioni esterne comprese, aumentando così drasticamente il rischio che venga compromesso o che venga usato in maniera impropria (per accedere a dati di cui non si dovrebbe aver accesso o abusando di funzionalità ad accesso limitato)​
1*S5icLr1G7fP8ncw54APtSg.png
  • Configurazioni insicure degli attributi: certe applicazioni dispongono di alcuni attributi che rendono l'app debuggabile o che permettono di fare il backup dei dati interni (allowBackup, debuggable). Queste configurazioni sono pericolose e non dovrebbero essere abilitate su sistemi di produzione​
We5rX.png


img_54ab20fc42d15.jpeg

4.2    Analisi del codice sorgente decompilato

Conclusa l'analisi del Manifest si può passare alla parte di analisi più lunga e complicata: quella del codice sorgente. Durante l'analisi del codice è possibile imbattersi in ogni sorta di implementazione, errore o vulnerabilità, per cui è difficile dare delle linee guida esatte di cosa cercare.​

In linea di massima le macro-categorie su cui concentrarsi sono:
  • Ricerca di chiavi, credenziali o segreti hard-coded
    B05055_06_34.jpg
  • Funzionalità di pinning del certificato
    cennf.png
  • Funzionalità di autenticazione/autorizzazione
  • Presenza di librerie obsolete o vulnerabili
  • Codice pericoloso
    • SQL statement
      XScu1.jpg


    • Log abilitati
      1-OR_LsoI41-bVJyk5vkXOZg.png
    • Protocolli insicuri (HTTP)
    • Funzioni crittografiche deboli (MD5, SHA1, ecc.)
    • Configurazioni delle WebView deboli
  • Implementazioni crittografice non sicure
  • Salvataggio dei dati in maniera non sicura sulla memoria

5    MobSF

Per ottimizzare le tempistiche è stato creato un tool, chiamato Mobile Security Framework (MobSF), che permette di eseguire tutta questa parte di analisi statica in maniera del tutto automatica. Ovviamente è sempre bene affiancare all'analisi automatica anche una fase di analisi manuale, soprattutto per convalidare i numerosi falsi positivi che lo strumento trova.
ec45ab80-b46b-11e9-9f7f-6db13d2e8507

Il tool può essere scaricato e installato tramite Docker ed è estremamente facile da utilizzare: una volta avviato basterà navigare l'url della web app (http://localhost:8000/), trascinare l'APK all'interno dell'interfaccia e attendere che il tool completi l'analisi.

76472502-1f6df700-63cc-11ea-9ac0-fca99327e47d.png


MobSF può essere usato anche per l'analisi dinamica dell'applicazione, anche se personalmente lo utilizzo solo per l'analisi statica.
Maggiori dettagli sulla documentazione ufficiale.​

6    Conclusioni

In questa guida abbiamo visto come reversare e analizzare un file APK in modo tale da anlizzarlo, studiarlo e cercarne le principali vulnerabilità. Nella prossima guida ci concentraremo sull'analisi dinamica dell'applicazione, sullo sfruttamento delle principali vulnerabilità e sui tools più utilizzati per l'attacco delle misconfigurazioni trovate con l'analisi statica e il bypass delle principali misure di sicurezza (certificate pinning, root detection, ecc.).


Made with ❤ for Inforge