- gala es un proyecto que implementa directamente un jailbreak de iOS 4 para iPhone 4, y esta parte 1 se centra en obtener ejecución inicial de código aprovechando una vulnerabilidad de SecureROM en dispositivos antiguos
- El arranque de iOS sigue una cadena de confianza en la que SecureROM verifica LLB o iBSS, y cada etapa posterior verifica la siguiente; SecureROM no puede reemplazarse con actualizaciones después de la fabricación
- limera1n ataca la SecureROM del SoC A4 cuando el dispositivo en modo DFU espera la transferencia de iBSS, y el fallo hallado mediante fuzzing de mensajes de control USB parece derivar en un desbordamiento de heap y ejecución de shellcode
- Tomando como referencia el dumper de SecureROM de pod2g, se reaprovecha la región de comunicación
0x84000000y la solicitud de lectura USB0xA1:2, reimplementando el flujo para traer al host un volcado de SecureROM y valores de depuración - Se creó una tubería para extraer y ejecutar shellcode escrito en Rust desde
__TEXT,__textde un Mach-O, pero al ubicarse cadenas estáticas en__constfue necesario usar direccionamiento relativo al puntero de instrucción y ubicar datos con ensamblador
Punto de partida del proyecto de jailbreak del iPhone 4
- gala es un proyecto para crear un jailbreak de iOS 4 para iPhone 4, y este documento corresponde a su parte 1, “Gaining Entry”
- La experiencia previa desarrollando tweaks para iOS llevó a distribuir por Cydia, modificar funciones de SpringBoard, usar directamente el runtime de Objective-C y hacer ingeniería inversa de binarios de código cerrado
- El objetivo de escribir un jailbreak propio es entender cómo funciona realmente el proceso de jailbreak
- Este trabajo depende en gran medida del conocimiento compartido como código abierto por p0sixninja y axi0mX
Elección de iPhones antiguos y una vulnerabilidad de Boot ROM
- El primer paso fue comprar un iPhone 4 y un iPhone 3GS en eBay
- Como las versiones actuales de Xcode no permiten apuntar a versiones antiguas de iOS, pronto se cerró la vía de compilar e instalar apps al estilo de la década de 2010
- También se evaluó instalar versiones antiguas de Mac OS X y Xcode en una VM, pero se descartó
- Tampoco estaba claro si Apple seguiría firmando binarios para targets heredados de iOS
- La alternativa fue apuntar directamente a una vulnerabilidad de Boot ROM
- Se puede intentar solo con código que interactúe con el dispositivo por USB desde la máquina host, sin toolchains viejos ni VMs
- En la sección
Vulnerabilities and Exploitsde iPhone Wiki se revisó el código del exploit limera1n
SecureROM y la cadena de confianza del arranque de iOS
- En la terminología de Apple, SecureROM es la primera etapa del proceso de arranque de iOS y la que inicia la siguiente etapa
- SecureROM puede cargar dos componentes
- En un arranque normal, inicia
Low Level Bootloader, es decir, LLB, desde una partición de disco en la NOR - Si está conectado por USB a una computadora en modo DFU, durante el proceso de
Restore iPhonepuede recibir el cargadoriBoot Single Stage, es decir, iBSS
- En un arranque normal, inicia
- SecureROM verifica que LLB o iBSS sea una imagen confiable firmada por Apple
- Después, LLB e iBSS también verifican la siguiente etapa que cargan, formando una cadena de confianza
- Como SecureROM es la primera etapa, no está verificada por una etapa anterior y queda grabada en memoria de solo lectura durante la fabricación
- Las demás etapas sí pueden reemplazarse mediante actualizaciones de iOS
- Una vulnerabilidad en una versión específica de SecureROM permanece de forma permanente en los dispositivos fabricados con esa versión
Obtener ejecución de código en un dispositivo DFU con limera1n
- limera1n es un exploit de SecureROM publicado por geohot en 2010 y empaquetado en una herramienta de jailbreak con el mismo nombre
- limera1n puede usarse cuando un dispositivo en modo DFU está esperando recibir iBSS desde el host por USB
- Como la SecureROM incluida en el SoC A4 es vulnerable, el iPhone 4 resulta un objetivo adecuado
- El mecanismo exacto de limera1n no está completamente documentado en público
- geohot dijo que no sabía por qué funcionaba
- p0sixninja planteó una teoría
- El fallo se descubrió con fuzzing de mensajes de control USB y parece una race condition que deriva en un desbordamiento de heap, permitiendo inyectar y ejecutar shellcode
Lectura de memoria en un dispositivo en modo DFU
- El dumper de SecureROM de pod2g sirve como implementación de referencia que muestra una implementación de limera1n, un payload de ejemplo y una forma de leer memoria por USB
- El dumper de SecureROM copia la memoria
0x0, donde está mapeada SecureROM, al área de recepción USB, y luego el host lee los datos mediante mensajes de control USB - El flujo entendido es el siguiente
- La MMU del A4 mapea el inicio de la SRAM en
0x84000000 - El host puede enviar la imagen iBSS en fragmentos mediante paquetes de control USB con
request type 0x21yrequest ID 1 - Estos datos se copian en la SRAM a partir de
0x84000000, y SecureROM mantiene un contador interno para seguir la siguiente posición de copia de paquetes - El dispositivo también responde a paquetes de control con
request type 0xA1yrequest ID 2, enviando al host el contenido de memoria de0x84000000
- La MMU del A4 mapea el inicio de la SRAM en
- Esta función de lectura es especialmente útil cuando ya se puede ejecutar código en el dispositivo
- El payload copia los datos deseados a
0x84000000 - El host puede recuperarlos con la solicitud de lectura
A1:2
- El payload copia los datos deseados a
- Las diapositivas de la charla de p0sixninja en Hack In the Box Malaysia 2013 indican que el dumper de SecureROM de pod2g está basado en SHAtter, pero la utilidad real usa una implementación de limera1n
- Se logró obtener un volcado de SecureROM con una implementación propia de limera1n
Depuración del payload usando 0x84000000
- Después de obtener ejecución de código, hizo falta confirmar dónde se ejecuta el shellcode, dónde está la pila y qué memoria sobreescribe
- Se reutilizó el flujo de lectura del dumper de SecureROM como salida de depuración
- El payload copia a
0x84000000los valores del puntero de instrucción (instruction pointer) y del puntero de pila (stack pointer) - El código del lado del host vuelve a leer esos valores del mismo modo
- Este método funciona como un
print()improvisado mediante volcados de memoria
- El payload copia a
- Un script automatizado vuelca las primeras palabras de
0x84000000después de ejecutar el exploit y las muestra en la ventana de salida - Los valores observados mostraron la ubicación de ejecución del shellcode y de la pila
- El puntero de instrucción estaba cerca de
0x8402b048 - El puntero de pila estaba en
0x8403bfa0 - El puntero de pila estaba dentro del área de pila general configurada por SecureROM, y el puntero de instrucción dentro del área de imagen recibida
- El puntero de instrucción estaba cerca de
Payload en Rust y extracción de shellcode desde Mach-O
- En lugar de escribir el payload solo en ensamblador, se armó un sistema de build para compilar un payload en Rust y convertirlo en shellcode
- Rust dejó de soportar el target
armv7-apple-iosa inicios de 2020, perorustuppermite cambiar a toolchains antiguos que sí lo soportan - Al compilar en un lenguaje de alto nivel se genera un binario que incluye no solo código máquina puro, sino también metadatos, información de configuración del espacio de direcciones virtuales, tablas de símbolos e información del linker
- Para el exploit solo hacen falta los bytes que se inyectarán en memoria y a los que luego se saltará, por lo que no se necesita todo el Mach-O, sino solo la sección
__textdel segmento__TEXT - strongarm es una biblioteca de análisis de Mach-O, y se usa en el sistema de build para parsear el Mach-O y extraer a un archivo la sección
__TEXT,__text - Los bytes del archivo extraído se convierten en el shellcode que limera1n ejecutará en el dispositivo
Problemas con el linker y los datos estáticos
- Los binarios normales usan la infraestructura del sistema operativo y convenciones de símbolos de entrada como
starto_main, pero para este uso como shellcode esos símbolos no hacen falta - El linker, por defecto, da error si no existen
_mainostart - Con una combinación de opciones
-U _main,-U starty-staticfue posible crear un archivo Mach-O que no usa dyld - Al principio, strongarm no podía procesar binarios sin el comando de carga
LC_DYLD_INFOy lanzaba una excepción- Ese binario no tiene
LC_DYLD_INFOporque no usa dyld - Se agregó un parche a strongarm para manejarlo
- Ese binario no tiene
- Al agregar cadenas estáticas al código Rust, el payload dejaba de funcionar
- Las cadenas estáticas compiladas se colocan en
__const - El proceso de extracción de shellcode conserva solo
__TEXT,__text, así que los datos de__constno se cargan en memoria - Como resultado, el código intenta leer cadenas desde direcciones no mapeadas y falla
- Las cadenas estáticas compiladas se colocan en
- La solución fue incluir los datos estáticos dentro de
__TEXT,__texty usar direccionamiento relativo al puntero de instrucción para no asumir una dirección de carga estable - El método actual define las cadenas en ensamblador y pasa su dirección al punto de entrada del payload en Rust
La tubería de ejecución completada en la parte 1
- La tubería final funciona en este orden
- Se modifica el payload en Rust
- Se presiona un botón para compilar el payload
- Se extrae el shellcode del binario
- Un runner ejecuta el payload con limera1n en un iPhone en modo DFU conectado
- El runner lee automáticamente datos desde
0x84000000, que usa como espacio de comunicación, y los muestra como hexdump
- En este punto ya se puede ejecutar código arbitrario en el dispositivo
- La ejecución arbitraria de código permite hacer muchas cosas en teoría, pero lograr que el dispositivo haga algo realmente interesante sigue siendo una etapa aparte
- El siguiente paso continúa en Part 2: Bypassing the Bootchain
1 comentarios
Opiniones en Hacker News
Después de años de solo leer, finalmente me hice una cuenta en Hacker News para dejar este comentario. Gracias por explicar así algo que durante mucho tiempo fue una caja negra misteriosa para mucha gente.
Recuerdo con claridad lo nervioso que estaba cuando le hacía jailbreak a mi iPod 4G con iOS 4, viendo pasar líneas y líneas de mensajes en la terminal. Después, durante la hora del almuerzo en la escuela, también se lo hacía a los dispositivos de mis amigos, preocupado de que por error arruinara un teléfono y lo convirtiera en un ladrillo de cientos de dólares.
Mirando hacia atrás, varios años después, esa “magia” de atravesar los muros de Apple y ejecutar código de usuario fue lo que me hizo engancharme con la programación, y estoy profundamente agradecido con todos los involucrados.
Muchas gracias por el artículo. Hace falta una comprensión profunda para explicar conceptos tan complejos de forma sencilla. Mientras leía, me vinieron buenos recuerdos de cuando me quedaba hasta tarde hackeando proyectos de jailbreak.
Disfruté muchísimo leerlo, especialmente porque todavía no soy muy hábil en ingeniería inversa de código nativo.
Esto parece un jailbreak tethered, ya que usa el mecanismo de recuperación del sistema para romper la cadena de confianza y arrancar un iOS modificado. Entonces me pregunto cómo funciona un jailbreak untethered. ¿Es correcto que explota un proceso privilegiado o no privilegiado del sistema en ejecución, y luego realiza una elevación de privilegios aparte, dejando intacta la cadena de arranque seguro y sin saltársela por completo? También me pregunto cómo se logra la persistencia y cómo se parchean las verificaciones de firma del kernel sin tocar las verificaciones de firma del bootloader y del propio kernel.
Un artículo realmente excelente. Me alegra ver que sigues activo en la comunidad.
Gracias por crear esto. Tengo un iPhone 4s con muchas fotos especiales, pero por alguna razón olvidé el PIN y lleva años en un estado en el que tendría que seguir esperando.
Si no fuera por las fotos, simplemente lo habría restaurado, pero me pregunto si con esto podría restablecer el PIN y copiar las fotos.
Edición: puede que esté equivocado. [0] también dice que durante un tiempo solo el almacenamiento de Mail estaba cifrado y que el valor predeterminado cambió en iOS 7. Así que si el iPhone tiene iOS <= 6, tal vez este método permita acceder al dispositivo y copiar las fotos. La herramienta de [1] podría ayudar.
[1] https://code.google.com/archive/p/iphone-dataprotection/
[0] https://darthnull.org/ios-encryption/
Fue un artículo muy bueno. Aunque la parte en la que la antigua interfaz de iOS muestra toda la gloria del diseño esqueuomórfico me revolvió el estómago. Me hizo recordar cuánto detesto a John Ive.
Tal vez Jony debería haberse limitado a seguir diseñando reposamuñecas de aluminio afilados como navajas, en vez de encargarse del software.
Leí con mucho gusto las primeras partes. Es genial seguir el tema desde esta perspectiva. Yo también leo muchísimo código fuente para descubrir cómo implementan otras personas cosas como exploits, así que me alegra saber que otros también lo hacen.
Todavía no lo leí, pero me entusiasma. Usé todos los tweaks enumerados al principio y quería decir gracias por haberlos creado. Los jailbreaks de los primeros iOS eran realmente divertidos.
Muy bueno. Intenté ejecutarlo, pero por desgracia mi dispositivo viejo ni siquiera arrancaba desde el principio.
Yo también hacía tweaks en esa época y el jailbreak me parecía magia negra. Después de leer este artículo, todavía me lo parece en cierta medida.
Muchísimas gracias por poner todo esto en orden. Me interesa mucho aprender sobre estos temas. En particular, quiero aprender cosas como “liberar” cámaras de seguridad Wi-Fi baratas, al estilo de dafang-hacks, con mi propio firmware personalizado, o crear nuevos exploits para rootear tablets Kindle Fire.
Pero sorprende lo difícil que es encontrar artículos que expliquen ese proceso en detalle.