- gala é um projeto que implementa diretamente um jailbreak do iOS 4 para o iPhone 4, e a Parte 1 foca no processo de obter execução inicial de código usando uma vulnerabilidade da SecureROM em dispositivos antigos
- O boot do iOS começa com a SecureROM validando o LLB ou o iBSS, e depois segue por uma cadeia de confiança em que cada etapa valida a próxima; a SecureROM não pode ser substituída por atualização após a fabricação
- limera1n ataca a SecureROM do SoC A4 enquanto, em modo DFU, o dispositivo espera o envio do iBSS, e o crash descoberto por fuzzing de mensagens de controle USB aparentemente leva a um heap overflow e à execução de shellcode
- Com base no dumper de SecureROM do pod2g, o fluxo é reimplementado usando a área de comunicação
0x84000000e a requisição de leitura USB0xA1:2para trazer ao host o dump da SecureROM e valores de depuração - Foi criado um pipeline que extrai shellcode de um Mach-O escrito em Rust a partir de
__TEXT,__text, mas como strings estáticas vão para__const, isso exigiu endereçamento relativo ao ponteiro de instrução e posicionamento em assembly
Ponto de partida do projeto de jailbreak do iPhone 4
- gala é um projeto para criar um jailbreak do iOS 4 para o iPhone 4, e este texto corresponde à Parte 1, “Gaining Entry”
- A experiência anterior com desenvolvimento de tweaks para iOS incluiu distribuição via Cydia, alterações de funcionalidades do SpringBoard, uso direto do runtime Objective-C e engenharia reversa de binários de código fechado
- O objetivo de escrever um jailbreak por conta própria é entender como o processo de jailbreak realmente funciona
- Este trabalho depende fortemente do conhecimento que p0sixninja e axi0mX compartilharam como código aberto
Escolhendo iPhones antigos e uma vulnerabilidade no Boot ROM
- O primeiro passo foi comprar um iPhone 4 e um iPhone 3GS no eBay
- Como o Xcode mais recente não permite mirar versões antigas do iOS, o caminho de compilar e instalar apps no estilo dos anos 2010 logo se mostrou inviável
- Também foi considerada a opção de instalar versões antigas do Mac OS X e do Xcode em uma VM, mas ela foi abandonada
- Também não estava claro se a Apple ainda assinaria binários destinados a alvos legados do iOS
- A alternativa foi mirar diretamente uma vulnerabilidade no Boot ROM
- Isso permite tentar o processo apenas com código no host que interage com o dispositivo via USB, sem toolchains antigas nem VMs
- Na seção
Vulnerabilities and Exploitsda iPhone Wiki, foi encontrado o código de exploit do limera1n
SecureROM e a cadeia de confiança do boot do iOS
- Na terminologia da Apple, a SecureROM é a primeira etapa do processo de boot do iOS e inicia a próxima fase da inicialização
- A SecureROM pode carregar dois componentes
- Em um boot normal, ela inicializa o
Low Level Bootloader, ou LLB, a partir da partição de disco na NOR - Quando o dispositivo está em modo DFU e conectado a um computador por USB, ela pode receber o bootloader
iBoot Single Stage, ou iBSS, durante o processo deRestore iPhone
- Em um boot normal, ela inicializa o
- A SecureROM verifica se o LLB ou o iBSS é uma imagem confiável assinada pela Apple
- Depois disso, o LLB e o iBSS também validam a próxima etapa que carregam, formando uma cadeia de confiança
- Como a SecureROM é a primeira etapa, ela não é validada por nenhuma etapa anterior e é gravada em memória somente leitura durante a fabricação
- As outras etapas podem ser substituídas por atualizações do iOS
- Uma vulnerabilidade em uma versão específica da SecureROM permanece para sempre nos dispositivos fabricados com aquela versão
Obtendo execução de código em um dispositivo DFU com limera1n
- limera1n é um exploit da SecureROM divulgado por geohot em 2010 e empacotado em uma ferramenta de jailbreak com o mesmo nome
- O limera1n pode ser usado quando um dispositivo em modo DFU está aguardando receber o iBSS do host via USB
- Como a SecureROM presente no SoC A4 é vulnerável, o iPhone 4 se torna um alvo adequado
- O funcionamento exato do limera1n não está totalmente documentado publicamente
- geohot disse que não sabia por que funcionava
- p0sixninja levantou uma teoria
- O crash foi descoberto por fuzzing de mensagens de controle USB e parece ser uma race condition que leva a um heap overflow, possibilitando injeção e execução de shellcode
Lendo memória em um dispositivo em modo DFU
- O dumper de SecureROM do pod2g serviu como implementação de referência, mostrando ao mesmo tempo a implementação do limera1n, exemplos de payload e uma forma de leitura de memória via USB
- O dumper de SecureROM copia a memória
0x0, onde a SecureROM está mapeada, para a área de recepção USB e depois o host lê os dados por meio de mensagens de controle USB - O fluxo entendido foi o seguinte
- A MMU do A4 mapeia o início da SRAM em
0x84000000 - O host pode enviar a imagem do iBSS em pedaços usando um pacote de controle USB com
request type 0x21erequest ID 1 - Esses dados são copiados para a SRAM a partir de
0x84000000, e a SecureROM mantém um contador interno que rastreia a próxima posição de cópia do pacote - O dispositivo também responde ao pacote de controle com
request type 0xA1erequest ID 2, enviando ao host o conteúdo da memória em0x84000000
- A MMU do A4 mapeia o início da SRAM em
- Essa função de leitura é especialmente útil quando já se consegue executar código no dispositivo
- O payload copia os dados desejados para
0x84000000 - O host pode buscar esses dados com a requisição de leitura
A1:2
- O payload copia os dados desejados para
- Os slides da apresentação de 2013 de p0sixninja na Hack In the Box Malaysia dizem que o dumper de SecureROM do pod2g é baseado em SHAtter, mas o utilitário real usa uma implementação de limera1n
- Foi possível obter com sucesso um dump da SecureROM com uma implementação própria do limera1n
Depuração de payload usando 0x84000000
- Depois de obter execução de código, foi preciso descobrir onde o shellcode estava sendo executado, onde a pilha ficava e que memória o shellcode sobrescrevia
- O fluxo de leitura do dumper de SecureROM foi reaproveitado para saída de depuração
- O payload copia os valores do ponteiro de instrução (instruction pointer) e do ponteiro de pilha (stack pointer) para
0x84000000 - O código no host lê os valores de volta da mesma forma
- Esse método funciona como um
print()improvisado por meio de dumps de memória
- O payload copia os valores do ponteiro de instrução (instruction pointer) e do ponteiro de pilha (stack pointer) para
- Um script automático faz o dump das primeiras palavras de
0x84000000após executar o exploit e as mostra na janela de saída - Os valores confirmados mostraram a posição de execução do shellcode e a localização da pilha
- O ponteiro de instrução estava perto de
0x8402b048 - O ponteiro de pilha era
0x8403bfa0 - O ponteiro de pilha ficava dentro da área normal de pilha configurada pela SecureROM, e o ponteiro de instrução ficava dentro da área da imagem recebida
- O ponteiro de instrução estava perto de
Payload em Rust e extração de shellcode de Mach-O
- Em vez de escrever o payload só em assembly, foi montado um sistema de build que compila um payload em Rust e o converte em shellcode
- O Rust deixou de oferecer suporte ao alvo
armv7-apple-iosno início de 2020, mas é possível alternar para um toolchain antigo compatível comrustup - Ao compilar em uma linguagem de alto nível, o binário gerado inclui não só código de máquina bruto, mas também metadados, informações de configuração de espaço de endereços virtuais, tabela de símbolos e informações do linker
- Como o exploit só precisa dos bytes para injetar na memória e executar com um jump, não é necessário o Mach-O inteiro, apenas a seção
__textdo segmento__TEXT - strongarm é uma biblioteca de análise de Mach-O, usada no sistema de build para fazer o parse do Mach-O e extrair para um arquivo a seção
__TEXT,__text - Os bytes do arquivo extraído se tornam o shellcode que o limera1n executa no dispositivo
Linker e o problema dos dados estáticos
- Binários comuns usam a infraestrutura do sistema operacional e convenções de símbolo de ponto de entrada como
startou_main, mas esse uso como shellcode não precisa desses símbolos - O linker, por padrão, gera erro se não existir
_mainoustart - Com uma combinação das opções
-U _main,-U starte-static, foi possível criar um arquivo Mach-O que não usa o dyld - No início, o strongarm não conseguia processar binários sem o comando de carga
LC_DYLD_INFOe lançava uma exceção- Esse binário não usa dyld, então não possui
LC_DYLD_INFO - Foi adicionada ao strongarm uma correção para lidar com isso
- Esse binário não usa dyld, então não possui
- Quando strings estáticas foram adicionadas ao código Rust, o payload quebrou
- As strings estáticas compiladas são colocadas em
__const - O processo de extração do shellcode mantém apenas
__TEXT,__text, então os dados em__constnão são carregados na memória - Como resultado, o código tenta ler a string em um endereço não mapeado e trava
- As strings estáticas compiladas são colocadas em
- A solução foi incluir os dados estáticos dentro de
__TEXT,__texte usar endereçamento relativo ao ponteiro de instrução para não depender de um endereço de carga fixo - O método atual define as strings em assembly e passa seus endereços ao ponto de entrada do payload em Rust
O pipeline de execução concluído na Parte 1
- O pipeline final funciona na seguinte ordem
- O payload em Rust é modificado
- Um botão é pressionado para compilar o payload
- O shellcode é extraído do binário
- O runner executa o payload com limera1n em um iPhone em modo DFU conectado
- O runner lê automaticamente os dados de
0x84000000, usado como área de comunicação, e os mostra em hexdump
- Neste ponto, já é possível executar código arbitrário no dispositivo
- Em teoria, execução arbitrária de código permite fazer muita coisa, mas fazer o dispositivo realmente realizar algo interessante continua sendo uma etapa separada
- A próxima etapa continua em Parte 2: Bypassing the Bootchain
1 comentários
Comentários do Hacker News
Depois de anos só lendo, finalmente criei uma conta no Hacker News para deixar esta mensagem. Obrigado por organizar algo que por muito tempo foi uma caixa-preta misteriosa para muita gente.
Lembro nitidamente de como fiquei tenso vendo as mensagens do terminal subirem uma atrás da outra quando fazia jailbreak em um iPod 4G com iOS 4. Depois, durante o almoço na escola, eu fazia o mesmo nos aparelhos dos amigos, preocupado em estragar algum telefone sem querer e transformar um dispositivo de centenas de dólares em um tijolo.
Olhando para trás, anos depois, aquela “mágica” de atravessar as barreiras da Apple e executar código do usuário foi o que me fez mergulhar na programação, e sou profundamente grato a todos os envolvidos.
Muito obrigado pelo texto. Explicar conceitos tão complexos de forma simples exige uma compreensão profunda. Enquanto lia, me vieram à cabeça boas lembranças de passar a madrugada hackeando projetos de jailbreak.
Foi um prazer ler do começo ao fim, especialmente porque ainda sou fraco em engenharia reversa de código nativo.
Isto parece um jailbreak tethered, já que usa o mecanismo de recuperação do sistema para quebrar a cadeia de confiança e inicializar um iOS modificado. Então fico curioso sobre como funciona um jailbreak untethered. Seria algo como não passar pela cadeia de boot seguro, deixando-a intacta, explorando um processo privilegiado ou não privilegiado no sistema em execução e depois fazendo uma elevação de privilégios separada? Também fico curioso sobre como a persistência é garantida e como se aplica patch à verificação de assinaturas do kernel sem mexer nas verificações de assinatura do bootloader e do próprio kernel.
Texto realmente excelente. Fico feliz em ver que você ainda está ativo na comunidade.
Obrigado por criar isto. Tenho um iPhone 4s com muitas fotos especiais, mas acabei esquecendo o PIN e estou preso nisso há anos.
Se não fossem as fotos, eu simplesmente restauraria o aparelho, mas fico me perguntando se com isso daria para redefinir o PIN e copiar as fotos.
Correção: posso estar errado. [0] também diz que, por um tempo, só o armazenamento do Mail era criptografado, e que o padrão mudou no iOS 7. Então, se o iPhone estiver no iOS <= 6, talvez seja possível acessar o dispositivo por este método e copiar as fotos. A ferramenta em [1] pode ajudar.
[1] https://code.google.com/archive/p/iphone-dataprotection/
[0] https://darthnull.org/ios-encryption/
Foi um texto muito bom. Mas as cenas que mostram a interface antiga do iOS em toda a glória do design esqueumórfico me deram um nó no estômago. Fiquei lembrando o quanto detesto John Ive.
Talvez Jony devesse ter continuado só desenhando apoios de pulso de alumínio afiados como lâminas de barbear, em vez de cuidar de software.
Li com muito interesse as primeiras partes. É legal acompanhar por essa perspectiva. Eu também leio muito código-fonte tentando entender como outras pessoas implementam coisas como exploits, então é bom saber que outros fazem o mesmo.
Ainda não li, mas estou ansioso. Usei todos os tweaks listados no começo e queria dizer obrigado por tê-los criado. O jailbreak nos primeiros tempos do iOS era realmente divertido.
Muito bom. Tentei executar, mas infelizmente meu aparelho antigo nem sequer dava boot.
Eu também criava tweaks naquela época e via o jailbreak como magia negra. Mesmo depois de ler este texto, ainda sinto que há um pouco disso.
Muito obrigado por organizar tudo isso. Tenho muito interesse em aprender esse tipo de coisa. Em especial, gostaria de aprender a “libertar” câmeras de segurança Wi‑Fi baratas, como no dafang-hacks, com meu próprio firmware customizado, ou a criar novos exploits para fazer root em tablets Kindle Fire.
Mas é surpreendentemente difícil encontrar textos que expliquem esse processo em detalhes.