iOS Pentesting – Análisis Estático

Directorio de aplicaciones

Una aplicación para iOS tiene dos carpetas principales donde guarda los datos:

  • Los datos estáticos se guardan en /Applications o /var/containers/Bundle/Application/ dependiendo de si la aplicación es nativa o descargada a través de AppStore respectivamente.
  • Los datos dinámicos en la carpeta /var/mobile/Containers/Data/Application/. La aplicación guarda los datos utilizados en tiempo de ejecución.

Sistema de archivos:

  • /Application – built-in apps
  • /var/containers/Bundle/Application – 3rd party apps
  • /var/mobile/Containers/Data/Application – 3rd party app data
  • /private/var/mobile/Library/Voicemail – voicemails
  • /private/var/mobile/Library/SMS – sms
  • /private/var/mobile/Media/DCIM – photos
  • /private/var/mobile/Media/Videos – videos
  • /var/mobile/Library/AddressBook/AddressBook.sqlitedb – address book

Buscar texto en archivos

Para buscar cualquier texto dentro de archivos en una ruta de forma recursiva, se puede usar el siguiente comando:

grep -rnw '/path/' -e 'pattern'

Además, puede ser interesante buscar IP internos, correos electrónicos, números de tarjetas de crédito …, usando regex:

grep -Eo 'REGEX' -r *

Algunas expresiones regulares interesantes:

IP (999.999.999.999)
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}

Direcciones de Email
[a-zA-Z0-9_.+-][email protected][a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$

DNI
[0-9]{8,8}[A-Za-z]$

IBAN
[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}

Base64
(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$

Buscar archivos por nombre

Hay varios archivos que deben tenerse en cuenta para detectar la divulgación de datos sensibles:

  • plist
  • sql
  • db
  • xml
  • almacenamiento local

El comando find busca archivos por nombre. El comodín (*) se puede usar para buscar archivos por extensión:

find . -iname "*PATTERN*"

Leer plist

Con el siguiente comando se puede usar para leer archivos plist:

plutil FILE.plist | less

Sin embargo, se puede convertir a XML si desea modificar algunos datos o guardarlos en un formato legible:

plutil -convert xml1 -i Info.plist -o output
plutil -convert plist -i Info.xml -o output

Almacenamiento inseguro de datos

Almacenamiento inseguro

Hay muchas aplicaciones que guardan información sensible sin cifrar en bases de datos inseguras como:

  • plist
  • xml
  • db
  • sql
  • almacenamiento local

Todos estos archivos deben verificarse antes y después de la prueba porque a veces la información se guarda cuando el usuario realiza acciones.

NSUserDefaults

Una de las formas más comunes de guardar las preferencias y propiedades del usuario en una aplicación es mediante NSUserDefaults. La información almacenada en NSUserDefaults persiste incluso si cierra la aplicación y la inicia de nuevo. Por lo general, la aplicación lo utiliza para guardar valores predeterminados, como la configuración del usuario. Hay que tener en cuenta que esta clase no cifra los datos.

El plist se puede encontrar en la carpeta de datos dinámicos:

/var/mobile/Containers/Data/Application/XXXXXXXX/Library/Preferences/$AppBundleId.plist

El nombre de $AppBundleId.plist se puede encontrar en la carpeta de datos estáticos:

/var/mobile/Containers/Data/Application/XXXXX/XXX/Info.plist

Llavero

Es una base de datos sqlite ubicada en /private/var/Keychains/keychain-2.db y se puede leer usando Keychain Dumper.

Hay diferentes tipos de permisos, algunos son:

  • NSFileProtectionComplete : el archivo se almacena en un formato cifrado en el disco y no se puede leer ni escribir mientras el dispositivo está bloqueado o se inicia. Si no se configuran estas opciones, los datos sensibles se pueden guardar en iCloud o iTunes durante las copias de seguridad automáticas.
  • kSecAtrAccessibleAfterFirstUnlock : los datos permanecen accesibles hasta el próximo reinicio. Esto se recomienda para los elementos a los que deben acceder las aplicaciones en segundo plano.
  • kSecAttrAccessibleAlways : siempre se puede acceder a los datos en el elemento del llavero, independientemente de si el dispositivo está bloqueado. No recomendado.
  • kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly : solo se puede acceder a los datos en el llavero cuando el dispositivo está desbloqueado. Solo está disponible si hay una contraseña establecida en el dispositivo. Esto se recomienda para elementos que solo necesitan ser accesibles mientras la aplicación está en primer plano.

IMPORTANTE : No se deben guardar datos sensibles en el llavero. Deben guardarse en el servidor.

Nota : Durante las pruebas, el llavero debe verificarse con el móvil bloqueado y desbloqueado y con la aplicación cerrada y en funcionamiento.

Datos principales (Ztables)

En la carpeta de datos dinámicos hay un archivo llamado Cache.db. Por lo general, la aplicación guarda algunos datos como solicitudes y respuestas HTTP, datos de usuario … Se recomienda verificar esta base de datos porque la aplicación puede guardar datos sensibles como nombre de usuario o contraseñas.

Para leer la base de datos, se debe usar sqlite3:

sqlite3 database.db
Coredata.sqlite
.tables
select * from TABLE

Almacenamiento en caché de Webkit

Una aplicación que usa UIWebView podría guardar información sensible de caché en una tabla llamada «cf_url»

Implementaciones de iOS inseguras

Teclado

Si la aplicación no implementa su propio teclado, es posible que parte de la información confidencial escrita se guarde en los siguientes archivos:

/var/mobile/Containers/Data/Application/XXXXXXXX/Library/Keyboard/dynamic-text.dat 
/var/mobile//Library/Keyboard/dynamic-text.dat

Fugas de información a través de portapapeles

La aplicación no debe permitir copiar información confidencial como nombres de usuario, contraseñas, correos electrónicos … Esta información se almacena en el siguiente archivo:

/private/var/mobile/Library/Caches/com.apple.UIKit.pboard

También se puede ver con cycript:

[UIPasteboard generalPasteboard].items

Instantáneas

Cuando la aplicación entra en el fondo, el móvil toma una foto de la pantalla actual para usarla en miniatura cuando el usuario enumera todas las aplicaciones que se están ejecutando.

Se recomienda configurar la aplicación porque, cuando se minimiza, utiliza una foto personalizada para evitar que se almacene información confidencial.

Las instantáneas se guardan en la siguiente carpeta:

/var/mobile/Containers/Data/Application/XXXXXXXXXXXXX/Library/Caches/Snapshots

Cookies

La aplicación guarda las cookies utilizadas en la siguiente carpeta:

/var/mobile/Containers/Data/Application/XXXXXXXXXXXXX/Library/Cookies/

El archivo se puede ver correctamente utilizando el script BinaryCookieReader.py.

Registro de dispositivo

common.cy:

@import com.saurik.substrate.MS
NSLog_ = dlsym(RTLD_DEFAULT, "NSLog")
NSLog = function() { var types = 'v', args = [], count = arguments.length; for (var i = 0; i != count; ++i) { types += '@'; args.push(arguments[i]); } new Functor(NSLog_, types).apply(null, args); }

Carga del archivo en el cifrado:

cycript -p MyApp-QA common.cy
cycript -p MyApp-QA

Leer el registro del sistema:

socat - UNIX-CONNECT:/var/run/lockdown/syslog.sock
watch

Analizador binario

Dependencias dinámicas

otool -L app

Volcar los comandos de carga para la aplicación

otool -I app

Posición Ejecutable Independiente (PIE)

Es una funcionalidad de seguridad que permite que la aplicación use ASLR. La aplicación debe compilarse utilizando la bandera -f PIE -pie

Con el siguiente comando se puede verificar si el PIE está activo o no:

otool -hv app

Protecciones de la pila

Es una funcionalidad de seguridad que carga un valor conocido en la pila justo antes de cargar las variables de la aplicación. Esto permite proteger el puntero y detectar si algunos valores se han modificado sin permiso.

otool -I -v APP | grep stack

La salida debe tener las siguientes líneas:

stack_chk_fail
stack_chk_guard

Conteo automático de referencia (ARC)

Es una característica del compilador que proporciona administración de memoria automática de objetos Objective-C. Disminuye la probabilidad de errores de corrupción de memoria causados ​​por la aplicación.

otool -I -v APP | grep _objc_

La salida debe tener las siguientes líneas:

_objc_retain
_objc_release
_objc_storeStrong
_objc_releaseReturnValue
_objc_autoreleaseReturnValue
_objc_retainAutoreleaseReturnValue

Descifrar binarios de iOS

Para detectar si el binario está cifrado, se puede usar el siguiente comando (si cryptid es 0, la aplicación no está cifrada):

otool -arch all -Vl APP | grep -A5 LC_ENCRYPT

Primero se enumeran todas las aplicaciones disponibles y se descifra:

Clutch -i 
Clutch -b ID

A veces, Clutch arroja el error: «Fallo de segmentación: 11«, es posible resolverlo si el siguiente comando se ejecuta justo antes de volcar el binario con Clutch:

ulimit 2048

Nota : puede haber errores si la aplicación tiene dependencias. Si es así, es posible descifrar la aplicación eliminando todos los archivos binarios dependientes y restaurándolos después del descifrado.

Obtención de encabezados de aplicación

Una vez descifrado, Class Dump se puede usar para obtener toda la clase, parámetros y funciones que usa la aplicación:

class-dump APP > output.txt

Un método alternativo es usar classdump-dyld. Primero, «hookee» la aplicación con cycript:

cycript -p App123

classdump-dyld debe agregarse ejecutando el comando this, que simplemente inyecta el archivo de la biblioteca en la aplicación:

dlopen("/usr/lib/libclassdumpdyld.dylib",RTLD_NOW);

El siguiente comando se usa para agregar una referencia a la función dumpBundleForClass:

extern "C" NSString * dumpBundleForClass(Class *aClass);

Luego, es necesario identificar la clase a volcar ejecutando:

UIApp

Devolverá algo como esto:

"<ClassName_App123: 0xab54cb592>"

Para volcar los encabezados de la clase:

dumpBundleForClass(ClassName_App123)

Todos los encabezados se volcarán en «/tmp/App123».

EXTRA: Dumpear archivos de la aplicación

A diferencia de los archivos apk de Android, las aplicaciones de iOS se almacenan como archivos ipa cifrados, lo que impide un fácil acceso y análisis. Después de instalar iproxy y Frida, podemos usar frida-ios-dump para hacer esto en tiempo de ejecución.

Deja un comentario