Segurança

Guia ipsw Parte 1: Pesquisa iOS/macOS | 8kSec

O primeiro post do blog sobre a ferramenta ipsw apresenta suas funcionalidades básicas e como ela pode facilitar pesquisas em sistemas iOS/macOS. O ipsw oferece comandos para interagir com APIs da Apple, gerenciar certificados de assinatura, dispositivos registrados e perfis de provisionamento, além de permitir a criação e remoção desses itens usando chaves e IDs fornecidas pela Apple.

Compartilhar
ipsw Walkthrough Part 1: iOS/macOS Research | 8kSec

Nesta primeira postagem de blog sobre a ferramenta ipsw, veremos seus usos básicos e como pode facilitar nossa vida. O ipsw é uma ferramenta que pode ser utilizada para pesquisa em *OS, ela fornece muitas funcionalidades relacionadas a dyld_shared_cache, DeviceTree, kernelcache, Img4, etc., todas do interesse de pesquisadores de segurança.

Vamos passar por cada comando para ver o que ele faz e como usá-lo, mas antes disso, precisamos obter o ipsw. Podemos construir o ipsw a partir da fonte ou podemos baixar um dos binários pré-construídos disponíveis no repositório GitHub.

Depois de baixarmos o ipsw, para confirmar que tudo está funcionando corretamente e ver a lista das opções, digitaremos --help.

Saída do comando --help da ferramenta IPSW mostrando todos os comandos e opções disponíveis

App Store

O appstore é o primeiro comando que a ferramenta ipsw fornece e permite interagir com a API do App Store Connect.

Saída do comando appstore da ferramenta IPSW mostrando subcomandos da API do App Store Connect

O ipsw appstore fornece:

  • gerenciamento de IDs de pacote dos aplicativos criados
  • gerenciamento de certificados de assinatura
  • listagem e registro de novos dispositivos
  • gerenciamento de perfis de provisionamento
  • geração de token jwt que podemos usar para interagir com a API do App Store Connect.

Muitos dos comandos ipsw exigem uma Chave da API do App Store Connect, e podemos obtê-la visitando https://appstoreconnect.apple.com/access/api.

Página de chaves da API do App Store Connect mostrando como criar e baixar uma chave com ID do Emissor e ID da Chave

Depois que a chave é criada, precisamos baixá-la clicando no botão Baixar.

O caminho para o arquivo será fornecido com a flag -p, a ID do Emissor com a flag -i e a ID da Chave com a flag -k. Ambas essas IDs podem ser copiadas da página web, como pode ser visto na imagem acima.

Pacote

Nós podemos listar as IDs de pacote registradas (criadas com o Xcode) usando ipsw appstore bundle ls, enquanto fornecemos a informação anteriormente adquirida (.p8 file, ID do Emissor e ID da Chave). Podemos usar este comando para ver todas as IDs de pacote que temos registradas.

comando: ipsw appstore bundle ls -p CAMINHO_PARA_ARQUIVO_P8 -i ID_DO_EMISSOR -k ID_DA_CHAVE

Saída do comando ipsw appstore bundle ls listando as IDs de pacote registradas

Certificado

O appstore nos fornece o gerenciamento de certificados de assinatura. Para listar os certificados, podemos simplesmente chamar ipsw appstore cert ls, com o arquivo .p8, ID do Emissor e ID da Chave. Podemos usar este comando quando quisermos criar rapidamente um novo certificado de assinatura ou se quisermos verificar eles.

comando: ipsw appstore cert ls -p CAMINHO_PARA_ARQUIVO_P8 -i ID_DO_EMISSOR -k ID_DA_CHAVE

Saída do comando ipsw appstore cert ls listando os certificados de assinatura

Agora veremos como criar um novo certificado de assinatura. A primeira coisa que precisamos fazer é criar uma nova chave usando openssl.

comando: openssl req -newkey rsa:2048 -keyout 8ksec.key -out 8ksec.csr

Após preencher as informações necessárias, teremos a Solicitação de Certificado de Assinatura (CSR) dentro do arquivo 8ksec.csr e a chave privada dentro do arquivo 8ksec.key. O conteúdo do arquivo 8ksec.csr será passado para a flag -c de ipsw appstore cert add. Precisamos limpar um pouco, removendo novas linhas, podemos fazer isso com tr -d ’n’.

Comando OpenSSL gerando uma CSR e chave privada para um certificado de assinatura

Após obter nosso csr, chamaremos ipsw appstore cert add com a opção --type DEVELOPMENT.

comando: ipsw appstore cert add -c CONTEÚDO_DO_CSR -t DEVELOPMENT -p CAMINHO_PARA_ARQUIVO_P8 -i ID_DO_EMITENTE -k CHAVE_ID

Comando IPSW appstore cert add enviando um novo certificado de assinatura

Podemos ver que criamos com sucesso um novo certificado de assinatura, que foi salvo no nosso sistema. Para confirmar que ele foi criado, vamos chamar ipsw appstore cert ls novamente.

Saída do comando IPSW appstore cert ls confirmando o novo certificado de assinatura na lista

Para remover o certificado, basta passar a opção --id para ipsw appstore cert rm. No nosso caso, o comando ficaria assim: ipsw appstore cert rm --id Q6FAZ3K5VT -p CAMINHO_PARA_ARQUIVO_P8 -i ID_DO_EMITENTE -k CHAVE_ID.

dispositivo

Também podemos gerenciar dispositivos usando o subcomando appstore, como listar dispositivos ou registrar novos dispositivos. Para adicionar um novo dispositivo, precisamos ter o UDID do dispositivo e especificar seu nome e plataforma (iOS). O UDID pode ser visto usando idevice_id da biblioteca libimobiledevice.

O comando para listar dispositivos é: ipsw appstore device ls -p CAMINHO_PARA_ARQUIVO_P8 -i ID_DO_EMITENTE -k CHAVE_ID

Saída do comando IPSW appstore device ls listando dispositivos registrados por UDID, nome e plataforma

perfil

O subcomando appstore fornece o subcomando profile, que permite gerenciar perfis de provisionamento. Podemos listar, criar, renovar e remover perfis de provisionamento. Esses perfis permitem executar aplicativos com direitos específicos ou certificados de assinatura fora da configuração normal do iOS.

Para listar os perfis de provisionamento: ipsw appstore profile ls -p CAMINHO_PARA_ARQUIVO_P8 -i ID_DO_EMITENTE -k CHAVE_ID

Saída do comando IPSW appstore profile ls listando perfis de provisionamento com seus IDs e datas de expiração

Para criar um novo perfil de provisionamento, precisamos passar:

  • O nome do perfil de provisionamento
  • ID do certificado para o novo perfil de provisionamento
  • ID do dispositivo para o qual esse novo perfil de provisionamento será relacionado

comando: ipsw appstore profile create NOME -c ID_DO_CERTIFICADO -d ID_DO_DISPOSITIVO -p CAMINHO_PARA_ARQUIVO_P8 -i ID_DO_EMITENTE -k CHAVE_ID

Comando IPSW appstore profile create gerando um novo perfil de provisionamento

Se a solicitação for bem-sucedida, o perfil será escrito no arquivo NOME.mobileprovision. Para confirmar que criamos o perfil, vamos emitir outro comando profile ls.

Saída do comando IPSW appstore profile ls confirmando o novo perfil de provisionamento

Para remover o perfil, basta passar o nome do perfil para ipsw appstore profile rm com a opção -n.

comando: ipsw appstore profile rm -n 8ksec -p CAMINHO_PARA_ARQUIVO_P8 -i ID_DO_EMITENTE -k CHAVE_ID

token

Finalmente, podemos gerar um token JWT para usar com a API do App Store Connect.

comando: ipsw appstore token -p CAMINHO_PARA_ARQUIVO_P8 -i ID_DO_EMITENTE -k CHAVE_ID

Comando IPSW appstore token gerando um token JWT para autenticação na API do App Store Connect

lista-de-dispositivos

O segundo subcomando principal que o ipsw oferece é device-list. Ele permite ver a lista de todos os dispositivos iOS, suas arquiteturas e CPUs.

Saída do comando IPSW device list mostrando dispositivos iOS/macOS conectados com seus identificadores

diff

O terceiro comando principal está relacionado à comparação (diff) de dois arquivos ipsw. Os arquivos ipsw são basicamente arquivos de firmware e podemos usar o comando diff para encontrar diferenças entre dois arquivos ipsw. Isso pode ser útil, por exemplo, se uma vulnerabilidade foi corrigida e não sabemos os detalhes exatos, isso pode nos apontar na direção certa.

Vamos usar os arquivos iPhone 15 17.0.2 e iPhone 15 17.0.3.

comando: ipsw diff ~/Downloads/iPhone15,4_17.0.2_21A350_Restore.ipsw ~/Downloads/iPhone15,4_17.0.3_21A360_Restore.ipsw

Saída do comando IPSW diff mostrando opções para comparar dois arquivos IPSW

Após executar o comando, podemos ver que ele verifica várias categorias diferentes, como dyld_shared_cache, entitlements, etc.

A algumas linhas abaixo, podemos ver algumas mudanças reais.

Saída do IPSW diff mostrando diferenças entre dois builds de IPSW com arquivos alterados destacados

download

O quarto subcomando permite que baixemos uma grande variedade de coisas, como sistemas operacionais (OSs), arquivos IPAs, arquivos IPSW, instaladores do macOS e muito mais. Podemos usar esse comando para navegar por várias páginas da web para fazer o download ou visualizar itens, em vez disso, podemos fazê-lo diretamente pelo terminal.

Saída do comando IPSW download mostrando subcomandos de download para arquivos IPSW, OTA e outros firmwares

appledb

Este subcomando permite que baixemos os arquivos IPSWs diretamente do appledb.

comando: ipsw download appledb --os iOS --version '17.0.3' --device iPhone15,2 --kernel

Saída do comando IPSW download appledb listando firmware disponíveis no banco de dados AppleDB

Saída do comando IPSW download appledb ls mostrando entradas de firmware com números de build e URLs

dev

O subcomando dev permite que você baixe arquivos IPSWs, sistemas operacionais (OSs), Xcode e muito mais do site https://developer.apple.com/download.

comando: ipsw download dev

Digitar o comando acima fornecerá uma lista de itens que você deseja baixar, tornando fácil a seleção.

Saída do comando IPSW download dev mostrando firmware beta disponível para download

macos

Outro subcomando útil para ipsw download é o macos, que permite baixar instaladores do macOS.

Saída do comando IPSW download macos listando arquivos IPSW do macOS disponíveis para download

O subcomando ipsw download oferece outras opções como git, ipa, mas deixaremos de lado essas para manter espaço para os outros comandos.

dtree

Este comando permite que analisemos o DeviceTree. O DeviceTree é uma representação do hardware usada pelos carregadores de inicialização para fornecer ao kernel um mapeamento do hardware.

Para analisar o DeviceTree, precisamos primeiro ter um e podemos usar ipsw extract para extrair o DeviceTree do arquivo IPSW.

Comando IPSW extract dtree extraído do kernelcache

Uma vez que tenhamos extraído o DeviceTree, podemos analisá-lo com ipsw dtree.

comando: ipsw dtree PATH_TO_DEVICE_TREE_FILE

Saída do comando IPSW dtree exibindo a estrutura de DeviceTree analisada com propriedades de hardware

dyld

O subcomando dyld fornece muitas funcionalidades relacionadas ao dyld_shared_cache. Algumas das funcionalidades são:

  • obtendo informações sobre o dyld_shared_cache
  • encontrando quais dylibs importam outro dylib
  • extração do dyld_shared_cache
  • pesquisa de string dentro do dyld_shared_cache
  • e muito mais

Odyld significa carregador dinâmico e sua função é carregar as bibliotecas compartilhadas na memória do processo. Para acelerar o processo de carregamento, todas essas são combinadas em um único arquivo chamado dyld shared cache. Vamos cobrir algumas dessas funcionalidades, pois há muitas delas.

informações

Para obter todas as informações do dyld_shared_cache, podemos simplesmente chamar ipsw dyld info com o caminho para dyld_shared_cache. Também temos algumas opções opcionais, como imprimir apenas dylibs, dlopen closures.

comando: ipsw dyld info CAMINHO_PARA_DYLD_SHARED_CACHE

Saída do comando IPSW dyld info mostrando metadados de dyld_shared_cache, incluindo plataforma e UUID

Também, após algumas informações gerais, podemos ver os dylibs dentro do dyld_shared_cache como pode ser visto na imagem abaixo.

Imagens de saída IPSW dyld info listando todos os arquivos dylib embutidos no dyld_shared_cache

Nós podemos extrair um framework específico para análise adicional do dyld_shared_cache usando o comando ipsw dyld extract.

comando: ipsw dyld extract CAMINHO_PARA_DYLD_SHARED_CACHE DYLIB

No exemplo abaixo, podemos ver a extração do Accelerate.framework.

Comando IPSW dyld extract extraído de um específico dylib do dyld_shared_cache

macho

Este subcomando para ipsw dyld nos permite analisar um específico dylib dentro do arquivo dyld_shared_cache.

comando: ipsw dyld macho CAMINHO_PARA_DYLD_SHARED_CACHE DYLIB

Por exemplo, para obter comandos de carregamento do Accelerate.framework, podemos fazer:

Saída do comando IPSW dyld macho mostrando informações da header Mach-O para um arquivo image em dyld_shared_cache

importações

Para ver quais dylibs carregam um específico dylib, podemos usar o comando ipsw dyld imports. Digamos que tenhamos encontrado uma vulnerabilidade em um específico dylib e queremos verificar quais outros frameworks/dylibs importam isso, podemos usar este comando.

comando: ipsw dyld imports CAMINHO_PARA_DYLD_SHARED_CACHE DYLIB

Saída do IPSW dyld imports listando todos os dylibs importados por um framework específico no cache compartilhado

Aqui podemos ver quais dylibs estão carregando o Accelerate.framework.

objc

Nós podemos coletar informações Objective C dos dylibs usando ipsw dyld objc. Podemos usá-lo para imprimir classes, protocolos, seletores ou imp-caches para dyld_shared_cache. Este comando é útil se quisermos ver algumas classes/funcionalidades dentro de PrivateFrameworks.

Para despejar todas as classes, podemos usar ipsw dyld objc --class CAMINHO_PARA_DYLD_SHARED_CACHE

Saída do comando IPSW dyld objc listando classes e protocolos Objective-C de um arquivo image em dyld_shared_cache

dividir

Nós podemos dividir o dyld_shared_cache usando ipsw dyld split, que nos permite ver tudo dentro do dyld_shared_cache. Vamos discutir a divisão de dyld_shared_cache no macOS Ventura.

No macOS Ventura, o dyld_shared_cache está armazenado na localização de /System/Cryptexes/OS/System/Library/dyld/.

Saída do terminal mostrando a localização do sistema de arquivos do dyld_shared_cache no macOS Ventura

Para fazer isso, precisamos apenas passar o caminho para o arquivo dyld_shared_cache e opcionalmente a saída do caminho. Como podemos lembrar anteriormente, nossos arquivos de dyld_shared_cache estão armazenados em /System/Cryptexes/OS/System/Library/dyld/ e usaremos um dyld_shared_cache_arm64e.

comando: ipsw dyld split /System/Cryptexes/Os/System/Library/dyld/dyld_shared_cache_arm64e /tmp/8ksec.

Comando do terminal extraído de uma biblioteca dinâmica do macOS local usando IPSW

Depois de alguns segundos, podemos examinar a pasta de saída para ver o que está dentro.

Terminal mostrando a análise do arquivo de saída extraído da biblioteca dinâmica dyld_shared_cache

Podemos ver muitas pastas interessantes como PrivateFrameworks e Frameworks. Agora, por exemplo, podemos ver os símbolos exportados de um desses frameworks, digamos CalendarWidget.framework, usando nm -Ug seguido pelo caminho para a biblioteca compartilhada CalendarWidget.

Saída do IPSW mostrando símbolos extraídos da biblioteca dinâmica do widget de calendário no cache compartilhado

str

ipsw dyld str nos permite procurar por padrões específicos de string dentro dos arquivos dyld_shared_cache. Isso é útil quando queremos verificar, por exemplo, onde uma determinada string é usada/referenciada.

comando: ipsw str CAMINHO_PARA_DYLD_SHARED_CACHE -p “REGEX PATTERN”

Saída do comando IPSW dyld str procurando por strings dentro de uma imagem dyld_shared_cache

Como pode ser visto na imagem acima, há muitos casos onde a string world está presente. Também podemos ver o nome do framework onde o padrão foi encontrado.

ent

ipsw ent nos permite procurar por permissões específicas dentro de um IPSW, fazer uma comparação de permissões entre dois arquivos IPSW diferentes e também despejar permissões para um arquivo MachO específico. Isso pode ser útil se quisermos saber todos os binários que contêm uma determinada permissão ou queremos ver as mudanças entre dois arquivos IPSW diferentes.

Para fazer a busca por uma permissão específica, digamos com.apple.developer.carplay-audio, o comando seria assim:

comando: ipsw ent -e com.apple.developer.carplay-audio CAMINHO_PARA_ARQUIVO_IPSW

Saída do comando IPSW ent search procurando por permissões em todos os binários de um arquivo IPSW

diff

A opção diff nos permite ver as diferenças nas permissões entre dois arquivos IPSW.

comando: ipsw ent --diff CAMINHO_PARA_PRIMEIRO_IPSW CAMINHO_PARA_SEGUNDO_IPSW

Saída do comando IPSW ent diff comparando mudanças de permissões entre duas builds iOS

info

O comando ipsw info nos permite ver informações sobre um arquivo IPSW ou OTA. Podemos usar este comando se quisermos saber a versão do chip ou iOS para o arquivo IPSW específico ou OTA. Podemos fazer a verificação em arquivos locais, ou podemos passar a URL com a bandeira -r para análise de um arquivo remoto.

comando para arquivo local: ipsw info CAMINHO_PARA_ARQUIVO_IPSW_OTA comando para remoto: ipsw info -r URL

Saída do comando IPSW info exibindo metadados sobre um arquivo IPSW, incluindo número de build e suporte ao dispositivo

mdevs

ipsw mdevs nos permite ver todos os dispositivos móveis dentro de um arquivo IPSW específico.

comando: ipsw mdevs CAMINHO_PARA_IPSW

Saída do comando IPSW mdevs listando todos os dispositivos Apple suportados por um determinado arquivo IPSW

mount

O comando ipsw mount nos permite montar a parte específica de um arquivo IPSW. Essas partes são fs (filesystem), sys (system) ou app (library). Podemos querer usar este comando se quisermos ver exatamente o que está dentro do arquivo IPSW e fazer uma análise/revisão específica, por exemplo, de uma determinada biblioteca dinâmica.

comando: ipsw mount [fs|sys|app] CAMINHO_PARA_ARQUIVO_IPSW

No próximo par de imagens podemos ver o montagem fs (filesystem) e o que está dentro dele.

Agora, vamos montar o sys (sistema) e verificar seu conteúdo.

Comando IPSW mount sys para montar a partição do sistema de um arquivo IPSW

Terminal mostrando o diretório da partição do sistema iOS montada após executar ipsw mount sys

Finalmente, vamos montar app.

Comando IPSW mount app para montar a partição de aplicativos de um arquivo IPSW

Terminal mostrando o diretório da partição de aplicativos iOS montada após executar ipsw mount app

plist

O comando ipsw plist nos permite despejar o arquivo .plist como json ou, por exemplo, observar alterações em arquivos plist dentro de um diretório específico. Digamos que estamos analisando um aplicativo e queremos saber quando e o que gera uma opção específica dentro do arquivo plist.

file

Nos podemos passar o caminho para o arquivo plist e ele será interpretado como json.

comando: ipsw plist CAMINHO_DO_ARQUIVO_PLIST

Comando IPSW plist file exibindo a leitura de um arquivo plist de um IPSW ou sistema de arquivos montado

Também podemos passar a saída desse comando para jq para obter, por exemplo, o identificador do bundle.

Saída do comando IPSW plist file encadeada com jq para exibir em JSON formatado uma propriedade de list

watch

Também podemos usar ipsw plist para observar alterações em um diretório específico dentro de arquivos plist. Isso é útil quando queremos rastrear o que está mudando no arquivo plist enquanto trabalhamos com o aplicativo.

comando: ipsw plist -w CAMINHO_DO_DIRETÓRIO

Comando IPSW plist watch monitorando alterações em arquivos plist de um dispositivo conectado

atualizar

O ipsw nos fornece uma maneira conveniente de atualizá-lo executando o comando ipsw update, que então permite baixar a nova versão para nosso sistema operacional e arquitetura específicos.

comando: ipsw update

Saída do comando IPSW update mostrando a versão atual da ferramenta ipsw antes de atualizar

Após o download ser concluído, podemos extrair o arquivo zip, verificar nossa versão e ver se estamos realmente executando a versão mais recente executando ipsw update dentro do pacote baixado.

Saída do comando IPSW update confirmando que a ferramenta foi atualizada para a versão mais recente

watch

O comando ipsw watch é aquele que não está estritamente relacionado a iOS ou macOS, mas sim à observação de um repositório específico do GitHub para alterações. Podemos observar arquivos modificados ou talvez padrões dentro das mensagens de commit e ser notificado sobre as mudanças no Discord.

No próximo artigo, vamos olhar para alguns usos adicionais do ipsw para pesquisas em segurança *OS.

Fonte original

Conteúdo traduzido e adaptado pela redação do Notícias Mobile. Confira também a matéria na fonte original.

Leia a matéria completa