En este primer artículo de la serie “guía de pentesting en aplicaciones iOS”, comenzamos por comprender cómo es la arquitectura de seguridad de iOS, ya que conocer cómo funciona este sistema operativo nos ayudará a conocer cuáles son las reglas del juego, es decir, las limitaciones, desafíos y las herramientas que necesitaremos para realizar tareas de pentesting en el sistema operativo de Apple.

Arquitectura de seguridad en iOS

En principio es necesario destacar que Apple publica periódicamente su iOS_Security_Guide, además de otras guías de seguridad, así como como la Apple Plataform Security, en la cual expone en detalle todo lo relacionado con la arquitectura de seguridad de sus sistemas proponiéndonos además considerarla como un hoja de ruta Indispensable de abordar.

Basados en la iOS_Security_Guide, repasamos cómo está compuesta la arquitectura de seguridad de iOS describiendo sus diversas funcionalidades a los efectos de comprender cuál será nuestro “escenario de batalla” a la hora de realizar nuestras pruebas de penetración.

Imagen 1. Fuente: iOS_Security_Guide

Como se puede ver en la Imagen 1, el esquema de seguridad del sistema operativo agrupa por una parte mecanismos de seguridad de tipo software y por otra parte mecanismos de seguridad de tipo hardware/firmaware.

Siguiendo la estructura que muestra el esquema, con respecto al grupo de mecanismos de seguridad de software podemos destacar que todo el sistema de ficheros (File System) se encuentra cifrado, tanto la partición del sistema operativo como la del usuario; incluidos los datos contenidos en la partición que también están cifrados. Continuando con el recorrido del esquema podemos advertir que en iOS cada aplicación se ejecuta en una sandbox  propia que prohíbe el acceso a los datos de otra aplicación, eliminando toda posibilidad de interacción entre aplicaciones. Como veremos más adelante, este tipo de sandbox siempre permanecerá en la partición del usuario haciendo que los datos de esta región estén sujetos a los algoritmos de cifrado de iOS. Además se añade una capa de seguridad adicional específicamente para los datos (Data Protection Class).

Con respecto a los mecanismos de seguridad de tipo hardware/firmware en el nivel más bajo, nos encontramos con las instancias: Device Key (valor único para cada dispositivo), y las Group Keys o claves de grupo, junto con el certificado Apple Root Certificate, el cual se encuentra en la ROM y es usado para cifrar, firmar y comprobar la autenticidad de las operaciones a partir de  un motor de cifrado que se ubica por encima de ellos y aporta mecanismos de cifrado utilizando enclaves seguros y elementos seguros en el kernel. Este motor de cifrado es el único  que puede acceder a las claves de cifrado del sistema.

Como resumen de esta introducción podemos decir que tanto para el grupo de mecanismos de seguridad de software como para el grupo de hardware/firmware existe una estructura de seguridad muy compleja y minuciosa que podríamos decir que convierte a la suma de estos mecanismos en una especie de gran jaula que a su vez contiene muchas otras dentro.

Según la propia iOS_Security_Guide podemos estructurar estos mecanismos de seguridad a partir de las siguientes seis categorías principales:
 


Hardware Security

Acerca de estos mecanismos podemos destacar que la arquitectura de seguridad de iOS hace un buen uso de las funciones de seguridad basadas en hardware que mejoran considerablemente el rendimiento del sistema. Cada dispositivo iOS viene con dos claves integradas de 256 bits de tipo AES, el ID único (UID) del dispositivo y el ID de grupo (GID) que son claves AES de 256 bits fusionadas (UID) o compiladas (GID) directamente en el procesador de aplicaciones (AP) y el procesador de enclave seguro (SEP) durante la fabricación. No hay una forma directa de leer estas claves con software o interfaces de depuración como JTAG, y las operaciones de cifrado y descifrado se realizan mediante motores de cifrado AES basados en hardware que tienen acceso exclusivo a estas claves.

El GID es un valor compartido por todos los procesadores en una clase sobre un dispositivo que se utiliza para evitar la manipulación de archivos de firmware y otras tareas criptográficas que están por fuera de los datos privados del usuario. Los UID son únicos para cada dispositivo y se utilizan para proteger la jerarquía de claves que se utiliza para el cifrado del sistema de archivos a nivel dispositivo.

En cuanto a la eliminación segura de datos, sobre la memoria flash los dispositivos iOS incluyen una función llamada Effaceable Storage, la cual consiste en tomar una región de la memoria flash para permitir el almacenamiento de pequeñas cantidades de datos y de este modo borrar de forma segura los bloques seleccionados.

Por la manipulacion y opratividad del kernel los sistemas iOS utilizan un Framework MAC basado en el legendario TrustedBSD. Siguiendo los detalles escritos al respecto por Robert N. Watson en su paper “New approaches to operating system security extensibility” de la universidad de Cambridge podemos observar como este framework trabaja sobre cuatro interfaces principales de control.

- KPI (Kernel Service Entry Point) de los servicios del kernel al framework

- La API de los comandos de usuario independientes de la política al framework

- KPI (Kernel Service Entry Point) entre el framework y los módulos de políticas de control de acceso

- Interfaz adicional de depuración y seguimiento a través de sondas DTrace (no contemplada en esta ilustración)

Imagen 2. Fuente: Universidad de Cambridge

Otros aspectos destacables sobre los mecanismos de seguridad de tipo hardware/firmware son, por ejemplo, el uso de Secure Enclave, que tal como se observa en la siguiente imagen podemos entender como un coprocesador seguro que incluye un administrador de claves basado en hardware y que a su vez se encuentra aislado del procesador principal para proporcionar una capa adicional de seguridad, la cual evita, por ejemplo, un posible downgrade al firmware del dispositivo.

Imagen 3. Fuente: Apple

Secure Boot

Durante el proceso de Booteo, el sistema iOS llama a la ROM de arranque, la cual contiene un código (que no es posible modificar) junto al certificado Apple Root CA (ambos grabados en el chip del dispositivo durante el proceso de fabricación). Luego, la ROM de arranque se asegura de que la firma del LLB (Low Level Bootloader) sea correcta para que luego el LLB compruebe que la firma del cargador de arranque (iBoot) también sea correcta. Una vez validada la firma, iBoot verifica la firma de la siguiente etapa de arranque (que es el kernel de iOS) contemplando que si alguno de estos pasos falla el proceso de arranque termine inmediatamente y el dispositivo entre en modo de recuperación (recovery mode) mostrando una  pantalla de restauración ("Connects to iTunes"). Por otra parte, si ni si quiera la ROM de arranque llega a  cargar, el dispositivo entrará en un modo de recuperación especial de bajo nivel llamado DFU (Device Firmware Upgrade), siendo este el último recurso para restaurar un dispositivo a su estado original. En este modo el dispositivo no mostrará ningún signo de actividad, es decir, su pantalla no mostrará nada.

Imagen 4. Secure Boot Chain

En concreto, todas estas etapas que se ejecutan en el proceso de Booteo se denominan "Secure Boot Chain", donde el propósito se centra en verificar la integridad del proceso de arranque, asegurando que el sistema y sus componentes estén escritos y distribuidos por Apple. Sin dudas el objetivo principal que se propuso Apple implementando este proceso es “asegurarse” que los componentes en el sistema puedan ser firmados únicamente por ellos.

Code Signing

Tal como hemos visto anteriormente durante el proceso de arranque, Apple implementa un sistema para asegurarse de que solo se ejecute en sus dispositivos código aprobado por ellos, lo que implica entre otras cosas que los usuarios solo puedan instalar software desde AppStore. Aunque alternativamente podríamos  instalar aplicaciones  mediante la obtención de un perfil de desarrollador Apple, esto implicaría también tener que registrarse en Apple, unirse al programa de desarrolladores de Apple y pagar una suscripción anual para obtener la gama completa de posibilidades de desarrollo e implementación (hay una cuenta de desarrollador gratuita que permite compilar e implementar aplicaciones pero no firmarlas ni distribuirlas en la AppStore). En resumen: siempre que queramos manipular aplicaciones tanto desde AppStore como desde un entorno de desarrollo (Xcode) necesitaremos la firma de Apple.

Entre otros aspectos destacables en lo que son los algoritmos de cifrado que utiliza Apple,  existe uno llamado Fairplay Code Encrypting, el cual básicamente se desarrolló como un DRM para contenido multimedia pago a través de iTunes (originalmente se usó para transmisiones MPEG y QuickTime, pero también se puede usar para archivos ejecutables). Cuando un usuario registra un AppleID, Apple crea un conjunto de claves públicas/privadas donde la clave privada se almacena de forma segura en el dispositivo del usuario, y cuando los usuarios descargan una aplicación, la misma se cifra con la clave pública y se descifra en memoria RAM (en tiempo de ejecución) con la clave privada.

Encryption and Data Protection

En cuanto a los algoritmos de cifrado, Apple ha incorporado cifrado basado en  hardware/firmware en sus dispositivos iOS desde el lanzamiento del iPhone 3GS, como hemos introducido en la sección hardware security de este artículo, cada dispositivo tiene un motor criptográfico dedicado que está basado en hardware y proporciona una implementación de cifrado AES de 256 bits y  algoritmos de hash SHA-1, conteniendo también un identificador único (UID) integrado en el hardware de cada dispositivo con una clave AES de 256 bits  fusionada en el procesador de aplicaciones (AP). Como hemos dicho anteriormente, también este UID puede ser leído únicamente por el motor de cifrado, contemplando que ni el software ni el firmware puedan leerlo directamente. Como veremos a continuación, este tipo de mecanismos de cifrado Apple también los utiliza para cifrar los datos almacenados en un dispositivo.

Por la protección de datos, cuando la misma está habilitada se establece un código de acceso en el dispositivo iOS (código que utilizamos para iniciar sesión en el dispositivo). Cada archivo de datos se asocia con una clase de protección específica y cada clase a un nivel diferente de accesibilidad, protegiendo los datos en función de cuándo se debe acceder a los mismos.

En cuanto a las operaciones de cifrado y descifrado asociadas con cada clase, las mismas se basan en múltiples mecanismos de clave que utilizan el UID y el código de acceso del dispositivo, una clave de clase (Class Key), una clave del sistema de archivos (File System Key), y una clave por archivo (File Key). La clave por archivo (File Key) se utiliza para cifrar el contenido del archivo, la clave de clase (Class Key) se envuelve alrededor de la clave por archivo (File Key)  y se almacena en los metadatos del archivo. En el caso de la clave del sistema de archivos ( File System Key), la misma se utiliza para cifrar los metadatos donde el UID y el código de acceso protegen la clave de clase (Class Key), siendo esta operación invisible para los usuarios.

Observando el siguiente gráfico y profundizando sobre las características de las clases mencionadas anteriormente podemos entender que cada vez que se crea un archivo en la partición de datos, si el sistema de protección de datos (Data Protection Engine) está habilitado, crea una nueva clave de 256 bits (File Key [5]) para entregarla al motor AES (basado hardware), el cual  mediante el  modo AES CBC utiliza la clave para cifrar el archivo a medida que se escribe en la memoria flash y así obtiene como resultado el cifrado del contenido del archivo (esta clave se almacena en los metadatos de los archivos). .

En cuanto a la Class Key [4], se trata de una clave dedicada para una clase de protección de datos en particular, de modo que los archivos clasificados con diferentes niveles de protección utilizan claves criptográficas independientes, jerarquía que por cierto proporciona flexibilidad y rendimiento puesto que, por ejemplo, cambiar la clase de un archivo solo requiere volver a empaquetar su clave por archivo (File Key), y un cambio de contraseña simplemente volver a empaquetar la clave de clase (Class Key).

Imagen 5. Fuente: iOS_Security_Guide

File System Key [3] clave de cifrado global que se utiliza para cifrar los metadatos relacionados con la seguridad del archivo después de que los metadatos se cifran con la Class Key.

Device key/Hardware Key  [1], también conocida como clave UID, es única para cada dispositivo y solo puede acceder a ella el motor AES de hardware. Esta es la clave maestra del sistema por así decirlo, la cual cifra las File System Key y las Class Key

Passcode Key [2], si está habilitado, se combina con la Device key/Hardware Key del dispositivo al cifrar las Class Key.

Sandbox

Sandbox es una tecnología con la que iOS maneja el control de acceso a ciertos aspectos del sistema. Se aplica a nivel de kernel y su propósito es limitar el daño al sistema y a los datos del usuario que puedan ocurrir cuando una aplicación está comprometida. A este concepto también se lo conoce como aislamiento de aplicaciones.

El sandboxing ha sido una característica de seguridad central desde el primer lanzamiento de iOS. Todas las aplicaciones de terceros se ejecutan bajo el mismo usuario (mobile) y solo unas pocas aplicaciones y servicios del sistema se ejecutan como root. Las aplicaciones iOS se instalan en un contenedor que restringe el acceso a los archivos propios de la aplicación y a un número muy limitado de API del sistema, el acceso a todos los recursos (como archivos, sockets de red, IPC y memoria compartida) está controlado por lo que se conoce como la zona de pruebas o sandbox profile.

Dionysus Blazakis nos plantea en su paper “The Apple Sandbox” el esquema de funcionamiento del  proceso de sandboxing, del que podemos destacar que cuenta con la presencia de un conjunto de funciones para inicializar y configurar el sandbox para cada proceso, un servidor Mach para manejar el registro desde el kernel, una extensión del kernel que usa la API de TrustBSD para hacer cumplir políticas individuales, y una extensión de soporte del kernel que proporciona coincidencia de expresiones regulares para el cumplimiento de políticas

La siguiente imagen nos muestra las relaciones entre los componentes mencionados anteriormente, donde los cuadros oscuros denotan componentes de código cerrado, mientras que los cuadros grises denotan componentes de código abierto. El sandboxing de una aplicación comienza con la llamada de un proceso a la función del sistema sandboxinit, la cual utiliza la biblioteca libsandbox.dylib para convertir una definición de política legible por humanos (que describe reglas como "no permitir el acceso a archivos en / opt / test") en un formato binario para el kernel. Este formato binario se pasa a la llamada al sistema mac_syscall, manejada por el subsistema TrustBSD, y luego este pasará la solicitud de inicialización del sandbox a la extensión del kernel Sandbox.kext para su procesamiento. La extensión del kernel instalará las reglas del sandbox profile para el proceso actual y una vez finalizado se devolverá un valor de retorno satisfactorio del kernel.

Imagen 6. Fuente.

Muy resumidamente, el proceso de sandboxing siempre se iniciara cuando un proceso realice una llamada MAC al sistema, luego la capa MAC comprobará si las políticas aplican al proceso que inicio la llamada. Si aplican, se listaran los módulos de las políticas invocadas, y si sandbox.kext está registrado invocará la devolución de la llamada MAC y verificará contra los mensajes coincidentes si debe aprobar o negar la solicitud.

Aspectos destacables del sandboxing

  • Las aplicaciones solo se pueden ejecutar en el directorio que se les otorgó(/private)/var/containers/Bundle/Application) mediante un proceso similar a chroot.
  • El syscall mmap y mprotect se modifican rápidamente para evitar que las aplicaciones intenten crear áreas ejecutables en la memoria como también detener procesos generados a partir del código fuente.
  • Todos los procesos son independientes entre sí.
  • No se puede acceder directamente a los controladores de hardware, a menos que se utilicen los frameworks públicos de Apple.

General Exploit Mitigations

Entre otras tantas restricciones que implementa Apple sobre iOS, se encuentra una función llamada ASLR (Address Space Layout Randomization), la cual aleatoriza la ubicación en memoria de un archivo ejecutable (conjuntamente con sus datos asociados) y la pila del mismo cada vez que este se ejecuta. Debido a que las bibliotecas compartidas deben ser estáticas para que múltiples procesos puedan acceder a ellas, las direcciones de las bibliotecas compartidas se aleatorizan cada vez que se inicia el sistema operativo en lugar de cada vez que se invoca el programa. Esto hace que las direcciones de memoria de bibliotecas y funciones específicas sean difíciles de predecir evitando así ataques como el de retorno a libc, el cual involucra las direcciones de memoria de las funciones básicas de libc. Por otra parte, también podemos destacar el uso del bit XN (EXecute Never) utilizado para mitigar los ataques de ejecución de código. Este mecanismo permite que iOS marque segmentos de memoria seleccionados de un proceso como no ejecutables. En iOS los procesos de la pila en modo de usuario se marcan como no ejecutables evitando que los atacantes puedan inyectar y ejecutar código máquina en la pila.

Aunque podríamos seguir profundizando en los diferentes mecanismos y capas que forman la arquitectura de seguridad del sistema iOS tales TouchID, Keyags, u otros aspectos como los de la seguridad a nivel Networking, es un hecho que no podemos abordar todo en esta entrega y aquí solo queda un esquema de referencia para que puedas profundizar tus conocimientos en la medida que lo necesites.

Por otra parte, tanto para abordar el estudio de la arquitectura del sistema operativo iOS como su arquitectura de seguridad, te sugerimos como práctica complementar este estudio con libros como iOS Application Security The Definitive Guide for Hackers and Developers o Learning iOS Penetration Testing, los cuales aportan distintos puntos de vista e información concreta sobre problemáticas de seguridad abordando casos prácticos sobre distintos perfiles y áreas de conocimiento.

Conclusiones

Ahora bien, la pregunta es concreta, con todos estos mecanismos de seguridad  ¿cómo hacemos una prueba de intrusión a una App iOS? No podemos acceder a los datos de las aplicaciones, las particiones están cifradas y las aplicaciones se ejecutan en sus propias sandboxes. Aunque parezca que estamos acorralados, como dice el dicho popular, hecha la ley, hecha la trampa, y la respuesta es el Jailbreak. Si bien en la siguiente entrega de esta serie sobre pentesting sobre aplicaciones iOS abordaremos este tema con más profundidad, Jailbreak básicamente es un proceso que nos permite elevar privilegios en el sistema brindándonos la posibilidad de romper muchos de los mecanismos de seguridad mencionados en el presente artículo, y destacándose sobre todo por darnos la posibilidad de instalar aplicaciones de terceros (sin necesitar la firma de Apple) como las que provee el repositorio Cydia, del cual hablaremos también cuando toque su turno. Sin dudas, aprender sobre este tipo de mecanismos (Jailbreak) será nuestro punto de partida para llevar a cabo nuestras pruebas de intrusión, aunque debemos considerar que nada es la panacea y tener este tipo de privilegios no reemplaza los conocimientos que debemos tener en materia de nuestro objetivo (Arquitectura de seguridad iOS) y conocimientos de pentesting a la hora de realizar estrategias de intrusión para encontrar defectos o vulnerabilidades en el mismo.

En una segunda entrega de esta guía de pentesting en aplicaciones iOS abordaremos el jailbreak.