Aplicaciones iOS en Macs ARM: Oportunidades de Pentesting

Blog post 20 julio 2021 por Jim Aspers, Especialista en Seguridad de Bureau Veritas Cybersecurity

Cuando inspeccionan aplicaciones iOS en busca de vulnerabilidades de seguridad, los encargados de las pruebas de penetración suelen confiar en que lleguen dispositivos con jailbreak. En el caso de las aplicaciones con detección de jailbreak, este requisito puede provocar retrasos en la ejecución, ya que eludir la detección de jailbreak puede ser una tarea complicada.


Aunque existen métodos que permiten inyectar herramientas de assessment de seguridad en la aplicación objetivo en un dispositivo sin jailbreak (véase, por ejemplo, frida-agent), esto suele llevar mucho tiempo y sus posibilidades son limitadas. La disponibilidad de una plataforma amplia y cómoda para realizar security testing, que no sea señalada por las aplicaciones como jailbroken, sería muy beneficiosa.

Adobe Stock 252554510 1

MacOS puede desempeñar el papel de dicha plataforma. El sistema operativo contiene muchas funciones nativas potentes que son útiles para la ingeniería inversa, como dtrace y sus derivados (por ejemplo, dtruss, opensnoop). Siguiente a eso, el tráfico Wi-Fi y Bluetooth puede ser interceptado trivialmente de forma local en el sistema (por ejemplo, utilizando Wireshark o un proxy como Burp Suite), en lugar de tener que configurar un man-in-the-middle externo.

Poco después de la llegada de los ordenadores Mac con procesador ARM, Apple anunció la posibilidad de ejecutar aplicaciones iOS en el sistema operativo macOS. Con el fin de explorar las posibilidades que ofrece esta característica para el pentesting, sin dejar de tener en cuenta las restricciones de Apple, buscamos una forma de ejecutar aplicaciones iOS arbitrarias en máquinas macOS.

Aunque es posible instalar aplicaciones iOS, Apple sigue manteniendo un firme control sobre lo que se puede instalar y lo que no, con el objetivo de ofrecer la misma protección contra la piratería/DRM que ofrece la plataforma iOS. Para ello, Apple anima a sus usuarios a instalar aplicaciones iOS a través de la App Store de macOS. Además, cuando se instala manualmente desde un paquete .ipa, sólo se pueden instalar paquetes de instalación firmados. Después de que la comunidad descubriera la posibilidad de 'sideloading' aplicaciones que se compraban utilizando el mismo ID de Apple con el que se registraba la máquina macOS, Apple añadió otra restricción por la que sólo se podrán instalar aplicaciones aprobadas para ejecutarse en macOS.

Aunque dista mucho de ser 'limpio', esperamos que el método demostrado pueda ser utilizado por los pentesters de aplicaciones en su beneficio.

Accelerated mobile pages amp improve seo

Descifrar la aplicación de destino

Los binarios de las aplicaciones de iOS están encriptados mediante el DRM FairPlay de Apple, lo que los hace inútiles para cualquiera excepto para el titular del ID de Apple del comprador de la aplicación. Además de ser un eficaz mecanismo antipiratería, esta encriptación implica lo siguiente:

  • La aplicación no puede transferirse a un dispositivo que no esté acoplado al mismo ID de Apple;
  • La aplicación no puede analizarse estáticamente en un desensamblador para realizar ingeniería inversa;
  • La aplicación no puede modific arse en disco para aplicar parches.

Por esta razón, los security testing y, especialmente, la ingeniería inversa se realizan generalmente sobre una aplicación iOS sin cifrar.

El proceso de obtención de una versión no cifrada de todos los binarios de la aplicación, incluidas las bibliotecas y los frameworks, puede llevarse a cabo de la forma más cómoda utilizando frida-ios-dump (véase AloneMonkey/frida-ios-dump). Esta herramienta basada en Frida aprovecha el hecho de que para ejecutar un binario cifrado, un dispositivo iOS necesita descifrar el binario en memoria a un formato ejecutable. La herramienta encuentra y vuelca las imágenes binarias descifradas de la memoria de un dispositivo con jailbreak justo después de lanzar la aplicación objetivo, y crea un archivo instalador .ipa para la aplicación que contiene binarios sin cifrar.

Adobe Stock 219049287

A efectos de demostración, se descargó la aplicación "Intelligent Hub" desarrollada por VMware desde la App Store de iOS en un dispositivo con jailbreak. Esta aplicación no está disponible para su instalación a través de la App Store de macOS, y contiene muchas bibliotecas y frameworks. Como tal, constituye un objetivo perfecto para nuestro experimento. Para el resto de este artículo, esta aplicación se utilizará como el objeto que nos gustaría ejecutar en un sistema macOS, y se hará referencia a ella como la "aplicación objetivo".

Para volcar un archivo .ipa de la aplicación de destino que contenga los binarios descifrados, se ejecuta el siguiente comando mientras el dispositivo iOS con jailbreak está conectado a través de USB:

I OS apps pic 18

Ahora bien, si intentamos instalar el archivo resultante directamente a través del instalador de aplicaciones iOS.app de macOS (que se encuentra en /System/Library/CoreServices/Applications/), nos encontramos con un error:

I OS apps pic 1

Mirando los registros en Console.app, vemos que la firma del archivo no es aceptada

I OS apps pic 2

Este es el comportamiento esperado, ya que el IPA no ha sido resignado por contener los binarios ahora desencriptados. Podríamos resignar el IPA, pero este proceso puede volverse engorroso con bastante rapidez, especialmente cuando se incluyen múltiples frameworks o cuando la aplicación de destino requiere derechos exóticos. Se pueden utilizar herramientas como AltSignpara este fin, pero como nos gustaría poder instalar paquetes de aplicaciones arbitrarias (modificadas) en cualquier momento para security testing, procedemos a buscar un método para eludir la validación de la firma en la aplicación instalada.

Aprendiendo con el ejemplo

Inspeccionando la salida en Console.app al instalar aplicaciones iOS marcadas oficialmente como compatibles con macOS desde la App Store, descubrimos que el proceso de instalación hace algo más que colocar los archivos del paquete de instalación en su sitio. Como ejemplo para estudiar el proceso de instalación, utilizamos la aplicación 'Aangifte 2020' desarrollada por de Belastingdienst. Esta aplicación estaba disponible como aplicación para iOS tanto en la App Store de iOS como en la de macOS. A lo largo de este artículo, nos referiremos a esta aplicación como la 'aplicación donante'.

La primera observación es que se crea una estructura de carpetas 'envoltorio' especial en /Aplicaciones:

I OS apps pic 3

Se comprobó que la carpeta maa.iOS.app contiene una estructura de carpetas típica de un paquete de aplicaciones iOS.

Otras observaciones muestran que el instalador hace algo más que crear esta envoltura para la aplicación iOS real. Observando los registros del sistema y la actividad de los archivos, numerosos componentes del sistema operativo están implicados en este proceso aparentemente complejo, en el que intervienen registros acoplados a los detalles del paquete en una base de datos del sistema.

En lugar de seguir realizando ingeniería inversa del proceso de instalación, se explora la posibilidad de utilizar la envoltura de la aplicación válida para alojar nuestra aplicación objetivo.

Reproducción del parásito

Volviendo al archivo descifrado de la aplicación VMware Intelligent Hub, su contenido puede extraerse de forma trivial:

I OS apps pic 4

Podemos sobrescribir el contenido del paquete de la aplicación donante con el contenido extraído del paquete de la aplicación de destino:

I OS apps pic 5

Ahora bien, esto no funcionará "out-of-the-box". Todos los binarios de macOS e iOS (incluidas las bibliotecas y marcos enlazados dinámicamente) deben estar firmados digitalmente. Para crear una firma válida, sólo pueden utilizarse certificados emitidos por Apple. Modificar un binario implica, por tanto, volver a firmar el código modificado. Estas firmas están incrustadas en el propio binario. En el caso de bibliotecas, frameworks y otros recursos importantes dentro de un paquete de aplicaciones (por ejemplo, Info.plist), las firmas se almacenan adicionalmente en un archivo específico (_CodeSignature/CodeResources). De este modo, el sistema operativo puede garantizar la integridad del código ejecutado. Para más detalles, consulte la documentación para desarrolladores de Apple al respecto.

Adobe Stock 225084966

Por esta razón, sobrescribir simplemente los contenidos del paquete de aplicaciones de nuestra envoltura válida con los de Hub.app no funcionará: las firmas de código de los binarios dentro del paquete extraído no son válidas. Como hemos copiado el contenido modificado del paquete de aplicaciones en la envoltura de la aplicación donante, tendremos que añadir una firma de código a los archivos pertinentes. Sin embargo, no queremos generar manualmente el perfil de aprovisionamiento necesario que incluya todos los derechos requeridos para cada aplicación sometida a prueba; esto implicaría un importante trabajo manual en el portal para desarrolladores de Apple. Además, esto requeriría editar los derechos de los binarios para que coincidieran con nuestra identidad de codiseño. De hecho, si adoptáramos este enfoque, bien podríamos renunciar al archivo de instalación descifrado en su totalidad. Para sortear todo esto, aquí utilizamos lo que se denomina 'firma ad-hoc'. De man codesign(1):

I OS apps pic 6

Cuando se utiliza la firma ad-hoc en lugar de la firma regular con una identidad de firma de código adecuada, las firmas de código de los binarios sólo contienen un hash del respectivo binario firmado. Este hash será verificado contra la caché de confianza estática del sistema operativo por el núcleo antes de la ejecución. La caché de confianza contiene hashes para los binarios conocidos del sistema de Apple, y no puede ser modificada en tiempo de ejecución sin explotar una grave vulnerabilidad de seguridad en la configuración por defecto de macOS.

Teniendo esto en cuenta, empezamos firmando ad-hoc nuestro paquete envuelto modificado:

I OS apps pic 7

Como era de esperar por nuestros conocimientos sobre la firma de código, si aplicamos la firma de código ad-hoc e intentamos ejecutar la aplicación, el cargador bloquea la aplicación en el momento de la carga. Justo antes del fallo, observamos la siguiente entrada de registro procedente del núcleo:

I OS apps pic 8

Vemos que el componente implicado es AppleMobileFileIntegrity, comúnmente conocido como AMFI. AMFI se ejecuta como parte del núcleo (KEXT), y se encarga de la comprobación de la integridad de los binarios. El mensaje encontrado muestra el código de retorno 0xe00002f0.

Buscando el subcódigo de retorno IOreturn observado en el código fuente del núcleo XNU se puede explicar el origen de este error:

I OS apps pic 9

El núcleo devolvió un kIOReturnNotFound como resultado cuando se le pidió que buscara el hash de nuestro binario en el almacén de confianza. Esto tiene sentido, ya que sabemos que el almacén de confianza es una estructura de datos precompilada y codificada que sólo contiene hashes de binarios en los que confía Apple. Añadir nuestros hashes al almacén de confianza está fuera del alcance de este artículo, y en su lugar utilizaremos un bypass trivial.

A efectos de prueba, a diferencia de iOS, macOS permite al usuario desactivar (parcialmente) AMFI. Si deshabilitamos AMFI, la ausencia del hash de nuestro binario firmado ad-hoc en la caché de confianza dejará de ser un problema de bloqueo. Deshabilitar AMFI puede hacerse pasando un argumento de arranque particularmente interesante al kernel de macOS. El argumento puede añadirse desde un sistema vivo de la siguiente manera, para que sea efectivo tras el reinicio:

I OS apps pic 10

Tenga en cuenta que para poder modificar los argumentos de arranque, la Protección de la Integridad del Sistema (SIP) debe estar desactivada en las versiones recientes de macOS.

Tras añadir los argumentos de arranque y reiniciar la máquina, el paquete de aplicaciones firmadas ad-hoc deja de estar bloqueado y puede iniciarse como una aplicación normal a través de Finder.app.

NOTA: Deshabilitar AMFI, y lo que es más importante, SIP, deshabilita el núcleo del modelo de seguridad del sistema operativo de macOS. ¡SIP NUNCA debe ser desactivado en un sistema de producción sin una cuidadosa consideración de los riesgos de seguridad involucrados!

Es importante tener en cuenta que para que este método funcione, la aplicación donante que utilizamos como envoltorio válido para nuestra aplicación de destino no debe lanzarse nunca antes de que se sobrescriba su contenido. Esto está relacionado con el hecho de que en el primer lanzamiento, macOS aparentemente almacena una referencia del identificador de paquete de la aplicación iOS en relación con el propio paquete envoltorio. Esto significa que si queremos mover otra aplicación de destino dentro de la envoltura, o bien tenemos que mantener el mismo identificador de paquete, o simplemente desinstalar y volver a instalar la aplicación donante de la App Store. Modificar el contenido del paquete de la aplicación iOS envuelta es posible sin restricciones, siempre y cuando el identificador del paquete no se modifique y todo el paquete se vuelva a firmar (ad-hoc) después de la modificación.

¡Manos a la obra!

Como resultado de nuestro pequeño hack, ahora podemos ejecutar con éxito nuestra aplicación de destino, el VMware Intelligent Hub, en nuestro sistema macOS:

I OS apps pic 11

Especialmente interesante para un pentester, inspeccionar los almacenes de datos de la aplicación se convierte en algo cómodo:

I OS apps pic 15

Podemos modificar la propia aplicación con restricciones mínimas (teniendo en cuenta que es necesario volver a firmarla). Esto permite aplicar parches en un abrir y cerrar de ojos. Un ejemplo para cambiar el nombre de visualización de la aplicación:

I OS apps pic 13

Como resultado, el nombre para mostrar de la aplicación (y por tanto el título de la ventana) cambiaba tras reiniciar la aplicación:

I OS apps pic 14

Como la aplicación iOS se ejecuta en el entorno nativo de macOS, se trata de forma casi idéntica a las aplicaciones macOS normales. Esto significa que el tráfico de red puede supervisarse e interceptarse utilizando herramientas comunes como Wireshark, Burp Suite o Charles. Además, se pueden utilizar herramientas de rastreo y depuración nativas de macOS, como lldb y herramientas similares a dtrace:

I OS apps pic 16

Adjuntar un entorno de depuración Xcode completo también se convierte en algo trivial, proporcionando una experiencia significativamente mejorada respecto al uso de herramientas de jailbreak simples:

I OS apps pic 17
Mobile 06

¿Y ahora?

¿Lo hemos conseguido? Bueno, en parte. Ahora podemos ejecutar aplicaciones iOS arbitrarias en nuestros sistemas macOS. Sin embargo, volviendo a nuestro planteamiento del problema planteado en la introducción, varias aplicaciones que emplean la detección de jailbreak siguen marcando nuestro sistema como jailbroken. Se necesitaría más investigación para saber si este enfoque es adecuado para resolver ese problema.

Además, no hemos conseguido instalar realmente ninguna aplicación arbitraria de iOS. Nos limitamos a "parasitar" una aplicación donante. En realidad, la ingeniería inversa de la forma en que macOS maneja internamente la generación de aplicaciones iOS y la aplicación de esto para alcanzar nuestro objetivo se tratará en un post posterior (véase https://github.com/srepsa/launchr para echar un vistazo). Permanezca atento.