.. | ||
basic-ios-testing-operations.md | ||
burp-configuration-for-ios.md | ||
extracting-entitlements-from-compiled-application.md | ||
frida-configuration-in-ios.md | ||
ios-app-extensions.md | ||
ios-basics.md | ||
ios-custom-uri-handlers-deeplinks-custom-schemes.md | ||
ios-hooking-with-objection.md | ||
ios-protocol-handlers.md | ||
ios-serialisation-and-encoding.md | ||
ios-testing-environment.md | ||
ios-uiactivity-sharing.md | ||
ios-uipasteboard.md | ||
ios-universal-links.md | ||
ios-webviews.md | ||
README.md |
iOS Pentesting
Utilice Trickest para construir y automatizar fácilmente flujos de trabajo con las herramientas de la comunidad más avanzadas del mundo.
Obtenga acceso hoy mismo:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- ¿Trabajas en una empresa de ciberseguridad? ¿Quieres ver tu empresa anunciada en HackTricks? ¿O quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Obtén el swag oficial de PEASS y HackTricks
- Únete al 💬 grupo de Discord o al grupo de Telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PRs al repositorio de hacktricks y al repositorio de hacktricks-cloud.
Fundamentos de iOS
{% content-ref url="ios-basics.md" %} ios-basics.md {% endcontent-ref %}
Entorno de Pruebas
En esta página puedes encontrar información sobre el simulador de iOS, emuladores y jailbreaking:
{% content-ref url="ios-testing-environment.md" %} ios-testing-environment.md {% endcontent-ref %}
Análisis Inicial
Operaciones Básicas de Pruebas en iOS
Durante las pruebas se sugerirán varias operaciones (conectar al dispositivo, leer/escribir/subir/descargar archivos, usar algunas herramientas...). Por lo tanto, si no sabes cómo realizar alguna de estas acciones, por favor, comienza leyendo la página:
{% content-ref url="basic-ios-testing-operations.md" %} basic-ios-testing-operations.md {% endcontent-ref %}
{% hint style="info" %}
Para los siguientes pasos, la aplicación debe estar instalada en el dispositivo y ya se debe haber obtenido el archivo IPA de la aplicación.
Lee la página Operaciones Básicas de Pruebas en iOS para aprender cómo hacer esto.
{% endhint %}
Análisis Estático Básico
Se recomienda utilizar la herramienta MobSF para realizar un análisis estático automático del archivo IPA.
Identificación de protecciones presentes en el binario:
- PIE (Ejecutable Independiente de la Posición): Cuando está habilitado, la aplicación se carga en una dirección de memoria aleatoria cada vez que se inicia, lo que dificulta predecir su dirección de memoria inicial.
otool -hv <app-binary> | grep PIE # Debería incluir la marca PIE
- Canarios de Pila: Para validar la integridad de la pila, se coloca un valor 'canario' en la pila antes de llamar a una función y se valida nuevamente una vez que la función termina.
otool -I -v <app-binary> | grep stack_chk # Debería incluir los símbolos: stack_chk_guard y stack_chk_fail
- ARC (Conteo Automático de Referencias): Para prevenir fallas comunes de corrupción de memoria
otool -I -v <app-binary> | grep objc_release # Debería incluir el símbolo _objc_release
- Binario Encriptado: El binario debe estar encriptado
otool -arch all -Vl <app-binary> | grep -A5 LC_ENCRYPT # El cryptid debería ser 1
Identificación de Funciones Sensibles/Inseguras
- Algoritmos de Hash Débiles
# En el dispositivo iOS
otool -Iv <app> | grep -w "_CC_MD5"
otool -Iv <app> | grep -w "_CC_SHA1"
# En Linux
grep -iER "_CC_MD5"
grep -iER "_CC_SHA1"
- Funciones Aleatorias Inseguras
# En el dispositivo iOS
otool -Iv <app> | grep -w "_random"
otool -Iv <app> | grep -w "_srand"
otool -Iv <app> | grep -w "_rand"
# En Linux
grep -iER "_random"
grep -iER "_srand"
grep -iER "_rand"
- Función 'Malloc' Insegura
# En el dispositivo iOS
otool -Iv <app> | grep -w "_malloc"
# En Linux
grep -iER "_malloc"
- Funciones Inseguras y Vulnerables
# En el dispositivo iOS
otool -Iv <app> | grep -w "_gets"
otool -Iv <app> | grep -w "_memcpy"
otool -Iv <app> | grep -w "_strncpy"
otool -Iv <app> | grep -w "_strlen"
otool -Iv <app> | grep -w "_vsnprintf"
otool -Iv <app> | grep -w "_sscanf"
otool -Iv <app> | grep -w "_strtok"
otool -Iv <app> | grep -w "_alloca"
otool -Iv <app> | grep -w "_sprintf"
otool -Iv <app> | grep -w "_printf"
otool -Iv <app> | grep -w "_vsprintf"
# En Linux
grep -R "_gets"
grep -iER "_memcpy"
grep -iER "_strncpy"
grep -iER "_strlen"
grep -iER "_vsnprintf"
grep -iER "_sscanf"
grep -iER "_strtok"
grep -iER "_alloca"
grep -iER "_sprintf"
grep -iER "_printf"
grep -iER "_vsprintf"
Análisis Dinámico Básico
Echa un vistazo al análisis dinámico que realiza MobSF. Deberás navegar por las diferentes vistas e interactuar con ellas, pero el programa enganchará varias clases y realizará otras acciones, y al final generará un informe.
Listado de Aplicaciones Instaladas
Cuando te dirijas a las aplicaciones instaladas en el dispositivo, primero tendrás que averiguar el identificador de paquete correcto de la aplicación que deseas analizar. Puedes utilizar frida-ps -Uai
para obtener todas las aplicaciones (-a
) actualmente instaladas (-i
) en el dispositivo USB conectado (-U
):
$ frida-ps -Uai
PID Name Identifier
---- ------------------- -----------------------------------------
6847 Calendar com.apple.mobilecal
6815 Mail com.apple.mobilemail
- App Store com.apple.AppStore
- Apple Store com.apple.store.Jolly
- Calculator com.apple.calculator
- Camera com.apple.camera
- iGoat-Swift OWASP.iGoat-Swift
Enumeración básica y Hooking
Aprende cómo enumerar los componentes de la aplicación y cómo enganchar fácilmente métodos y clases con objection:
{% content-ref url="ios-hooking-with-objection.md" %} ios-hooking-with-objection.md {% endcontent-ref %}
Estructura de IPA
Los archivos .ipa
son paquetes comprimidos, por lo que puedes cambiar la extensión a .zip
y descomprimirlos. Una aplicación empaquetada completa lista para ser instalada se conoce comúnmente como un Bundle.
Después de descomprimirlos, deberías ver <NOMBRE>.app
, un archivo comprimido que contiene el resto de los recursos.
Info.plist
: Un archivo que contiene algunas de las configuraciones específicas de la aplicación._CodeSignature/
contiene un archivo plist con una firma sobre todos los archivos en el bundle.Assets.car
: Otro archivo comprimido que contiene recursos (iconos).Frameworks/
contiene las bibliotecas nativas de la aplicación como archivos .dylib o .framework.PlugIns/
puede contener extensiones de la aplicación como archivos .appex (no presentes en el ejemplo).Core Data
: Se utiliza para guardar los datos permanentes de tu aplicación para su uso sin conexión, para almacenar datos temporales en caché y para agregar funcionalidad de deshacer a tu aplicación en un solo dispositivo. Para sincronizar datos en varios dispositivos en una sola cuenta de iCloud, Core Data refleja automáticamente tu esquema en un contenedor de CloudKit.PkgInfo
: El archivoPkgInfo
es una forma alternativa de especificar los códigos de tipo y creador de tu aplicación o bundle.- en.lproj, fr.proj, Base.lproj: Son los paquetes de idioma que contienen recursos para esos idiomas específicos y un recurso predeterminado en caso de que no se admita un idioma.
Hay varias formas de definir la interfaz de usuario en una aplicación iOS: archivos storyboard, nib o xib.
Info.plist
La lista de propiedades de información o Info.plist
es la principal fuente de información para una aplicación iOS. Consiste en un archivo estructurado que contiene pares de clave-valor que describen información de configuración esencial sobre la aplicación. En realidad, se espera que todos los ejecutables empaquetados (extensiones de la aplicación, frameworks y aplicaciones) tengan un archivo Info.plist
. Puedes encontrar todas las claves posibles en la Documentación para desarrolladores de Apple.
El archivo puede estar formateado en formato XML o binario (bplist). Puedes convertirlo a formato XML con un simple comando:
- En macOS con
plutil
, que es una herramienta que viene de forma nativa con macOS 10.2 y versiones superiores (actualmente no hay documentación oficial en línea disponible):
$ plutil -convert xml1 Info.plist
- En Linux:
$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist
Aquí tienes una lista no exhaustiva de algunas informaciones y las palabras clave correspondientes que puedes buscar fácilmente en el archivo Info.plist
simplemente inspeccionando el archivo o usando grep -i <palabra clave> Info.plist
:
- Cadenas de propósito de permisos de la aplicación:
UsageDescription
- Esquemas de URL personalizados:
CFBundleURLTypes
- Tipos de documentos personalizados exportados/importados:
UTExportedTypeDeclarations
/UTImportedTypeDeclarations
- Configuración de Seguridad de Transporte de Aplicación (ATS):
NSAppTransportSecurity
Consulta los capítulos mencionados para obtener más información sobre cómo probar cada uno de estos puntos.
Rutas de datos
En iOS, las aplicaciones del sistema se pueden encontrar en el directorio /Applications
, mientras que las aplicaciones instaladas por el usuario están disponibles en /private/var/containers/
. Sin embargo, encontrar la carpeta correcta solo navegando por el sistema de archivos no es una tarea trivial, ya que a cada aplicación se le asigna un UUID (Identificador Único Universal) de 128 bits aleatorio para los nombres de sus directorios.
Para obtener fácilmente la información del directorio de instalación de las aplicaciones instaladas por el usuario, puedes usar el comando env
de objection, que también te mostrará toda la información del directorio de la aplicación:
OWASP.iGoat-Swift on (iPhone: 11.1.2) [usb] # env
Name Path
----------------- -------------------------------------------------------------------------------------------
BundlePath /var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app
CachesDirectory /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Library/Caches
DocumentDirectory /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Documents
LibraryDirectory /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Library
Como puedes ver, las aplicaciones tienen dos ubicaciones principales:
- El directorio Bundle (
/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/
). - El directorio de Datos (
/var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/
).
Estas carpetas contienen información que debe ser examinada detenidamente durante las evaluaciones de seguridad de la aplicación (por ejemplo, al analizar los datos almacenados en busca de datos sensibles).
Directorio Bundle:
- AppName.app
- Este es el paquete de la aplicación como se ve antes en el IPA, contiene datos esenciales de la aplicación, contenido estático y el binario compilado de la aplicación.
- Este directorio es visible para los usuarios, pero los usuarios no pueden escribir en él.
- El contenido de este directorio no se respalda.
- El contenido de esta carpeta se utiliza para validar la firma del código.
Directorio de Datos:
- Documents/
- Contiene todos los datos generados por el usuario. El usuario final de la aplicación inicia la creación de estos datos.
- Visible para los usuarios y los usuarios pueden escribir en él.
- El contenido de este directorio se respalda.
- La aplicación puede deshabilitar rutas estableciendo
NSURLIsExcludedFromBackupKey
. - Library/
- Contiene todos los archivos que no son específicos del usuario, como cachés, preferencias, cookies y archivos de configuración de listas de propiedades (plist).
- Las aplicaciones de iOS suelen utilizar los subdirectorios
Application Support
yCaches
, pero la aplicación puede crear subdirectorios personalizados. - Library/Caches/
- Contiene archivos en caché semipersistentes.
- Invisible para los usuarios y los usuarios no pueden escribir en él.
- El contenido de este directorio no se respalda.
- El sistema operativo puede eliminar automáticamente los archivos de este directorio cuando la aplicación no se está ejecutando y el espacio de almacenamiento es escaso.
- Library/Application Support/
- Contiene archivos persistentes necesarios para ejecutar la aplicación.
- Invisible para los usuarios y los usuarios no pueden escribir en él.
- El contenido de este directorio se respalda.
- La aplicación puede deshabilitar rutas estableciendo
NSURLIsExcludedFromBackupKey
. - Library/Preferences/
- Se utiliza para almacenar propiedades que pueden persistir incluso después de reiniciar la aplicación.
- La información se guarda sin cifrar dentro del sandbox de la aplicación en un archivo plist llamado [BUNDLE_ID].plist.
- Todos los pares clave/valor almacenados usando
NSUserDefaults
se pueden encontrar en este archivo. - tmp/
- Utiliza este directorio para escribir archivos temporales que no necesitan persistir entre lanzamientos de la aplicación.
- Contiene archivos en caché no persistentes.
- Invisible para los usuarios.
- El contenido de este directorio no se respalda.
- El sistema operativo puede eliminar automáticamente los archivos de este directorio cuando la aplicación no se está ejecutando y el espacio de almacenamiento es escaso.
Echemos un vistazo más de cerca al directorio de paquetes de la aplicación (.app) de iGoat-Swift dentro del directorio Bundle (/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app
):
OWASP.iGoat-Swift on (iPhone: 11.1.2) [usb] # ls
NSFileType Perms NSFileProtection ... Name
------------ ------- ------------------ ... --------------------------------------
Regular 420 None ... rutger.html
Regular 420 None ... mansi.html
Regular 420 None ... splash.html
Regular 420 None ... about.html
Regular 420 None ... LICENSE.txt
Regular 420 None ... Sentinel.txt
Regular 420 None ... README.txt
Reversión binaria
Dentro de la carpeta <nombre-de-la-aplicación>.app
encontrarás un archivo binario llamado <nombre-de-la-aplicación>
. Este es el archivo que se ejecutará. Puedes realizar una inspección básica del binario con la herramienta otool
:
otool -Vh DVIA-v2 #Check some compilation attributes
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC_64 ARM64 ALL 0x00 EXECUTE 65 7112 NOUNDEFS DYLDLINK TWOLEVEL WEAK_DEFINES BINDS_TO_WEAK PIE
otool -L DVIA-v2 #Get third party libraries
DVIA-v2:
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.1)
/usr/lib/libsqlite3.dylib (compatibility version 9.0.0, current version 274.6.0)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
@rpath/Bolts.framework/Bolts (compatibility version 1.0.0, current version 1.0.0)
[...]
Verificar si la aplicación está encriptada
Verificar si hay alguna salida para:
otool -l <app-binary> | grep -A 4 LC_ENCRYPTION_INFO
Desensamblar el binario
Desensamblar la sección de texto:
otool -tV DVIA-v2
DVIA-v2:
(__TEXT,__text) section
+[DDLog initialize]:
0000000100004ab8 sub sp, sp, #0x60
0000000100004abc stp x29, x30, [sp, #0x50] ; Latency: 6
0000000100004ac0 add x29, sp, #0x50
0000000100004ac4 sub x8, x29, #0x10
0000000100004ac8 mov x9, #0x0
0000000100004acc adrp x10, 1098 ; 0x10044e000
0000000100004ad0 add x10, x10, #0x268
Para imprimir el segmento Objective-C de la aplicación de muestra, se puede utilizar:
otool -oV DVIA-v2
DVIA-v2:
Contents of (__DATA,__objc_classlist) section
00000001003dd5b8 0x1004423d0 _OBJC_CLASS_$_DDLog
isa 0x1004423a8 _OBJC_METACLASS_$_DDLog
superclass 0x0 _OBJC_CLASS_$_NSObject
cache 0x0 __objc_empty_cache
vtable 0x0
data 0x1003de748
flags 0x80
instanceStart 8
Para obtener un código Objective-C más compacto, puedes usar class-dump:
class-dump some-app
//
// Generated by class-dump 3.5 (64 bit).
//
// class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard.
//
#pragma mark Named Structures
struct CGPoint {
double _field1;
double _field2;
};
struct CGRect {
struct CGPoint _field1;
struct CGSize _field2;
};
struct CGSize {
double _field1;
double _field2;
};
Sin embargo, las mejores opciones para desensamblar el binario son: Hopper y IDA.
Utiliza Trickest para construir y automatizar flujos de trabajo con las herramientas comunitarias más avanzadas del mundo.
Obtén acceso hoy mismo:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
Almacenamiento de datos
Para aprender cómo iOS almacena datos en el dispositivo, lee esta página:
{% content-ref url="ios-basics.md" %} ios-basics.md {% endcontent-ref %}
{% hint style="warning" %}
Los siguientes lugares para almacenar información deben ser verificados justo después de instalar la aplicación, después de verificar todas las funcionalidades de la aplicación e incluso después de cerrar sesión de un usuario y acceder con otro.
El objetivo es encontrar información sensible no protegida de la aplicación (contraseñas, tokens), del usuario actual y de usuarios que hayan iniciado sesión anteriormente.
{% endhint %}
Plist
Los archivos plist son archivos XML estructurados que contienen pares clave-valor. Es una forma de almacenar datos persistentes, por lo que a veces puedes encontrar información sensible en estos archivos. Se recomienda verificar estos archivos después de instalar la aplicación y después de usarla intensivamente para ver si se escriben nuevos datos.
La forma más común de persistir datos en archivos plist es a través del uso de NSUserDefaults. Este archivo plist se guarda dentro del sandbox de la aplicación en Library/Preferences/<appBundleID>.plist
La clase NSUserDefaults
proporciona una interfaz programática para interactuar con el sistema predeterminado. El sistema predeterminado permite que una aplicación personalice su comportamiento según las preferencias del usuario. Los datos guardados por NSUserDefaults
se pueden ver en el paquete de la aplicación. Esta clase almacena datos en un archivo plist, pero está destinada a ser utilizada con pequeñas cantidades de datos.
Estos datos no se pueden acceder directamente a través de una computadora de confianza, pero se pueden acceder realizando una copia de seguridad.
Puedes volcar la información guardada utilizando NSUserDefaults
utilizando el comando ios nsuserdefaults get
de objection.
Para encontrar todos los archivos plist utilizados por la aplicación, puedes acceder a /private/var/mobile/Containers/Data/Application/{APPID}
y ejecutar:
find ./ -name "*.plist"
El archivo puede estar formateado en XML o binario (bplist). Puedes convertirlo a formato XML con un simple comando:
- En macOS con
plutil
, que es una herramienta que viene de forma nativa con macOS 10.2 y versiones superiores (actualmente no hay documentación oficial en línea disponible):
$ plutil -convert xml1 Info.plist
- En Linux:
$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist
- En una sesión de objection:
ios plist cat /private/var/mobile/Containers/Data/Application/AF1F534B-1B8F-0825-ACB21-C0301AB7E56D/Library/Preferences/com.some.package.app.plist
Core Data
Core Data
es un marco para administrar la capa de modelo de objetos en tu aplicación. Core Data puede usar SQLite como su almacenamiento persistente, pero el marco en sí no es una base de datos.
CoreData no encripta sus datos de forma predeterminada. Sin embargo, se puede agregar una capa adicional de encriptación a CoreData. Consulta el Repositorio de GitHub para obtener más detalles.
Puedes encontrar la información de SQLite Core Data de una aplicación en la ruta /private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support
Si puedes abrir el SQLite y acceder a información sensible, entonces has encontrado una mala configuración.
{% code title="Código de iGoat" %}
-(void)storeDetails {
AppDelegate * appDelegate = (AppDelegate *)(UIApplication.sharedApplication.delegate);
NSManagedObjectContext *context =[appDelegate managedObjectContext];
User *user = [self fetchUser];
if (user) {
return;
}
user = [NSEntityDescription insertNewObjectForEntityForName:@"User"
inManagedObjectContext:context];
user.email = CoreDataEmail;
user.password = CoreDataPassword;
NSError *error;
if (![context save:&error]) {
NSLog(@"Error in saving data: %@", [error localizedDescription]);
}else{
NSLog(@"data stored in core data");
}
}
{% endcode %}
YapDatabase
YapDatabase es un almacén de clave/valor construido sobre SQLite.
Como las bases de datos Yap son bases de datos sqlite, puedes encontrarlas usando el comando propuesto en la sección anterior.
Otras bases de datos SQLite
Es común que las aplicaciones creen su propia base de datos sqlite. Pueden estar almacenando datos sensibles en ellas y dejándolos sin cifrar. Por lo tanto, siempre es interesante verificar cada base de datos dentro del directorio de aplicaciones. Por lo tanto, ve al directorio de la aplicación donde se guardan los datos (/private/var/mobile/Containers/Data/Application/{APPID}
)
find ./ -name "*.sqlite" -or -name "*.db"
Bases de datos en tiempo real de Firebase
Puede ser aprovechado por los desarrolladores de aplicaciones para almacenar y sincronizar datos con una base de datos en la nube sin SQL. Los datos se almacenan como JSON y se sincronizan en tiempo real con cada cliente conectado y también permanecen disponibles incluso cuando la aplicación está sin conexión.
Puedes encontrar cómo verificar bases de datos de Firebase mal configuradas aquí:
{% content-ref url="../../network-services-pentesting/pentesting-web/buckets/firebase-database.md" %} firebase-database.md {% endcontent-ref %}
Bases de datos de Realm
Realm Objective-C y Realm Swift no son suministrados por Apple, pero aún así vale la pena mencionarlos. Almacenan todo sin cifrar, a menos que la configuración tenga el cifrado habilitado.
Puedes encontrar estas bases de datos en /private/var/mobile/Containers/Data/Application/{APPID}
.
iPhone:/private/var/mobile/Containers/Data/Application/A079DF84-726C-4AEA-A194-805B97B3684A/Documents root# ls
default.realm default.realm.lock default.realm.management/ default.realm.note|
$ find ./ -name "*.realm*"
Puedes utilizar la herramienta Realm Studio para abrir estos archivos de base de datos.
El siguiente ejemplo muestra cómo utilizar el cifrado con una base de datos de Realm:
// Open the encrypted Realm file where getKey() is a method to obtain a key from the Keychain or a server
let config = Realm.Configuration(encryptionKey: getKey())
do {
let realm = try Realm(configuration: config)
// Use the Realm as normal
} catch let error as NSError {
// If the encryption key is wrong, `error` will say that it's an invalid database
fatalError("Error opening realm: \(error)")
}
Bases de datos de Couchbase Lite
Couchbase Lite es un motor de base de datos ligero, integrado y orientado a documentos (NoSQL) que se puede sincronizar. Se compila nativamente para iOS y macOS.
Verifique posibles bases de datos de Couchbase en /private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support/
Cookies
iOS almacena las cookies de las aplicaciones en Library/Cookies/cookies.binarycookies
dentro de la carpeta de cada aplicación. Sin embargo, a veces los desarrolladores deciden guardarlas en el llavero ya que el mencionado archivo de cookies puede ser accedido en las copias de seguridad.
Para inspeccionar el archivo de cookies, puedes usar este script de Python o usar el comando ios cookies get
de Objection.
También puedes usar Objection para convertir estos archivos a formato JSON e inspeccionar los datos.
...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # ios cookies get --json
[
{
"domain": "highaltitudehacks.com",
"expiresDate": "2051-09-15 07:46:43 +0000",
"isHTTPOnly": "false",
"isSecure": "false",
"name": "username",
"path": "/",
"value": "admin123",
"version": "0"
}
]
Caché
Por defecto, NSURLSession almacena datos, como las solicitudes y respuestas HTTP, en la base de datos Cache.db. Esta base de datos puede contener datos sensibles, como tokens, nombres de usuario u otra información confidencial que se haya almacenado en caché. Para encontrar la información almacenada en caché, abre el directorio de datos de la aplicación (/var/mobile/Containers/Data/Application/<UUID>
) y ve a /Library/Caches/<Bundle Identifier>
. La caché de WebKit también se almacena en el archivo Cache.db. Objection puede abrir e interactuar con la base de datos con el comando sqlite connect Cache.db
, ya que es una base de datos SQLite normal.
Se recomienda desactivar el almacenamiento en caché de estos datos, ya que pueden contener información sensible en la solicitud o respuesta. La siguiente lista muestra diferentes formas de lograr esto:
- Se recomienda eliminar las respuestas almacenadas en caché después de cerrar sesión. Esto se puede hacer con el método proporcionado por Apple llamado
removeAllCachedResponses
. Puedes llamar a este método de la siguiente manera:
URLCache.shared.removeAllCachedResponses()
Este método eliminará todas las solicitudes y respuestas almacenadas en caché del archivo Cache.db. 2. Si no necesitas utilizar las ventajas de las cookies, se recomienda utilizar la propiedad de configuración .ephemeral de URLSession, que desactivará el almacenamiento de cookies y cachés.
Un objeto de configuración de sesión efímera es similar a una configuración de sesión predeterminada (ver default), excepto que el objeto de sesión correspondiente no almacena cachés, almacenes de credenciales ni ningún dato relacionado con la sesión en el disco. En su lugar, los datos relacionados con la sesión se almacenan en la RAM. La única vez que una sesión efímera escribe datos en el disco es cuando le indicas que escriba el contenido de una URL en un archivo.
3. La caché también se puede desactivar estableciendo la política de caché en .notAllowed. Esto desactivará el almacenamiento de la caché de cualquier manera, ya sea en memoria o en disco.
Capturas de pantalla
Cada vez que presionas el botón de inicio, iOS toma una captura de pantalla de la pantalla actual para poder hacer la transición a la aplicación de una manera más suave. Sin embargo, si hay datos sensibles en la pantalla actual, se guardarán en la imagen (que persiste incluso después de reiniciar el dispositivo). Estas son las capturas de pantalla a las que también se puede acceder al hacer doble clic en la pantalla de inicio para cambiar entre aplicaciones.
A menos que el iPhone esté con jailbreak, el atacante necesita tener acceso al dispositivo desbloqueado para ver estas capturas de pantalla. Por defecto, la última captura de pantalla se almacena en el sandbox de la aplicación en la carpeta Library/Caches/Snapshots/
o Library/SplashBoard/Snapshots
(los equipos de confianza no pueden acceder al sistema de archivos a partir de iOS 7.0).
Una forma de prevenir este comportamiento no deseado es poner una pantalla en blanco o eliminar los datos sensibles antes de tomar la captura de pantalla utilizando la función ApplicationDidEnterBackground()
.
A continuación se muestra un ejemplo de un método de remediación que establecerá una captura de pantalla predeterminada.
Swift:
private var backgroundImage: UIImageView?
func applicationDidEnterBackground(_ application: UIApplication) {
let myBanner = UIImageView(image: #imageLiteral(resourceName: "overlayImage"))
myBanner.frame = UIScreen.main.bounds
backgroundImage = myBanner
window?.addSubview(myBanner)
}
func applicationWillEnterForeground(_ application: UIApplication) {
backgroundImage?.removeFromSuperview()
}
Objective-C:
Objective-C es un lenguaje de programación utilizado para desarrollar aplicaciones en iOS. Es un lenguaje orientado a objetos que se basa en el lenguaje C. Objective-C es ampliamente utilizado para desarrollar aplicaciones nativas de iOS y ofrece una amplia gama de funcionalidades y bibliotecas para facilitar el desarrollo de aplicaciones.
En el contexto de la piratería ética, el conocimiento de Objective-C es útil para realizar pruebas de penetración en aplicaciones iOS. Al comprender cómo se escriben y estructuran las aplicaciones en Objective-C, los piratas informáticos pueden identificar posibles vulnerabilidades y explotarlas para obtener acceso no autorizado a la aplicación o a los datos del usuario.
Algunas técnicas comunes de piratería en aplicaciones iOS que involucran Objective-C incluyen la inyección de código, la manipulación de datos en tiempo de ejecución y la explotación de vulnerabilidades conocidas en bibliotecas y marcos de Objective-C.
Es importante tener en cuenta que la piratería ética debe realizarse con el consentimiento del propietario de la aplicación y siguiendo las leyes y regulaciones aplicables. El objetivo principal de la piratería ética es identificar y remediar las vulnerabilidades de seguridad en lugar de causar daño o robar información confidencial.
@property (UIImageView *)backgroundImage;
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIImageView *myBanner = [[UIImageView alloc] initWithImage:@"overlayImage.png"];
self.backgroundImage = myBanner;
self.backgroundImage.bounds = UIScreen.mainScreen.bounds;
[self.window addSubview:myBanner];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[self.backgroundImage removeFromSuperview];
}
Esto establece la imagen de fondo como overlayImage.png
cada vez que la aplicación se pone en segundo plano. Esto evita fugas de datos sensibles porque overlayImage.png
siempre sobrescribirá la vista actual.
Keychain
Herramientas como Keychain-Dumper se pueden utilizar para volcar el keychain (el dispositivo debe estar jailbroken).
También puedes usar ios keychain dump
de Objection.
NSURLCredential
NSURLCredential es la clase perfecta para almacenar nombre de usuario y contraseña en el keychain. No es necesario preocuparse por NSUserDefaults ni por ningún envoltorio de keychain.
Una vez que el usuario ha iniciado sesión, puedes almacenar su nombre de usuario y contraseña en el keychain:
NSURLCredential *credential;
credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistencePermanent];
[[NSURLCredentialStorage sharedCredentialStorage] setCredential:credential forProtectionSpace:self.loginProtectionSpace];
Puedes usar ios nsurlcredentialstorage dump
de Objection para volcar estas contraseñas.
Teclados personalizados/Caché del teclado
A partir de iOS 8.0, Apple permite instalar extensiones personalizadas para iOS, como teclados personalizados.
Los teclados instalados se pueden gestionar a través de Ajustes > General > Teclado > Teclados.
Los teclados personalizados se pueden utilizar para interceptar las pulsaciones de teclas y enviarlas al servidor del atacante. Sin embargo, ten en cuenta que los teclados personalizados que requieren conectividad de red se notificarán al usuario.
Además, el usuario puede cambiar a un teclado diferente (más confiable) para introducir las credenciales.
Además, las aplicaciones pueden evitar que sus usuarios utilicen teclados personalizados dentro de la aplicación (o al menos en partes sensibles de la aplicación).
{% hint style="warning" %} Se recomienda no permitir teclados de terceros si consideras que los usuarios no los necesitarán. {% endhint %}
Ten en cuenta que debido a la autocorrección y las sugerencias automáticas, el teclado predeterminado de iOS capturará y almacenará cada palabra no estándar en un archivo de caché si el atributo secureTextEntry no está establecido en true o si autoCorrectionType no está establecido en UITextAutoCorrectionTypeNo.
Por defecto, los teclados almacenan esta caché dentro del sandbox de las aplicaciones en el archivo Library/Keyboard/{locale}-dynamic-text.dat
o en /private/var/mobile/Library/Keyboard/dynamic-text.dat
. Sin embargo, es posible que esté guardando los datos en otro lugar.
Es posible restablecer la caché en Ajustes > General > Restablecer > Restablecer diccionario del teclado
{% hint style="info" %}
Por lo tanto, siempre verifica estos archivos y busca posibles información sensible.
Interceptar el tráfico de red es otra forma de comprobar si el teclado personalizado está enviando pulsaciones de teclas a un servidor remoto.
{% endhint %}
El protocolo UITextInputTraits se utiliza para la caché del teclado. Las clases UITextField, UITextView y UISearchBar admiten automáticamente este protocolo y ofrecen las siguientes propiedades:
var autocorrectionType: UITextAutocorrectionType
determina si se habilita la autocorrección durante la escritura. Cuando la autocorrección está habilitada, el objeto de texto realiza un seguimiento de las palabras desconocidas y sugiere reemplazos adecuados, reemplazando automáticamente el texto escrito a menos que el usuario anule el reemplazo. El valor predeterminado de esta propiedad esUITextAutocorrectionTypeDefault
, que para la mayoría de los métodos de entrada habilita la autocorrección.var secureTextEntry: BOOL
determina si se desactiva la copia de texto y la caché de texto y oculta el texto que se está ingresando paraUITextField
. El valor predeterminado de esta propiedad esNO
.
Para identificar este comportamiento en el código:
- Busca en el código fuente implementaciones similares, como
textObject.autocorrectionType = UITextAutocorrectionTypeNo;
textObject.secureTextEntry = YES;
- Abre los archivos xib y storyboard en el
Interface Builder
de Xcode y verifica los estados deSecure Text Entry
yCorrection
en elInspector de Atributos
para el objeto correspondiente.
La aplicación debe evitar el almacenamiento en caché de información sensible ingresada en los campos de texto. Puedes evitar el almacenamiento en caché desactivándolo programáticamente, utilizando la directiva textObject.autocorrectionType = UITextAutocorrectionTypeNo
en los UITextFields, UITextViews y UISearchBars deseados. Para los datos que deben estar enmascarados, como los PIN y las contraseñas, establece textObject.secureTextEntry
en YES
.
UITextField *textField = [ [ UITextField alloc ] initWithFrame: frame ];
textField.autocorrectionType = UITextAutocorrectionTypeNo;
Registros
Las formas más comunes de depurar código es mediante el uso de registros, y la aplicación puede imprimir información sensible dentro de los registros.
En la versión de iOS 6 y anteriores, los registros eran legibles para todo el mundo (una aplicación maliciosa podía leer los registros de otras aplicaciones y extraer información sensible de allí). Hoy en día, las aplicaciones solo pueden acceder a sus propios registros.
Sin embargo, un atacante con acceso físico a un dispositivo desbloqueado puede conectarlo a una computadora y leer los registros (ten en cuenta que los registros escritos en el disco por una aplicación no se eliminan si la aplicación se desinstala).
Se recomienda navegar por todas las pantallas de la aplicación e interactuar con cada elemento de la interfaz de usuario y funcionalidad y proporcionar texto de entrada en todos los campos de texto y revisar los registros en busca de información sensible expuesta.
Utiliza las siguientes palabras clave para verificar el código fuente de la aplicación en busca de declaraciones de registro predefinidas y personalizadas:
- Para funciones predefinidas e integradas:
- NSLog
- NSAssert
- NSCAssert
- fprintf
- Para funciones personalizadas:
- Logging
- Logfile
Monitoreo de los registros del sistema
Muchas aplicaciones registran mensajes informativos (y potencialmente sensibles) en el registro de la consola. El registro también contiene informes de errores y otra información útil.
Puedes utilizar estas herramientas:
idevice_id --list # To find the device ID
idevicesyslog -u <id> (| grep <app>) # To get the device logs
Puedes recopilar los registros de la consola a través de la ventana Dispositivos de Xcode de la siguiente manera:
- Inicia Xcode.
- Conecta tu dispositivo a tu computadora principal.
- Elige Ventana -> Dispositivos y Simuladores.
- Haz clic en tu dispositivo iOS conectado en la sección izquierda de la ventana Dispositivos.
- Reproduce el problema.
- Haz clic en el botón Abrir Consola ubicado en la parte superior derecha de la ventana Dispositivos para ver los registros de la consola en una ventana separada.
También puedes conectarte a la shell del dispositivo como se explica en Acceso a la Shell del Dispositivo, instalar socat a través de apt-get y ejecutar el siguiente comando:
iPhone:~ root# socat - UNIX-CONNECT:/var/run/lockdown/syslog.sock
========================
ASL is here to serve you
> watch
OK
Jun 7 13:42:14 iPhone chmod[9705] <Notice>: MS:Notice: Injecting: (null) [chmod] (1556.00)
Jun 7 13:42:14 iPhone readlink[9706] <Notice>: MS:Notice: Injecting: (null) [readlink] (1556.00)
Jun 7 13:42:14 iPhone rm[9707] <Notice>: MS:Notice: Injecting: (null) [rm] (1556.00)
Jun 7 13:42:14 iPhone touch[9708] <Notice>: MS:Notice: Injecting: (null) [touch] (1556.00)
...
Utiliza Trickest para construir y automatizar fácilmente flujos de trabajo con las herramientas comunitarias más avanzadas del mundo.
Obtén acceso hoy mismo:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
Copias de seguridad
iOS incluye funciones de copia de seguridad automática que crean copias de los datos almacenados en el dispositivo. Puedes hacer copias de seguridad de iOS desde tu computadora host utilizando iTunes (hasta macOS Catalina) o Finder (desde macOS Catalina en adelante), o a través de la función de copia de seguridad de iCloud. En ambos casos, la copia de seguridad incluye casi todos los datos almacenados en el dispositivo iOS, excepto datos altamente sensibles como la información de Apple Pay y la configuración de Touch ID.
Dado que iOS realiza copias de seguridad de las aplicaciones instaladas y sus datos, una preocupación obvia es si los datos sensibles del usuario almacenados por la aplicación podrían filtrarse accidentalmente a través de la copia de seguridad. Otra preocupación, aunque menos obvia, es si se podrían manipular las configuraciones de protección de datos o restricción de funcionalidad de la aplicación para cambiar el comportamiento de la aplicación después de restaurar una copia de seguridad modificada. Ambas preocupaciones son válidas y estas vulnerabilidades han demostrado existir en una gran cantidad de aplicaciones en la actualidad.
Una copia de seguridad de un dispositivo en el que se ha instalado una aplicación móvil incluirá todos los subdirectorios (excepto Library/Caches/
) y archivos en el directorio privado de la aplicación.
Por lo tanto, evita almacenar datos sensibles en texto plano dentro de los archivos o carpetas que se encuentran en el directorio privado de la aplicación o sus subdirectorios.
Aunque todos los archivos en Documents/
y Library/Application Support/
siempre se respaldan de forma predeterminada, puedes excluir archivos de la copia de seguridad llamando a NSURL setResourceValue:forKey:error:
con la clave NSURLIsExcludedFromBackupKey
.
Puedes utilizar las propiedades del sistema de archivos NSURLIsExcludedFromBackupKey y CFURLIsExcludedFromBackupKey para excluir archivos y directorios de las copias de seguridad.
{% hint style="warning" %} Por lo tanto, al verificar la copia de seguridad de una aplicación, debes verificar si alguna información sensible es accesible y si puedes modificar algún comportamiento sensible de la aplicación mediante la modificación de alguna configuración de la copia de seguridad y la restauración de la copia de seguridad. {% endhint %}
Cómo probar
Comienza por crear una copia de seguridad del dispositivo (puedes hacerlo utilizando Finder) y encontrar dónde se almacena la copia de seguridad. La documentación oficial de Apple te ayudará a localizar las copias de seguridad de tu iPhone, iPad y iPod touch.
Una vez que hayas encontrado la copia de seguridad del dispositivo (/Users/carlos.martin/Library/Application Support/MobileSync/Backup/{deviceID}
), puedes comenzar a buscar información sensible utilizando, por ejemplo, el comando grep o herramientas como iMazing.
Para identificar si una copia de seguridad está encriptada, puedes verificar la clave llamada "IsEncrypted" en el archivo "Manifest.plist", ubicado en la raíz del directorio de la copia de seguridad. El siguiente ejemplo muestra una configuración que indica que la copia de seguridad está encriptada:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
...
<key>Date</key>
<date>2021-03-12T17:43:33Z</date>
<key>IsEncrypted</key>
<true/>
...
</plist>
En caso de que necesites trabajar con una copia de seguridad encriptada, hay algunos scripts en Python en el repositorio de GitHub de DinoSec, como backup_tool.py y backup_passwd.py, que servirán como un buen punto de partida. Sin embargo, ten en cuenta que es posible que no funcionen con las últimas versiones de iTunes/Finder y es posible que necesiten ajustes.
También puedes utilizar la herramienta iOSbackup para leer y extraer fácilmente archivos de una copia de seguridad de iOS encriptada con contraseña.
Cómo modificar el comportamiento
En la aplicación de billetera de Bitcoin de código abierto, Bither, verás que es posible configurar un PIN para bloquear la interfaz de usuario. Este PIN se almacena en el archivo net.bither.plist
dentro de la clave pin_code. Si borras esta clave de ese plist en la copia de seguridad y restauras la copia de seguridad, podrás acceder a la billetera.
Pruebas de memoria para datos sensibles
En algún momento, la información sensible se almacenará en la memoria. El objetivo es asegurarse de que esta información se exponga el menor tiempo posible.
Para investigar la memoria de una aplicación, primero crea un volcado de memoria. Alternativamente, puedes analizar la memoria en tiempo real con, por ejemplo, un depurador. Independientemente del método que utilices, este proceso es propenso a errores porque los volcados proporcionan los datos dejados por las funciones ejecutadas y es posible que te saltes pasos críticos. Además, es bastante fácil pasar por alto datos durante el análisis a menos que conozcas la huella de los datos que estás buscando (ya sea su valor exacto o su formato). Por ejemplo, si la aplicación cifra según una clave simétrica generada aleatoriamente, es muy improbable que encuentres la clave en la memoria a menos que encuentres su valor de otras formas.
Recuperación y análisis de un volcado de memoria
Ya sea que estés utilizando un dispositivo con jailbreak o sin jailbreak, puedes volcar la memoria del proceso de la aplicación con objection y Fridump.
Después de que se haya volcado la memoria (por ejemplo, en un archivo llamado "memory"), dependiendo de la naturaleza de los datos que estás buscando, necesitarás un conjunto de herramientas diferentes para procesar y analizar ese volcado de memoria. Por ejemplo, si te estás enfocando en cadenas de texto, puede ser suficiente ejecutar el comando strings
o rabin2 -zz
para extraer esas cadenas.
# using strings
$ strings memory > strings.txt
# using rabin2
$ rabin2 -ZZ memory > strings.txt
Abre strings.txt
en tu editor favorito y examínalo para identificar información sensible.
Sin embargo, si deseas inspeccionar otro tipo de datos, es mejor que uses radare2 y sus capacidades de búsqueda. Consulta la ayuda de radare2 sobre el comando de búsqueda (/?
) para obtener más información y una lista de opciones. Lo siguiente muestra solo un subconjunto de ellas:
$ r2 <name_of_your_dump_file>
[0x00000000]> /?
Usage: /[!bf] [arg] Search stuff (see 'e??search' for options)
|Use io.va for searching in non virtual addressing spaces
| / foo\x00 search for string 'foo\0'
| /c[ar] search for crypto materials
| /e /E.F/i match regular expression
| /i foo search for string 'foo' ignoring case
| /m[?][ebm] magicfile search for magic, filesystems or binary headers
| /v[1248] value look for an `cfg.bigendian` 32bit value
| /w foo search for wide string 'f\0o\0o\0'
| /x ff0033 search for hex string
| /z min max search for strings of given size
...
Análisis de la memoria en tiempo de ejecución
Usando r2frida puedes analizar e inspeccionar la memoria de la aplicación mientras se ejecuta sin necesidad de volcarla. Por ejemplo, puedes ejecutar los comandos de búsqueda anteriores desde r2frida y buscar en la memoria una cadena, valores hexadecimales, etc. Al hacerlo, recuerda agregar una barra invertida \
antes del comando de búsqueda (y cualquier otro comando específico de r2frida) después de iniciar la sesión con r2 frida://usb//<nombre_de_tu_aplicación>
.
Criptografía defectuosa
Procesos de gestión de claves deficientes
Algunos desarrolladores guardan datos sensibles en el almacenamiento local y los cifran con una clave codificada/predeterminada en el código. Esto no debería hacerse, ya que un análisis inverso podría permitir a los atacantes extraer la información confidencial.
Uso de algoritmos inseguros y/o obsoletos
Los desarrolladores no deberían utilizar algoritmos obsoletos para realizar verificaciones de autorización, almacenar o enviar datos. Algunos de estos algoritmos son: RC4, MD4, MD5, SHA1... Si se utilizan hashes para almacenar contraseñas, por ejemplo, se deben utilizar hashes resistentes a ataques de fuerza bruta con sal.
Verificación
Las principales verificaciones a realizar son buscar contraseñas/secretos codificados en el código, o si estos son predecibles, y si el código está utilizando algún tipo de algoritmo de criptografía débil.
Es interesante saber que puedes monitorizar automáticamente algunas bibliotecas de criptografía utilizando objection con:
ios monitor crypt
Para obtener más información sobre las API y bibliotecas criptográficas de iOS, acceda a https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06e-testing-cryptography
Autenticación local
El probador debe tener en cuenta que siempre se debe aplicar la autenticación local en un punto final remoto o basada en una primitiva criptográfica. Los atacantes pueden evadir fácilmente la autenticación local si no se devuelve ningún dato del proceso de autenticación.
El framework de Autenticación Local proporciona un conjunto de API para que los desarrolladores extiendan un diálogo de autenticación a un usuario. En el contexto de la conexión a un servicio remoto, es posible (y recomendado) aprovechar el llavero para implementar la autenticación local.
El sensor de identificación de huellas dactilares es operado por el coprocesador de seguridad SecureEnclave y no expone los datos de huellas dactilares a ninguna otra parte del sistema. Además de Touch ID, Apple introdujo Face ID: que permite la autenticación basada en el reconocimiento facial.
Los desarrolladores tienen dos opciones para incorporar la autenticación Touch ID/Face ID:
LocalAuthentication.framework
es una API de alto nivel que se puede utilizar para autenticar al usuario a través de Touch ID. La aplicación no puede acceder a ningún dato asociado con la huella digital registrada y solo se le notifica si la autenticación fue exitosa.Security.framework
es una API de nivel inferior para acceder a los servicios del llavero. Esta es una opción segura si su aplicación necesita proteger algunos datos secretos con autenticación biométrica, ya que el control de acceso se gestiona a nivel del sistema y no se puede evadir fácilmente.Security.framework
tiene una API en C, pero hay varios envoltorios de código abierto disponibles, lo que facilita el acceso al llavero de la misma manera que a NSUserDefaults.
{% hint style="danger" %}
Tenga en cuenta que el uso de LocalAuthentication.framework
o Security.framework
puede ser eludido por un atacante, ya que solo devuelve un valor booleano y no datos para continuar. Consulte Don't touch me that way, de David Lindner et al para obtener más detalles.
{% endhint %}
Framework de Autenticación Local
Los desarrolladores pueden mostrar un cuadro de diálogo de autenticación utilizando la función evaluatePolicy
de la clase LAContext
. Dos políticas disponibles definen las formas aceptables de autenticación:
deviceOwnerAuthentication
(Swift) oLAPolicyDeviceOwnerAuthentication
(Objective-C): Cuando está disponible, se le solicita al usuario que realice la autenticación de Touch ID. Si Touch ID no está activado, se solicita el código de acceso del dispositivo en su lugar. Si el código de acceso del dispositivo no está habilitado, la evaluación de la política falla.deviceOwnerAuthenticationWithBiometrics
(Swift) oLAPolicyDeviceOwnerAuthenticationWithBiometrics
(Objective-C): La autenticación se limita a la biometría, donde se le solicita al usuario que utilice Touch ID.
La función evaluatePolicy
devuelve un valor booleano que indica si el usuario se ha autenticado correctamente. Lo que significa que puede ser fácilmente eludido (ver a continuación)
Autenticación Local utilizando el Llavero
Las API del llavero de iOS se pueden (y deben) utilizar para implementar la autenticación local. Durante este proceso, la aplicación almacena un token de autenticación secreto u otro dato secreto que identifica al usuario en el llavero. Para autenticarse en un servicio remoto, el usuario debe desbloquear el llavero utilizando su contraseña o huella digital para obtener los datos secretos.
El llavero permite guardar elementos con el atributo especial SecAccessControl
, que permitirá el acceso al elemento solo desde el llavero después de que el usuario haya pasado la autenticación de Touch ID (o el código de acceso, si los parámetros del atributo lo permiten).
En el siguiente ejemplo, guardaremos la cadena "test_strong_password" en el llavero. La cadena solo se puede acceder en el dispositivo actual mientras el código de acceso esté configurado (kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
parámetro) y después de la autenticación de Touch ID solo para los dedos actualmente registrados (SecAccessControlCreateFlags.biometryCurrentSet
parámetro):
{% tabs %} {% tab title="Swift" %}
// 1. create AccessControl object that will represent authentication settings
var error: Unmanaged<CFError>?
guard let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
SecAccessControlCreateFlags.biometryCurrentSet,
&error) else {
// failed to create AccessControl object
return
}
// 2. define keychain services query. Pay attention that kSecAttrAccessControl is mutually exclusive with kSecAttrAccessible attribute
var query: [String: Any] = [:]
query[kSecClass as String] = kSecClassGenericPassword
query[kSecAttrLabel as String] = "com.me.myapp.password" as CFString
query[kSecAttrAccount as String] = "OWASP Account" as CFString
query[kSecValueData as String] = "test_strong_password".data(using: .utf8)! as CFData
query[kSecAttrAccessControl as String] = accessControl
// 3. save item
let status = SecItemAdd(query as CFDictionary, nil)
if status == noErr {
// successfully saved
} else {
// error while saving
}
{% tab title="Objective-C" %}
El siguiente es un ejemplo de código Objective-C para realizar una solicitud HTTP utilizando la biblioteca AFNetworking:
#import <AFNetworking/AFNetworking.h>
- (void)makeHTTPRequest {
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:@"https://api.example.com/data" parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(@"Response: %@", responseObject);
} failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
}
Este código utiliza AFNetworking para realizar una solicitud GET a la URL "https://api.example.com/data". El resultado de la solicitud se imprime en la consola.
Para utilizar AFNetworking en su proyecto Objective-C, debe agregar la biblioteca a su proyecto y asegurarse de importarla en su archivo de implementación.
Puede encontrar más información sobre AFNetworking en su repositorio de GitHub.
{% endtab %}
```objectivec
// 1. create AccessControl object that will represent authentication settings
CFErrorRef *err = nil;
SecAccessControlRef sacRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
kSecAccessControlUserPresence,
err);
// 2. define keychain services query. Pay attention that kSecAttrAccessControl is mutually exclusive with kSecAttrAccessible attribute
NSDictionary* query = @{
(_ _bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrLabel: @"com.me.myapp.password",
(__bridge id)kSecAttrAccount: @"OWASP Account",
(__bridge id)kSecValueData: [@"test_strong_password" dataUsingEncoding:NSUTF8StringEncoding],
(__bridge id)kSecAttrAccessControl: (__bridge_transfer id)sacRef
};
// 3. save item
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, nil);
if (status == noErr) {
// successfully saved
} else {
// error while saving
}
{% endtab %} {% endtabs %}
Ahora podemos solicitar el elemento guardado del llavero. Los servicios del llavero presentarán el diálogo de autenticación al usuario y devolverán los datos o nil dependiendo de si se proporcionó una huella digital adecuada o no.
{% tabs %} {% tab title="Swift" %}
// 1. define query
var query = [String: Any]()
query[kSecClass as String] = kSecClassGenericPassword
query[kSecReturnData as String] = kCFBooleanTrue
query[kSecAttrAccount as String] = "My Name" as CFString
query[kSecAttrLabel as String] = "com.me.myapp.password" as CFString
query[kSecUseOperationPrompt as String] = "Please, pass authorisation to enter this area" as CFString
// 2. get item
var queryResult: AnyObject?
let status = withUnsafeMutablePointer(to: &queryResult) {
SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
}
if status == noErr {
let password = String(data: queryResult as! Data, encoding: .utf8)!
// successfully received password
} else {
// authorization not passed
}
{% tab title="Objective-C" %}
El siguiente es un contenido de un libro de hacking sobre técnicas de hacking. El siguiente contenido es del archivo mobile-pentesting/ios-pentesting/README.md. Traduzca el texto relevante al español y devuelva la traducción manteniendo exactamente la misma sintaxis de markdown y html. No traduzca cosas como código, nombres de técnicas de hacking, palabras de hacking, nombres de plataformas en la nube/SaaS (como Workspace, aws, gcp...), la palabra 'leak', pentesting y etiquetas de markdown. Tampoco agregue nada adicional aparte de la traducción y la sintaxis de markdown.
// 1. define query
NSDictionary *query = @{(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecReturnData: @YES,
(__bridge id)kSecAttrAccount: @"My Name1",
(__bridge id)kSecAttrLabel: @"com.me.myapp.password",
(__bridge id)kSecUseOperationPrompt: @"Please, pass authorisation to enter this area" };
// 2. get item
CFTypeRef queryResult = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &queryResult);
if (status == noErr){
NSData* resultData = ( __bridge_transfer NSData* )queryResult;
NSString* password = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
NSLog(@"%@", password);
} else {
NSLog(@"Something went wrong");
}
{% endtab %} {% endtabs %}
Detección
El uso de frameworks en una aplicación también puede ser detectado mediante el análisis de la lista de bibliotecas dinámicas compartidas del binario de la aplicación. Esto se puede hacer utilizando otool
:
$ otool -L <AppName>.app/<AppName>
Si se utiliza LocalAuthentication.framework
en una aplicación, la salida contendrá ambas de las siguientes líneas (recuerda que LocalAuthentication.framework
utiliza Security.framework
internamente):
/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication
/System/Library/Frameworks/Security.framework/Security
Si se utiliza Security.framework
, solo se mostrará el segundo.
Bypass del Marco de Autenticación Local
Objection
Objection Biometrics Bypass se puede utilizar para evitar la autenticación local. Objection utiliza Frida para instrumentar la función evaluatePolicy
para que devuelva True
incluso si la autenticación no se realizó correctamente. Utiliza el comando ios ui biometrics_bypass
para evitar la autenticación biométrica insegura. Objection registrará un trabajo que reemplazará el resultado de evaluatePolicy
. Funcionará tanto en implementaciones Swift como Objective-C.
...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # ios ui biometrics_bypass
(agent) Registering job 3mhtws9x47q. Type: ios-biometrics-disable
...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # (agent) [3mhtws9x47q] Localized Reason for auth requirement: Please authenticate yourself
(agent) [3mhtws9x47q] OS authentication response: false
(agent) [3mhtws9x47q] Marking OS response as True instead
(agent) [3mhtws9x47q] Biometrics bypass hook complete
Si es vulnerable, el módulo automáticamente omitirá el formulario de inicio de sesión.
Frida
Un ejemplo de uso de evaluatePolicy
de la aplicación DVIA-v2:
+(void)authenticateWithTouchID {
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = @"Please authenticate yourself";
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
[TouchIDAuthentication showAlert:@"Authentication Successful" withTitle:@"Success"];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[TouchIDAuthentication showAlert:@"Authentication Failed !" withTitle:@"Error"];
});
}
}];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[TouchIDAuthentication showAlert:@"Your device doesn't support Touch ID or you haven't configured Touch ID authentication on your device" withTitle:@"Error"];
});
}
}
Para evadir la Autenticación Local, debemos escribir un script de Frida que evade la mencionada comprobación de _evaluatePolicy. Como se puede ver en el fragmento de código anterior, evaluatePolicy utiliza un callback que determina el resultado. Por lo tanto, la forma más sencilla de lograr el hackeo es interceptar ese callback y asegurarse de que siempre devuelva el valor de success=1.
// from https://securitycafe.ro/2022/09/05/mobile-pentesting-101-bypassing-biometric-authentication/
if(ObjC.available) {
console.log("Injecting...");
var hook = ObjC.classes.LAContext["- evaluatePolicy:localizedReason:reply:"];
Interceptor.attach(hook.implementation, {
onEnter: function(args) {
var block = new ObjC.Block(args[4]);
const callback = block.implementation;
block.implementation = function (error, value) {
console.log("Changing the result value to true")
const result = callback(1, null);
return result;
};
},
});
} else {
console.log("Objective-C Runtime is not available!");
}
frida -U -f com.highaltitudehacks.DVIAswiftv2 --no-pause -l fingerprint-bypass-ios.js
Exposición de Funcionalidad Sensible a través de IPC
Controladores de URI personalizados / Enlaces profundos / Esquemas personalizados
{% content-ref url="ios-custom-uri-handlers-deeplinks-custom-schemes.md" %} ios-custom-uri-handlers-deeplinks-custom-schemes.md {% endcontent-ref %}
Enlaces universales
{% content-ref url="ios-universal-links.md" %} ios-universal-links.md {% endcontent-ref %}
Compartir con UIActivity
{% content-ref url="ios-uiactivity-sharing.md" %} ios-uiactivity-sharing.md {% endcontent-ref %}
UIPasteboard
{% content-ref url="ios-uipasteboard.md" %} ios-uipasteboard.md {% endcontent-ref %}
Extensiones de la aplicación
{% content-ref url="ios-app-extensions.md" %} ios-app-extensions.md {% endcontent-ref %}
WebViews
{% content-ref url="ios-webviews.md" %} ios-webviews.md {% endcontent-ref %}
Serialización y codificación
{% content-ref url="ios-serialisation-and-encoding.md" %} ios-serialisation-and-encoding.md {% endcontent-ref %}
Comunicación en red
Es importante verificar que no se esté produciendo ninguna comunicación sin cifrado y también que la aplicación esté validando correctamente el certificado TLS del servidor.
Para verificar este tipo de problemas, puedes utilizar un proxy como Burp:
{% content-ref url="burp-configuration-for-ios.md" %} burp-configuration-for-ios.md {% endcontent-ref %}
Verificación de nombre de host
Un problema común al validar el certificado TLS es verificar que el certificado haya sido firmado por una CA de confianza, pero no verificar si el nombre de host del certificado es el nombre de host al que se accede.
Para verificar este problema utilizando Burp, después de confiar en la CA de Burp en el iPhone, puedes crear un nuevo certificado con Burp para un nombre de host diferente y utilizarlo. Si la aplicación sigue funcionando, entonces algo es vulnerable.
Pinning de certificados
Si una aplicación está utilizando correctamente el Pinning de SSL, entonces la aplicación solo funcionará si el certificado es el esperado. Al probar una aplicación, esto puede ser un problema ya que Burp servirá su propio certificado.
Para evitar esta protección en un dispositivo con jailbreak, puedes instalar la aplicación SSL Kill Switch o instalar Burp Mobile Assistant
También puedes utilizar el comando ios sslpinning disable
de objection.
Misceláneo
- En
/System/Library
puedes encontrar los frameworks instalados en el teléfono utilizados por las aplicaciones del sistema. - Las aplicaciones instaladas por el usuario desde la App Store se encuentran en
/User/Applications
. - Y
/User/Library
contiene los datos guardados por las aplicaciones a nivel de usuario. - Puedes acceder a
/User/Library/Notes/notes.sqlite
para leer las notas guardadas dentro de la aplicación. - Dentro de la carpeta de una aplicación instalada (
/User/Applications/<ID DE LA APP>/
) puedes encontrar algunos archivos interesantes: iTunesArtwork
: El icono utilizado por la aplicación.iTunesMetadata.plist
: Información de la aplicación utilizada en la App Store./Library/*
: Contiene las preferencias y la caché. En/Library/Cache/Snapshots/*
puedes encontrar la instantánea realizada a la aplicación antes de enviarla al segundo plano.
Parcheo en caliente/Actualización forzada
Los desarrolladores pueden parchear remotamente todas las instalaciones de su aplicación al instante sin tener que volver a enviar la aplicación a la App Store y esperar a que sea aprobada.
Para este propósito, generalmente se utiliza JSPatch. Pero también hay otras opciones como Siren y react-native-appstore-version-checker.
Este es un mecanismo peligroso que podría ser abusado por SDK de terceros maliciosos, por lo tanto, se recomienda verificar qué método se utiliza para la actualización automática (si lo hay) y probarlo. Puedes intentar descargar una versión anterior de la aplicación con este propósito.
Terceros
Un problema de los SDK de terceros es que no hay control granular sobre las características ofrecidas por el SDK. Puedes usar el SDK y tener todas las características (incluyendo fugas de diagnóstico y conexiones HTTP inseguras), o no usarlo. Además, por lo general, no es posible para los desarrolladores de aplicaciones parchear una vulnerabilidad en el SDK.
Además, algunos SDK comienzan a contener malware una vez que son muy confiables para la comunidad.
Además, las características que estos servicios proporcionan pueden implicar servicios de rastreo para monitorear el comportamiento del usuario mientras utiliza la aplicación, vender anuncios de banner o mejorar la experiencia del usuario. El inconveniente de los servicios de terceros es que los desarrolladores no conocen los detalles del código ejecutado a través de las bibliotecas de terceros. En consecuencia, no se debe enviar más información de la necesaria a un servicio y no se debe divulgar información confidencial.
El inconveniente es que un desarrollador no conoce en detalle qué código se ejecuta a través de las bibliotecas de terceros y, por lo tanto, renuncia a la visibilidad. En consecuencia, se debe asegurar que no se envíe más información de la necesaria al servicio y que no se divulgue información confidencial.
La mayoría de los servicios de terceros se implementan de dos formas:
- con una biblioteca independiente
- con un SDK completo
Todos los datos que se envían a los servicios de terceros deben ser anonimizados para evitar la exposición de información de identificación personal (PII, por sus siglas en inglés) que permitiría al tercero identificar la cuenta de usuario.
Puedes encontrar las bibliotecas utilizadas por una aplicación ejecutando otool
contra la aplicación (y ejecutándolo contra cada biblioteca compartida para encontrar más bibliotecas compartidas utilizadas).
Referencias
- https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06b-basic-security-testing#information-gathering
- iOS & Mobile App Pentesting - INE
Más información
- https://github.com/ivRodriguezCA/RE-iOS-Apps/ Curso gratuito de iOS (https://syrion.me/blog/ios-swift-antijailbreak-bypass-frida/)
- https://www.sans.org/reading-room/whitepapers/testing/ipwn-apps-pentesting-ios-applications-34577
- https://www.slideshare.net/RyanISI/ios-appsecurityminicourse
- https://github.com/prateek147/DVIA
- https://github.com/prateek147/DVIA-v2
- https://github.com/OWASP/MSTG-Hacking-Playground%20
- OWASP iGoat https://github.com/OWASP/igoat <<< Versión Objective-C https://github.com/OWASP/iGoat-Swift <<< Versión Swift
- https://github.com/authenticationfailure/WheresMyBrowser.iOS
- https://github.com/nabla-c0d3/ssl-kill-switch2
Utiliza Trickest para construir y automatizar flujos de trabajo con las herramientas comunitarias más avanzadas del mundo.
Obtén acceso hoy mismo:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- ¿Trabajas en una empresa de ciberseguridad? ¿Quieres que tu empresa sea anunciada en HackTricks? ¿O quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Obtén el oficial PEASS & HackTricks swag
- Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PRs al repositorio de hacktricks y al repositorio de hacktricks-cloud.