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.

App Store
O appstore é o primeiro comando que a ferramenta ipsw fornece e permite interagir com a 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.

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

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

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’.

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

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.

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

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

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

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.

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

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.

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

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.

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.

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


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.

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

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.

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

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

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

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.

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:

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

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

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/.

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.

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

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.

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”

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.
search
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

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

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

mdevs
ipsw mdevs nos permite ver todos os dispositivos móveis dentro de um arquivo IPSW específico.
comando: ipsw mdevs CAMINHO_PARA_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.


Finalmente, vamos montar 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

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

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

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

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.

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.

