hacktricks/mobile-pentesting/ios-pentesting/README.md
2023-06-06 18:56:34 +00:00

1140 lines
67 KiB
Markdown

# iOS Pentesting
![](../.gitbook/assets/image%20\(9\)%20\(1\)%20\(2\).png)
\
Use [**Trickest**](https://trickest.io/) para construir e automatizar facilmente fluxos de trabalho com as ferramentas da comunidade mais avançadas do mundo.\
Acesse hoje:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
## Conceitos básicos do iOS
{% content-ref url="ios-basics.md" %}
[ios-basics.md](ios-basics.md)
{% endcontent-ref %}
## Ambiente de teste
Nesta página, você pode encontrar informações sobre o **simulador iOS**, **emuladores** e **jailbreaking**:
{% content-ref url="ios-testing-environment.md" %}
[ios-testing-environment.md](ios-testing-environment.md)
{% endcontent-ref %}
## Análise inicial
### Operações básicas de teste do iOS
Durante o teste, **várias operações serão sugeridas** (conectar ao dispositivo, ler/escrever/fazer upload/baixar arquivos, usar algumas ferramentas...). Portanto, se você não sabe como executar nenhuma dessas ações, **comece lendo a página**:
{% content-ref url="basic-ios-testing-operations.md" %}
[basic-ios-testing-operations.md](basic-ios-testing-operations.md)
{% endcontent-ref %}
{% hint style="info" %}
Para os seguintes passos, **o aplicativo deve estar instalado** no dispositivo e o arquivo **IPA do aplicativo** já deve ter sido obtido.\
Leia a página [Operações básicas de teste do iOS](basic-ios-testing-operations.md) para aprender como fazer isso.
{% endhint %}
### Análise estática básica
Recomenda-se usar a ferramenta [**MobSF**](https://github.com/MobSF/Mobile-Security-Framework-MobSF) para realizar uma Análise Estática automática do arquivo IPA.
Identificação de **proteções presentes no binário**:
* **PIE (Position Independent Executable)**: Quando ativado, o aplicativo é carregado em um endereço de memória aleatório toda vez que é iniciado, tornando mais difícil prever seu endereço de memória inicial.
```
otool -hv <app-binary> | grep PIE # Deve incluir a flag PIE
```
* **Stack Canaries**: Para validar a integridade da pilha, um valor 'canary' é colocado na pilha antes de chamar uma função e é validado novamente quando a função termina.
```
otool -I -v <app-binary> | grep stack_chk # Deve incluir os símbolos: stack_chk_guard e stack_chk_fail
```
* **ARC (Automatic Reference Counting)**: Para evitar falhas comuns de corrupção de memória
```
otool -I -v <app-binary> | grep objc_release # Deve incluir o símbolo _objc_release
```
* **Binário criptografado**: O binário deve estar criptografado
```
otool -arch all -Vl <app-binary> | grep -A5 LC_ENCRYPT # O cryptid deve ser 1
```
**Identificação de funções sensíveis/inseguras**
* **Algoritmos de hash fracos**
```
# No dispositivo iOS
otool -Iv <app> | grep -w "_CC_MD5"
otool -Iv <app> | grep -w "_CC_SHA1"
# No linux
grep -iER "_CC_MD5"
grep -iER "_CC_SHA1"
```
* **Funções randômicas inseguras**
```
# No dispositivo iOS
otool -Iv <app> | grep -w "_random"
otool -Iv <app> | grep -w "_srand"
otool -Iv <app> | grep -w "_rand"
# No linux
grep -iER "_random"
grep -iER "_srand"
grep -iER "_rand"
```
* **Função 'Malloc' insegura**
```
# No dispositivo iOS
otool -Iv <app> | grep -w "_malloc"
# No linux
grep -iER "_malloc"
```
* **Funções inseguras e vulneráveis**
```
# No dispositivo iOS
otool -Iv <app> | grep -w "_gets"
otool -Iv <app> | grep -w "_memcpy"
otool -Iv <app> | grep -w "_strncpy"
otool -Iv <app> | grep -w "_strlen"
otool -Iv <app> | grep -w "_vsnprintf"
otool -Iv <app> | grep -w "_sscanf"
otool -Iv <app> | grep -w "_strtok"
otool -Iv <app> | grep -w "_alloca"
otool -Iv <app> | grep -w "_sprintf"
otool -Iv <app> | grep -w "_printf"
otool -Iv <app> | grep -w "_vsprintf"
# No linux
grep -R "_gets"
grep -iER "_memcpy"
grep -iER "_strncpy"
grep -iER "_strlen"
grep -iER "_vsnprintf"
grep -iER "_sscanf"
grep -iER "_strtok"
grep -iER "_alloca"
grep -iER "_sprintf"
grep -iER "_printf"
grep -iER "_vsprintf"
```
### Análise dinâmica básica
Confira a análise dinâmica que o [**MobSF**](https://github.com/MobSF/Mobile-Security-Framework-MobSF) realiza. Você precisará navegar pelas diferentes visualizações e interagir com elas, mas ele estará conectando várias classes para fazer outras coisas e preparará um relatório quando você terminar.
### Listando aplicativos instalados
Ao direcionar aplicativos instalados no dispositivo, você primeiro terá que descobrir o identificador de pacote correto do aplicativo que deseja analisar. Você pode usar `frida-ps -Uai` para obter todos os aplicativos (`-a`) atualmente instalados (`-i`) no dispositivo USB conectado (`-U`):
```bash
$ frida-ps -Uai
PID Name Identifier
---- ------------------- -----------------------------------------
6847 Calendar com.apple.mobilecal
6815 Mail com.apple.mobilemail
- App Store com.apple.AppStore
- Apple Store com.apple.store.Jolly
- Calculator com.apple.calculator
- Camera com.apple.camera
- iGoat-Swift OWASP.iGoat-Swift
```
### Enumeração Básica e Hooking
Aprenda como **enumerar os componentes do aplicativo** e como facilmente **hookar métodos e classes** com o Objection:
{% content-ref url="ios-hooking-with-objection.md" %}
[ios-hooking-with-objection.md](ios-hooking-with-objection.md)
{% endcontent-ref %}
### Estrutura IPA
Os arquivos `.ipa` são **pacotes zipados**, então você pode mudar a extensão para `.zip` e **descompactá-los**. Um aplicativo **completo** e **empacotado**, pronto para ser instalado, é comumente referido como um **Bundle**.\
Depois de descompactá-los, você deve ver `<NOME>.app`, um arquivo zipado que contém o restante dos recursos.
* `Info.plist`: Um arquivo que contém algumas das configurações específicas do aplicativo.
* `_CodeSignature/` contém um arquivo plist com uma assinatura sobre todos os arquivos no pacote.
* `Assets.car`: Outro arquivo zipado que contém recursos (ícones).
* `Frameworks/` contém as bibliotecas nativas do aplicativo como arquivos .dylib ou .framework.
* `PlugIns/` pode conter extensões de aplicativos como arquivos .appex (não presentes no exemplo).
* [`Core Data`](https://developer.apple.com/documentation/coredata): É usado para salvar os dados permanentes do seu aplicativo para uso offline, para armazenar dados temporários e para adicionar funcionalidade de desfazer ao seu aplicativo em um único dispositivo. Para sincronizar dados em vários dispositivos em uma única conta do iCloud, o Core Data espelha automaticamente seu esquema em um contêiner do CloudKit.
* [`PkgInfo`](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/ConfigApplications.html): O arquivo `PkgInfo` é uma maneira alternativa de especificar os códigos de tipo e criador do seu aplicativo ou pacote.
* **en.lproj, fr.proj, Base.lproj**: São os pacotes de idiomas que contêm recursos para esses idiomas específicos e um recurso padrão caso um idioma não seja suportado.
Existem várias maneiras de definir a interface do usuário em um aplicativo iOS: arquivos _storyboard_, _nib_ ou _xib_.
**Info.plist**
A lista de propriedades de informações ou `Info.plist` é a principal fonte de informações para um aplicativo iOS. Consiste em um arquivo estruturado contendo pares de **chave-valor** que descrevem informações de configuração essenciais sobre o aplicativo. Na verdade, todos os executáveis empacotados (extensões de aplicativos, estruturas e aplicativos) **devem ter** um arquivo `Info.plist`. Você pode encontrar todas as chaves possíveis na [**Documentação do Desenvolvedor da Apple**](https://developer.apple.com/documentation/bundleresources/information\_property\_list?language=objc).
O arquivo pode ser formatado em **XML ou binário (bplist)**. Você pode **convertê-lo para o formato XML** com um único comando:
* No macOS com `plutil`, que é uma ferramenta que vem nativamente com o macOS 10.2 e versões superiores (não há documentação oficial online disponível no momento):
```bash
$ plutil -convert xml1 Info.plist
```
* No Linux:
```bash
$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist
```
Aqui está uma lista não exaustiva de algumas informações e as palavras-chave correspondentes que você pode facilmente procurar no arquivo `Info.plist` apenas inspecionando o arquivo ou usando `grep -i <palavra-chave> Info.plist`:
* Strings de propósito de permissões do aplicativo: `UsageDescription`
* Esquemas de URL personalizados: `CFBundleURLTypes`
* Tipos de documentos personalizados exportados/importados: `UTExportedTypeDeclarations` / `UTImportedTypeDeclarations`
* Configuração de Segurança de Transporte de Aplicativo (ATS): `NSAppTransportSecurity`
Consulte os capítulos mencionados para aprender mais sobre como testar cada um desses pontos.
**Caminhos de Dados**
No iOS, **os aplicativos do sistema podem ser encontrados no diretório `/Applications`** enquanto os aplicativos **instalados pelo usuário** estão disponíveis em **`/private/var/containers/`**. No entanto, encontrar a pasta certa apenas navegando no sistema de arquivos não é uma tarefa trivial, pois **cada aplicativo recebe um UUID (Identificador Único Universal) de 128 bits aleatório** atribuído para seus nomes de diretório.
Para obter facilmente as informações do diretório de instalação para aplicativos instalados pelo usuário, você pode usar o comando **`env` do Objection** que também mostrará todas as informações de diretório do aplicativo:
```bash
OWASP.iGoat-Swift on (iPhone: 11.1.2) [usb] # env
Name Path
----------------- -------------------------------------------------------------------------------------------
BundlePath /var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app
CachesDirectory /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Library/Caches
DocumentDirectory /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Documents
LibraryDirectory /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Library
```
Como você pode ver, os aplicativos têm dois locais principais:
* O **diretório Bundle** (`/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/`).
* O **diretório de dados** (`/var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/`).
Essas pastas contêm informações que devem ser examinadas de perto durante as avaliações de segurança do aplicativo (por exemplo, ao analisar os dados armazenados em busca de dados sensíveis).
**Diretório Bundle:**
* **AppName.app**
* Este é o Pacote de Aplicativos, como visto antes no IPA, ele contém dados essenciais do aplicativo, conteúdo estático e o binário compilado do aplicativo.
* Este diretório é visível para os usuários, mas **os usuários não podem escrever nele**.
* O conteúdo deste diretório **não é copiado**.
* O conteúdo desta pasta é usado para **validar a assinatura do código**.
**Diretório de dados:**
* **Documents/**
* Contém todos os dados gerados pelo usuário. O usuário final do aplicativo inicia a criação desses dados.
* Visível para os usuários e **os usuários podem escrever nele**.
* O conteúdo deste diretório é **copiado**.
* O aplicativo pode desabilitar caminhos definindo `NSURLIsExcludedFromBackupKey`.
* **Library/**
* Contém todos os **arquivos que não são específicos do usuário**, como **caches**, **preferências**, **cookies** e arquivos de configuração de lista de propriedades (plist).
* Os aplicativos iOS geralmente usam os subdiretórios `Application Support` e `Caches`, mas o aplicativo pode criar subdiretórios personalizados.
* **Library/Caches/**
* Contém arquivos em cache **semi-permanentes**.
* Invisível para os usuários e **os usuários não podem escrever nele**.
* O conteúdo deste diretório **não é copiado**.
* O sistema operacional pode excluir automaticamente os arquivos deste diretório quando o aplicativo não está em execução e o espaço de armazenamento está baixo.
* **Library/Application Support/**
* Contém **arquivos persistentes** necessários para executar o aplicativo.
* **Invisível** **para** **os usuários** e os usuários não podem escrever nele.
* O conteúdo deste diretório é **copiado**.
* O aplicativo pode desabilitar caminhos definindo `NSURLIsExcludedFromBackupKey`.
* **Library/Preferences/**
* Usado para armazenar propriedades que podem **persistir mesmo depois que um aplicativo é reiniciado**.
* As informações são salvas, sem criptografia, dentro do sandbox do aplicativo em um arquivo plist chamado \[BUNDLE\_ID].plist.
* Todos os pares chave/valor armazenados usando `NSUserDefaults` podem ser encontrados neste arquivo.
* **tmp/**
* Use este diretório para gravar **arquivos temporários** que não precisam persistir entre os lançamentos do aplicativo.
* Contém arquivos em cache não persistentes.
* **Invisível** para os usuários.
* O conteúdo deste diretório não é copiado.
* O sistema operacional pode excluir automaticamente os arquivos deste diretório quando o aplicativo não está em execução e o espaço de armazenamento está baixo.
Vamos dar uma olhada mais de perto no diretório de Pacote de Aplicativos (.app) do iGoat-Swift dentro do diretório Bundle (`/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app`):
```bash
OWASP.iGoat-Swift on (iPhone: 11.1.2) [usb] # ls
NSFileType Perms NSFileProtection ... Name
------------ ------- ------------------ ... --------------------------------------
Regular 420 None ... rutger.html
Regular 420 None ... mansi.html
Regular 420 None ... splash.html
Regular 420 None ... about.html
Regular 420 None ... LICENSE.txt
Regular 420 None ... Sentinel.txt
Regular 420 None ... README.txt
```
### Reversão Binária
Dentro da pasta `<application-name>.app`, você encontrará um arquivo binário chamado `<application-name>`. Este é o arquivo que será **executado**. Você pode realizar uma inspeção básica do binário com a ferramenta **`otool`**:
```bash
otool -Vh DVIA-v2 #Check some compilation attributes
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC_64 ARM64 ALL 0x00 EXECUTE 65 7112 NOUNDEFS DYLDLINK TWOLEVEL WEAK_DEFINES BINDS_TO_WEAK PIE
otool -L DVIA-v2 #Get third party libraries
DVIA-v2:
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.1)
/usr/lib/libsqlite3.dylib (compatibility version 9.0.0, current version 274.6.0)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
@rpath/Bolts.framework/Bolts (compatibility version 1.0.0, current version 1.0.0)
[...]
```
**Verifique se o aplicativo está criptografado**
Verifique se há alguma saída para:
```bash
otool -l <app-binary> | grep -A 4 LC_ENCRYPTION_INFO
```
**Desmontando o binário**
Desmonte a seção de texto:
```bash
otool -tV DVIA-v2
DVIA-v2:
(__TEXT,__text) section
+[DDLog initialize]:
0000000100004ab8 sub sp, sp, #0x60
0000000100004abc stp x29, x30, [sp, #0x50] ; Latency: 6
0000000100004ac0 add x29, sp, #0x50
0000000100004ac4 sub x8, x29, #0x10
0000000100004ac8 mov x9, #0x0
0000000100004acc adrp x10, 1098 ; 0x10044e000
0000000100004ad0 add x10, x10, #0x268
```
Para imprimir o **segmento Objective-C** do aplicativo de exemplo, pode-se usar:
```bash
otool -oV DVIA-v2
DVIA-v2:
Contents of (__DATA,__objc_classlist) section
00000001003dd5b8 0x1004423d0 _OBJC_CLASS_$_DDLog
isa 0x1004423a8 _OBJC_METACLASS_$_DDLog
superclass 0x0 _OBJC_CLASS_$_NSObject
cache 0x0 __objc_empty_cache
vtable 0x0
data 0x1003de748
flags 0x80
instanceStart 8
```
Para obter um código Objective-C mais compacto, você pode usar o [**class-dump**](http://stevenygard.com/projects/class-dump/):
```bash
class-dump some-app
//
// Generated by class-dump 3.5 (64 bit).
//
// class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard.
//
#pragma mark Named Structures
struct CGPoint {
double _field1;
double _field2;
};
struct CGRect {
struct CGPoint _field1;
struct CGSize _field2;
};
struct CGSize {
double _field1;
double _field2;
};
```
No entanto, as melhores opções para desmontar o binário são: [**Hopper**](https://www.hopperapp.com/download.html?) e [**IDA**](https://www.hex-rays.com/products/ida/support/download\_freeware/).
![](../.gitbook/assets/image%20\(9\)%20\(1\)%20\(2\).png)
Use [**Trickest**](https://trickest.io/) para construir e **automatizar fluxos de trabalho** com as ferramentas da comunidade **mais avançadas do mundo**.\
Obtenha acesso hoje:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
## Armazenamento de Dados
Para aprender sobre como o iOS armazena dados no dispositivo, leia esta página:
{% content-ref url="ios-basics.md" %}
[ios-basics.md](ios-basics.md)
{% endcontent-ref %}
{% hint style="warning" %}
Os seguintes locais para armazenar informações devem ser verificados **logo após a instalação do aplicativo**, **após verificar todas as funcionalidades** do aplicativo e até mesmo após **sair de um usuário e entrar em outro**.\
O objetivo é encontrar **informações sensíveis desprotegidas** do aplicativo (senhas, tokens), do usuário atual e de usuários que fizeram login anteriormente.
{% endhint %}
### Plist
Os arquivos **plist** são arquivos XML estruturados que **contêm pares de chave-valor**. É uma maneira de armazenar dados persistentes, então às vezes você pode encontrar **informações sensíveis nesses arquivos**. É recomendável verificar esses arquivos após a instalação do aplicativo e após o uso intensivo para ver se novos dados são gravados.
A maneira mais comum de persistir dados em arquivos plist é por meio do uso de **NSUserDefaults**. Este arquivo plist é salvo dentro do sandbox do aplicativo em **`Library/Preferences/<appBundleID>.plist`**
A classe [`NSUserDefaults`](https://developer.apple.com/documentation/foundation/nsuserdefaults) fornece uma interface programática para interagir com o sistema padrão. O sistema padrão permite que um aplicativo personalize seu comportamento de acordo com as **preferências do usuário**. Os dados salvos pelo `NSUserDefaults` podem ser visualizados no pacote do aplicativo. Esta classe armazena **dados** em um **arquivo plist**, mas é destinada a ser usada com pequenas quantidades de dados.
Esses dados não podem ser mais acessados diretamente por um computador confiável, mas podem ser acessados realizando um **backup**.
Você pode **despejar** as informações salvas usando **`NSUserDefaults`** usando o `ios nsuserdefaults get` do objection.
Para encontrar todos os arquivos plist usados pelo aplicativo, você pode acessar `/private/var/mobile/Containers/Data/Application/{APPID}` e executar:
```bash
find ./ -name "*.plist"
```
O arquivo pode estar formatado em **XML ou binário (bplist)**. Você pode **convertê-lo para o formato XML** com um comando simples:
* No macOS com `plutil`, que é uma ferramenta que vem nativamente com o macOS 10.2 e versões superiores (não há documentação oficial online disponível no momento):
```bash
$ plutil -convert xml1 Info.plist
```
* No Linux:
```bash
$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist
```
* Em uma sessão do Objection:
```bash
ios plist cat /private/var/mobile/Containers/Data/Application/AF1F534B-1B8F-0825-ACB21-C0301AB7E56D/Library/Preferences/com.some.package.app.plist
```
### Core Data
[`Core Data`](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/nsfetchedresultscontroller.html#//apple\_ref/doc/uid/TP40001075-CH8-SW1) é um framework para gerenciar a camada de modelo de objetos em seu aplicativo. [Core Data pode usar o SQLite como seu armazenamento persistente](https://cocoacasts.com/what-is-the-difference-between-core-data-and-sqlite/), mas o próprio framework não é um banco de dados.\
CoreData não criptografa seus dados por padrão. No entanto, uma camada adicional de criptografia pode ser adicionada ao CoreData. Consulte o [Repositório do GitHub](https://github.com/project-imas/encrypted-core-data) para mais detalhes.
Você pode encontrar as informações do SQLite Core Data de um aplicativo no caminho `/private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support`
**Se você puder abrir o SQLite e acessar informações sensíveis, encontrou uma configuração incorreta.**
{% code title="Código do iGoat" %}
```objectivec
-(void)storeDetails {
AppDelegate * appDelegate = (AppDelegate *)(UIApplication.sharedApplication.delegate);
NSManagedObjectContext *context =[appDelegate managedObjectContext];
User *user = [self fetchUser];
if (user) {
return;
}
user = [NSEntityDescription insertNewObjectForEntityForName:@"User"
inManagedObjectContext:context];
user.email = CoreDataEmail;
user.password = CoreDataPassword;
NSError *error;
if (![context save:&error]) {
NSLog(@"Error in saving data: %@", [error localizedDescription]);
}else{
NSLog(@"data stored in core data");
}
}
```
{% endcode %}
### YapDatabase
[YapDatabase](https://github.com/yapstudios/YapDatabase) é um armazenamento de chave/valor construído em cima do SQLite.\
Como os bancos de dados Yap são bancos de dados SQLite, você pode encontrá-los usando o comando proposto na seção anterior.
### Outros bancos de dados SQLite
É comum que os aplicativos criem seus próprios bancos de dados SQLite. Eles podem estar armazenando dados sensíveis neles e deixando-os sem criptografia. Portanto, é sempre interessante verificar todos os bancos de dados dentro do diretório de aplicativos. Para isso, vá para o diretório do aplicativo onde os dados são salvos (`/private/var/mobile/Containers/Data/Application/{APPID}`)
```bash
find ./ -name "*.sqlite" -or -name "*.db"
```
### Bancos de dados em tempo real do Firebase
Os desenvolvedores de aplicativos podem aproveitá-lo para **armazenar e sincronizar dados com um banco de dados hospedado na nuvem NoSQL**. Os dados são armazenados como JSON e são sincronizados em tempo real para cada cliente conectado e também permanecem disponíveis mesmo quando o aplicativo fica offline.
Você pode descobrir como verificar bancos de dados do Firebase mal configurados aqui:
{% content-ref url="../../network-services-pentesting/pentesting-web/buckets/firebase-database.md" %}
[firebase-database.md](../../network-services-pentesting/pentesting-web/buckets/firebase-database.md)
{% endcontent-ref %}
### Bancos de dados Realm
[Realm Objective-C](https://realm.io/docs/objc/latest/) e [Realm Swift](https://realm.io/docs/swift/latest/) não são fornecidos pela Apple, mas ainda valem a pena serem mencionados. Eles **armazenam tudo sem criptografia, a menos que a configuração tenha a criptografia habilitada**.
Você pode encontrar esses bancos de dados em `/private/var/mobile/Containers/Data/Application/{APPID}`.
```bash
iPhone:/private/var/mobile/Containers/Data/Application/A079DF84-726C-4AEA-A194-805B97B3684A/Documents root# ls
default.realm default.realm.lock default.realm.management/ default.realm.note|
$ find ./ -name "*.realm*"
```
Você pode usar a ferramenta [**Realm Studio**](https://github.com/realm/realm-studio) para abrir esses arquivos de banco de dados.
O exemplo a seguir demonstra como usar a criptografia com um banco de dados Realm:
```swift
// Open the encrypted Realm file where getKey() is a method to obtain a key from the Keychain or a server
let config = Realm.Configuration(encryptionKey: getKey())
do {
let realm = try Realm(configuration: config)
// Use the Realm as normal
} catch let error as NSError {
// If the encryption key is wrong, `error` will say that it's an invalid database
fatalError("Error opening realm: \(error)")
}
```
### Bancos de Dados Couchbase Lite
O [Couchbase Lite](https://github.com/couchbase/couchbase-lite-ios) é um motor de banco de dados leve, incorporado e orientado a documentos (NoSQL) que pode ser sincronizado. Ele é compilado nativamente para iOS e macOS.
Verifique possíveis bancos de dados couchbase em `/private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support/`
### Cookies
O iOS armazena os cookies dos aplicativos no arquivo **`Library/Cookies/cookies.binarycookies`** dentro da pasta de cada aplicativo. No entanto, os desenvolvedores às vezes decidem salvá-los no **keychain** já que o mencionado **arquivo de cookie pode ser acessado em backups**.
Para inspecionar o arquivo de cookies, você pode usar [**este script python**](https://github.com/mdegrazia/Safari-Binary-Cookie-Parser) ou usar o comando **`ios cookies get`** do Objection.\
**Você também pode usar o Objection para** converter esses arquivos para um formato JSON\*\* e inspecionar os dados.
```bash
...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # ios cookies get --json
[
{
"domain": "highaltitudehacks.com",
"expiresDate": "2051-09-15 07:46:43 +0000",
"isHTTPOnly": "false",
"isSecure": "false",
"name": "username",
"path": "/",
"value": "admin123",
"version": "0"
}
]
```
### Cache
Por padrão, o NSURLSession armazena dados, como **solicitações e respostas HTTP no banco de dados Cache.db**. Este banco de dados pode conter **dados sensíveis**, se tokens, nomes de usuário ou qualquer outra informação sensível tiver sido armazenada em cache. Para encontrar as informações armazenadas em cache, abra o diretório de dados do aplicativo (`/var/mobile/Containers/Data/Application/<UUID>`) e vá para `/Library/Caches/<Bundle Identifier>`. O **cache do WebKit também é armazenado no arquivo Cache.db**. O **Objection** pode abrir e interagir com o banco de dados com o comando `sqlite connect Cache.db`, pois é um **banco de dados SQLite normal**.
É **recomendado desativar o armazenamento em cache desses dados**, pois eles podem conter informações sensíveis na solicitação ou resposta. A lista abaixo mostra diferentes maneiras de alcançar isso:
1. É recomendado remover as respostas armazenadas em cache após o logout. Isso pode ser feito com o método fornecido pela Apple chamado [`removeAllCachedResponses`](https://developer.apple.com/documentation/foundation/urlcache/1417802-removeallcachedresponses). Você pode chamar esse método da seguinte maneira:
`URLCache.shared.removeAllCachedResponses()`
Este método removerá todas as solicitações e respostas armazenadas em cache do arquivo Cache.db.
2. Se você não precisa usar as vantagens dos cookies, seria recomendado usar apenas a propriedade [.ephemeral](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1410529-ephemeral) da URLSession, que desativará o armazenamento de cookies e caches.
[Documentação da Apple](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1410529-ephemeral):
`Um objeto de configuração de sessão efêmera é semelhante a uma configuração de sessão padrão (consulte padrão), exceto que o objeto de sessão correspondente não armazena caches, lojas de credenciais ou quaisquer dados relacionados à sessão no disco. Em vez disso, os dados relacionados à sessão são armazenados na RAM. A única vez que uma sessão efêmera grava dados no disco é quando você diz a ela para gravar o conteúdo de uma URL em um arquivo.`
3. O cache também pode ser desativado definindo a Política de Cache como [.notAllowed](https://developer.apple.com/documentation/foundation/urlcache/storagepolicy/notallowed). Isso desativará o armazenamento de cache de qualquer maneira, seja na memória ou no disco.
### Snapshots
Sempre que você pressiona o botão home, o iOS **tira uma captura de tela da tela atual** para poder fazer a transição para o aplicativo de maneira mais suave. No entanto, se **dados sensíveis** estiverem presentes na tela atual, eles serão **salvos** na **imagem** (que **persiste** **através** **de** **reinicializações**). Essas são as capturas de tela às quais você também pode acessar tocando duas vezes na tela inicial para alternar entre aplicativos.
A menos que o iPhone esteja com jailbreak, o **atacante** precisa ter **acesso** ao **dispositivo** **desbloqueado** para ver essas capturas de tela. Por padrão, a última captura de tela é armazenada no sandbox do aplicativo na pasta `Library/Caches/Snapshots/` ou `Library/SplashBoard/Snapshots` (os computadores confiáveis não podem acessar o sistema de arquivos a partir do iOS 7.0).
Uma maneira de evitar esse comportamento ruim é colocar uma tela em branco ou remover os dados sensíveis antes de tirar a captura de tela usando a função `ApplicationDidEnterBackground()`.
A seguir, um método de remediação de amostra que definirá uma captura de tela padrão.
Swift:
```swift
private var backgroundImage: UIImageView?
func applicationDidEnterBackground(_ application: UIApplication) {
let myBanner = UIImageView(image: #imageLiteral(resourceName: "overlayImage"))
myBanner.frame = UIScreen.main.bounds
backgroundImage = myBanner
window?.addSubview(myBanner)
}
func applicationWillEnterForeground(_ application: UIApplication) {
backgroundImage?.removeFromSuperview()
}
```
Objective-C:
Objective-C é uma linguagem de programação orientada a objetos utilizada principalmente para desenvolvimento de aplicativos iOS e macOS. É uma extensão da linguagem C, adicionando recursos de orientação a objetos, como herança, polimorfismo e encapsulamento. É uma linguagem de tipagem dinâmica, o que significa que os tipos de dados são verificados em tempo de execução em vez de tempo de compilação. É amplamente utilizado para desenvolvimento de aplicativos iOS e macOS, especialmente antes da introdução da linguagem Swift.
```
@property (UIImageView *)backgroundImage;
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIImageView *myBanner = [[UIImageView alloc] initWithImage:@"overlayImage.png"];
self.backgroundImage = myBanner;
self.backgroundImage.bounds = UIScreen.mainScreen.bounds;
[self.window addSubview:myBanner];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[self.backgroundImage removeFromSuperview];
}
```
Isso define a imagem de fundo como `overlayImage.png` sempre que o aplicativo é colocado em segundo plano. Isso impede vazamentos de dados sensíveis porque `overlayImage.png` sempre substituirá a visualização atual.
### Keychain
Ferramentas como [**Keychain-Dumper**](https://github.com/ptoomey3/Keychain-Dumper) podem ser usadas para despejar o keychain (o dispositivo deve estar com jailbreak).\
Você também pode usar `ios keychain dump` do [**Objection**](https://github.com/sensepost/objection)**.**
**NSURLCredential**
**NSURLCredential** é a classe perfeita para **armazenar nome de usuário e senha no keychain**. Não há necessidade de se preocupar com NSUserDefaults ou qualquer wrapper de keychain.\
Assim que o usuário fizer login, você pode\*\* armazenar\*\* seu nome de usuário e senha no keychain:
```swift
NSURLCredential *credential;
credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistencePermanent];
[[NSURLCredentialStorage sharedCredentialStorage] setCredential:credential forProtectionSpace:self.loginProtectionSpace];
```
Você pode usar o comando `ios nsurlcredentialstorage dump` do **Objection** para extrair esses segredos.
## Teclados Personalizados/Cache do Teclado
A partir do iOS 8.0, a Apple permite a instalação de extensões personalizadas para iOS, como teclados personalizados.\
Os teclados instalados podem ser gerenciados em **Configurações** > **Geral** > **Teclado** > **Teclados**.\
Os teclados personalizados podem ser usados para **capturar** as **teclas digitadas** e enviá-las para o servidor do atacante. No entanto, observe que **os teclados personalizados que exigem conectividade de rede serão notificados ao usuário.**\
Além disso, o **usuário pode mudar para um teclado diferente** (mais confiável) **para inserir as credenciais.**
Além disso, **os aplicativos podem impedir que seus usuários usem teclados personalizados** dentro do aplicativo (ou pelo menos para partes sensíveis do aplicativo).
{% hint style="warning" %}
Recomenda-se não permitir teclados de terceiros se você considerar que os usuários não precisarão deles.
{% endhint %}
Observe que, devido à correção automática e sugestões automáticas, o teclado padrão do iOS capturará e armazenará cada palavra não padrão em um arquivo de cache se o atributo **securetTextEntry** não estiver definido como **true** ou se **autoCorrectionType** não estiver definido como **UITextAutoCorrectionTypeNo.**
Por padrão, os teclados **armazenam esse cache** dentro do sandbox do aplicativo no arquivo `Library/Keyboard/{locale}-dynamic-text.dat` ou em `/private/var/mobile/Library/Keyboard/dynamic-text.dat`. No entanto, pode estar salvando os dados em outro lugar.\
É possível redefinir o cache em _**Configurações**_ > _**Geral**_ > _**Redefinir**_ > _**Redefinir Dicionário do Teclado**_
{% hint style="info" %}
Portanto, **sempre verifique esses arquivos** e procure por possíveis **informações sensíveis**.\
**Interceptar o tráfego de rede** é outra maneira de verificar se o teclado personalizado está enviando as teclas digitadas para um servidor remoto.
{% endhint %}
O protocolo [UITextInputTraits](https://developer.apple.com/reference/uikit/uitextinputtraits) é usado para o cache do teclado. As classes UITextField, UITextView e UISearchBar suportam automaticamente esse protocolo e oferecem as seguintes propriedades:
* `var autocorrectionType: UITextAutocorrectionType` determina se a correção automática está habilitada durante a digitação. Quando a correção automática está habilitada, o objeto de texto rastreia palavras desconhecidas e sugere substituições adequadas, substituindo automaticamente o texto digitado, a menos que o usuário anule a substituição. O valor padrão dessa propriedade é `UITextAutocorrectionTypeDefault`, que para a maioria dos métodos de entrada habilita a correção automática.
* `var secureTextEntry: BOOL` determina se a cópia de texto e o cache de texto estão desativados e oculta o texto digitado para `UITextField`. O valor padrão dessa propriedade é `NO`.
**Para identificar esse comportamento no código:**
* Procure no código-fonte por implementações semelhantes, como
```objectivec
textObject.autocorrectionType = UITextAutocorrectionTypeNo;
textObject.secureTextEntry = YES;
```
* Abra arquivos xib e storyboard no `Interface Builder` do Xcode e verifique os estados de `Secure Text Entry` e `Correction` no `Attributes Inspector` para o objeto apropriado.
A aplicação deve impedir o armazenamento em cache de informações confidenciais inseridas em campos de texto. Você pode impedir o armazenamento em cache desabilitando-o programaticamente, usando a diretiva `textObject.autocorrectionType = UITextAutocorrectionTypeNo` nos UITextFields, UITextViews e UISearchBars desejados. Para dados que devem ser mascarados, como PINs e senhas, defina `textObject.secureTextEntry` como `YES`.
```objectivec
UITextField *textField = [ [ UITextField alloc ] initWithFrame: frame ];
textField.autocorrectionType = UITextAutocorrectionTypeNo;
```
## **Logs**
A forma mais comum de depurar o código é usando logs, e o aplicativo **pode imprimir informações sensíveis dentro dos logs**.\
No iOS versão 6 e abaixo, os logs eram legíveis para todo o mundo (um aplicativo malicioso poderia ler logs de outros aplicativos e extrair informações sensíveis de lá). **Hoje em dia, os aplicativos só podem acessar seus próprios logs**.
No entanto, um **atacante** com **acesso físico** a um dispositivo **desbloqueado** pode conectá-lo a um computador e **ler os logs** (observe que os logs gravados no disco por um aplicativo não são removidos se o aplicativo for desinstalado).
É recomendável **navegar por todas as telas** do aplicativo e **interagir** com **todos** os elementos da interface do usuário e **funcionalidades** e fornecer texto de entrada em todos os campos de texto e **revisar os logs** em busca de **informações** **sensíveis** expostas.
Use as seguintes palavras-chave para verificar o código-fonte do aplicativo em busca de declarações de log pré-definidas e personalizadas:
* Para funções pré-definidas e integradas:
* NSLog
* NSAssert
* NSCAssert
* fprintf
* Para funções personalizadas:
* Logging
* Logfile
**Monitorando os Logs do Sistema**
Muitos aplicativos registram mensagens informativas (e potencialmente sensíveis) no log do console. O log também contém relatórios de falhas e outras informações úteis.
Você pode usar as seguintes ferramentas:
```bash
idevice_id --list # To find the device ID
idevicesyslog -u <id> (| grep <app>) # To get the device logs
```
Você pode coletar logs do console através da janela **Devices** do Xcode da seguinte forma:
1. Inicie o Xcode.
2. Conecte seu dispositivo ao seu computador host.
3. Escolha **Window** -> **Devices and Simulators**.
4. Clique no seu dispositivo iOS conectado na seção esquerda da janela Devices.
5. Reproduza o problema.
6. Clique no botão **Open Console** localizado na área superior direita da janela Devices para visualizar os logs do console em uma janela separada.
![](<../../.gitbook/assets/image (466) (2) (2) (2) (2) (2) (2) (2) (3) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (6).png>)
Você também pode se conectar ao shell do dispositivo conforme explicado em Acessando o Shell do Dispositivo, instalar o **socat** via **apt-get** e executar o seguinte comando:
```bash
iPhone:~ root# socat - UNIX-CONNECT:/var/run/lockdown/syslog.sock
========================
ASL is here to serve you
> watch
OK
Jun 7 13:42:14 iPhone chmod[9705] <Notice>: MS:Notice: Injecting: (null) [chmod] (1556.00)
Jun 7 13:42:14 iPhone readlink[9706] <Notice>: MS:Notice: Injecting: (null) [readlink] (1556.00)
Jun 7 13:42:14 iPhone rm[9707] <Notice>: MS:Notice: Injecting: (null) [rm] (1556.00)
Jun 7 13:42:14 iPhone touch[9708] <Notice>: MS:Notice: Injecting: (null) [touch] (1556.00)
...
```
![](../.gitbook/assets/image%20\(9\)%20\(1\)%20\(2\).png)
Use [**Trickest**](https://trickest.io/) para criar e automatizar facilmente fluxos de trabalho com as ferramentas comunitárias mais avançadas do mundo.\
Obtenha acesso hoje:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
## Backups
O iOS inclui recursos de backup automático que criam cópias dos dados armazenados no dispositivo. Você pode fazer backups do iOS a partir do seu computador host usando o iTunes (até o macOS Catalina) ou o Finder (a partir do macOS Catalina), ou por meio do recurso de backup do iCloud. Em ambos os casos, o backup inclui quase todos os dados armazenados no dispositivo iOS, exceto dados altamente sensíveis, como informações do Apple Pay e configurações do Touch ID.
Uma preocupação óbvia é se dados sensíveis do usuário armazenados pelo aplicativo podem vazar inadvertidamente através do backup. Outra preocupação, embora menos óbvia, é se configurações de proteção de dados ou restrição de funcionalidade do aplicativo poderiam ser adulteradas para alterar o comportamento do aplicativo após a restauração de um backup modificado. Ambas as preocupações são válidas e essas vulnerabilidades têm se mostrado existir em um grande número de aplicativos hoje.
Um backup de um dispositivo em que um aplicativo móvel foi instalado incluirá todos os subdiretórios (exceto `Library/Caches/`) e arquivos no [diretório privado do aplicativo](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple\_ref/doc/uid/TP40010672-CH2-SW12).\
Portanto, evite armazenar dados sensíveis em texto simples em qualquer um dos arquivos ou pastas que estão no diretório privado do aplicativo ou subdiretórios.
Embora todos os arquivos em `Documents/` e `Library/Application Support/` sejam sempre copiados por padrão, você pode [excluir arquivos do backup](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple\_ref/doc/uid/TP40010672-CH2-SW28) chamando `NSURL setResourceValue:forKey:error:` com a chave `NSURLIsExcludedFromBackupKey`.\
Você pode usar as propriedades do sistema de arquivos [NSURLIsExcludedFromBackupKey](https://developer.apple.com/reference/foundation/nsurl#//apple\_ref/c/data/NSURLIsExcludedFromBackupKey) e [CFURLIsExcludedFromBackupKey](https://developer.apple.com/reference/corefoundation/cfurl-rd7#//apple\_ref/c/data/kCFURLIsExcludedFromBackupKey) para excluir arquivos e diretórios de backups.
{% hint style="warning" %}
Portanto, ao verificar o backup de um aplicativo, você deve verificar se **alguma informação sensível** é acessível e se você pode **modificar qualquer comportamento sensível** do aplicativo **modificando alguma configuração do backup** e restaurando o backup.
{% endhint %}
**Como testar**
Comece **criando um backup do dispositivo** (você pode fazer isso usando o Finder) e encontrando onde o backup está armazenado. A documentação oficial da Apple ajudará você a [localizar backups do seu iPhone, iPad e iPod touch](https://support.apple.com/en-us/HT204215).
Depois de encontrar o backup do dispositivo (`/Users/carlos.martin/Library/Application Support/MobileSync/Backup/{deviceID}`), você pode começar a procurar informações sensíveis usando o grep, por exemplo, ou usando ferramentas como [iMazing](https://imazing.com)).
Para identificar se um backup está criptografado, você pode verificar a chave chamada "IsEncrypted" do arquivo "Manifest.plist", localizado na raiz do diretório de backup. O exemplo a seguir mostra uma configuração indicando que o backup está criptografado:
```markup
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
...
<key>Date</key>
<date>2021-03-12T17:43:33Z</date>
<key>IsEncrypted</key>
<true/>
...
</plist>
```
Caso precise trabalhar com um backup criptografado, existem alguns scripts em Python no repositório do GitHub da DinoSec, como o **backup\_tool.py** e o **backup\_passwd.py**, que servirão como um bom ponto de partida. No entanto, observe que eles podem não funcionar com as versões mais recentes do iTunes/Finder e podem precisar ser ajustados.
Você também pode usar a ferramenta [**iOSbackup**](https://pypi.org/project/iOSbackup/) para ler e extrair facilmente arquivos de um backup iOS criptografado com senha.
**Como modificar o comportamento**
No aplicativo de carteira de bitcoin de código aberto, [Bither](https://github.com/bither/bither-ios), é possível configurar um PIN para bloquear a interface do usuário.\
Este PIN é armazenado no arquivo `net.bither.plist` dentro da **chave** **pin\_code**.\
Se você limpar essa chave desse plist no backup e restaurar o backup, poderá acessar a carteira.
## Testando a Memória em Busca de Dados Sensíveis
Em algum momento, informações sensíveis serão armazenadas na memória. O objetivo é garantir que essas informações sejam expostas pelo menor tempo possível.
Para investigar a memória de um aplicativo, primeiro crie um **dump de memória**. Alternativamente, você pode **analisar a memória em tempo real** com, por exemplo, um depurador. Independentemente do método que você usar, este é um processo muito propenso a erros porque os dumps fornecem os dados deixados pelas funções executadas e você pode perder etapas críticas. Além disso, é muito fácil ignorar dados durante a análise, a menos que você conheça a pegada dos dados que está procurando (seja o valor exato ou o formato). Por exemplo, se o aplicativo criptografa de acordo com uma chave simétrica gerada aleatoriamente, é muito improvável que você encontre a chave na memória, a menos que encontre seu valor por outros meios.
**Recuperando e Analisando um Dump de Memória**
Seja usando um dispositivo com ou sem jailbreak, você pode despejar a memória do processo do aplicativo com o [objection](https://github.com/sensepost/objection) e o [Fridump](https://github.com/Nightbringer21/fridump).
Depois que a memória for despejada (por exemplo, em um arquivo chamado "memory"), dependendo da natureza dos dados que você está procurando, você precisará de um conjunto de ferramentas diferentes para processar e analisar esse dump de memória. Por exemplo, se você estiver focando em strings, pode ser suficiente executar o comando `strings` ou `rabin2 -zz` para extrair essas strings.
```bash
# using strings
$ strings memory > strings.txt
# using rabin2
$ rabin2 -ZZ memory > strings.txt
```
Abra o arquivo `strings.txt` no seu editor favorito e procure por informações sensíveis.
No entanto, se você quiser inspecionar outros tipos de dados, é melhor usar o radare2 e suas capacidades de pesquisa. Consulte a ajuda do radare2 no comando de pesquisa (`/?`) para obter mais informações e uma lista de opções. O seguinte mostra apenas um subconjunto delas:
```bash
$ r2 <name_of_your_dump_file>
[0x00000000]> /?
Usage: /[!bf] [arg] Search stuff (see 'e??search' for options)
|Use io.va for searching in non virtual addressing spaces
| / foo\x00 search for string 'foo\0'
| /c[ar] search for crypto materials
| /e /E.F/i match regular expression
| /i foo search for string 'foo' ignoring case
| /m[?][ebm] magicfile search for magic, filesystems or binary headers
| /v[1248] value look for an `cfg.bigendian` 32bit value
| /w foo search for wide string 'f\0o\0o\0'
| /x ff0033 search for hex string
| /z min max search for strings of given size
...
```
**Análise de Memória em Tempo de Execução**
Usando o [**r2frida**](https://github.com/nowsecure/r2frida), você pode analisar e inspecionar a memória do aplicativo enquanto ele está em execução, sem precisar fazer o dump dela. Por exemplo, você pode executar os comandos de pesquisa anteriores do r2frida e pesquisar a memória por uma string, valores hexadecimais, etc. Ao fazer isso, lembre-se de adicionar uma barra invertida `\` antes do comando de pesquisa (e de qualquer outro comando específico do r2frida) após iniciar a sessão com `r2 frida://usb//<nome_do_seu_app>`.
## Criptografia Quebrada
### Processos de Gerenciamento de Chave Fracos
Alguns desenvolvedores salvam dados sensíveis no armazenamento local e os criptografam com uma chave codificada/predizível no código. Isso não deve ser feito, pois a reversão pode permitir que os atacantes extraiam as informações confidenciais.
### Uso de Algoritmos Inseguros e/ou Obsoletos
Os desenvolvedores não devem usar **algoritmos obsoletos** para realizar **verificações** de autorização, **armazenar** ou **enviar** dados. Alguns desses algoritmos são: RC4, MD4, MD5, SHA1... Se **hashes** forem usados para armazenar senhas, por exemplo, hashes resistentes a ataques de força bruta devem ser usados com sal.
### Verificação
As principais verificações a serem realizadas são encontrar senhas/segredos **codificados** no código ou se eles são **previsíveis**, e se o código está usando algum tipo de algoritmo de **criptografia** **fraco**.
É interessante saber que você pode **monitorar** algumas **bibliotecas** de **criptografia** automaticamente usando o **objection** com:
```swift
ios monitor crypt
```
Para **mais informações** sobre APIs e bibliotecas criptográficas do iOS, acesse [https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06e-testing-cryptography](https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06e-testing-cryptography)
## Autenticação Local
O testador deve estar ciente de que **a autenticação local deve sempre ser aplicada em um endpoint remoto** ou com base em um primitivo criptográfico. Os atacantes podem facilmente ignorar a autenticação local se nenhum dado for retornado do processo de autenticação.
O [**Local Authentication framework**](https://developer.apple.com/documentation/localauthentication) \_\*\*\_fornece um conjunto de APIs para que os desenvolvedores possam estender um diálogo de autenticação para um usuário. No contexto de conexão com um serviço remoto, é possível (e recomendado) aproveitar o [keychain](https://developer.apple.com/library/content/documentation/Security/Conceptual/keychainServConcepts/01introduction/introduction.html) para implementar a autenticação local.
O sensor de **identificação de impressão digital** é operado pelo [coprocessador de segurança SecureEnclave](https://www.blackhat.com/docs/us-16/materials/us-16-Mandt-Demystifying-The-Secure-Enclave-Processor.pdf) e não expõe dados de impressão digital para outras partes do sistema. Ao lado do Touch ID, a Apple introduziu o _Face ID_: que permite autenticação baseada em reconhecimento facial.
Os desenvolvedores têm duas opções para incorporar a autenticação Touch ID/Face ID:
* `LocalAuthentication.framework` é uma API de alto nível que pode ser usada para **autenticar o usuário via Touch ID**. O aplicativo não pode acessar nenhum dado associado à impressão digital registrada e é notificado apenas se a autenticação foi bem-sucedida.
* `Security.framework` é uma API de nível inferior para acessar [serviços de keychain](https://developer.apple.com/documentation/security/keychain\_services). Esta é uma opção segura se o seu aplicativo precisar **proteger alguns dados secretos com autenticação biométrica**, uma vez que o controle de acesso é gerenciado em nível de sistema e não pode ser facilmente ignorado. `Security.framework` tem uma API C, mas existem vários [wrappers de código aberto disponíveis](https://www.raywenderlich.com/147308/secure-ios-user-data-keychain-touch-id), tornando o acesso ao keychain tão simples quanto ao NSUserDefaults.
{% hint style="danger" %}
Esteja ciente de que o uso do `LocalAuthentication.framework` ou do `Security.framework` será um controle que pode ser ignorado por um atacante, pois ele retorna apenas um booleano e nenhum dado para prosseguir. Veja [Don't touch me that way, de David Lindner et al](https://www.youtube.com/watch?v=XhXIHVGCFFM) para mais detalhes.
{% endhint %}
### Framework de Autenticação Local
Os desenvolvedores podem exibir um **prompt de autenticação** utilizando a função **`evaluatePolicy`** da classe **`LAContext`**. Duas políticas disponíveis definem formas aceitáveis de autenticação:
* `deviceOwnerAuthentication`(Swift) ou `LAPolicyDeviceOwnerAuthentication`(Objective-C): Quando disponível, o usuário é solicitado a realizar a autenticação do Touch ID. Se o Touch ID não estiver ativado, o código de acesso do dispositivo é solicitado. Se o código de acesso do dispositivo não estiver habilitado, a avaliação da política falha.
* `deviceOwnerAuthenticationWithBiometrics` (Swift) ou `LAPolicyDeviceOwnerAuthenticationWithBiometrics`(Objective-C): A autenticação é restrita a biometria, onde o usuário é solicitado a usar o Touch ID.
A **função `evaluatePolicy` retorna um valor booleano** indicando se o usuário foi autenticado com sucesso. O que significa que pode ser facilmente ignorado (veja abaixo)
### Autenticação Local usando Keychain
As **APIs do keychain do iOS podem (e devem) ser usadas para implementar a autenticação local**. Durante esse processo, o aplicativo armazena um token de autenticação secreto ou outro pedaço de dados secretos que identificam o usuário no keychain. Para autenticar em um serviço remoto, o usuário deve desbloquear o keychain usando sua senha ou impressão digital para obter os dados secretos.
O keychain permite salvar itens com o atributo especial `SecAccessControl`, que permitirá o acesso ao item do keychain somente após o usuário passar pela autenticação do Touch ID (ou código de acesso, se tal fallback for permitido pelos parâmetros do atributo).
No exemplo a seguir, salvaremos a string "test\_strong\_password" no keychain. A string só pode ser acessada no dispositivo atual enquanto o código de acesso estiver definido (`kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly` parâmetro) e após a autenticação do Touch ID para os dedos atualmente registrados (`SecAccessControlCreateFlags.biometryCurrentSet` parâmetro):
{% tabs %}
{% tab title="Swift" %}
```swift
// 1. create AccessControl object that will represent authentication settings
var error: Unmanaged<CFError>?
guard let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
SecAccessControlCreateFlags.biometryCurrentSet,
&error) else {
// failed to create AccessControl object
return
}
// 2. define keychain services query. Pay attention that kSecAttrAccessControl is mutually exclusive with kSecAttrAccessible attribute
var query: [String: Any] = [:]
query[kSecClass as String] = kSecClassGenericPassword
query[kSecAttrLabel as String] = "com.me.myapp.password" as CFString
query[kSecAttrAccount as String] = "OWASP Account" as CFString
query[kSecValueData as String] = "test_strong_password".data(using: .utf8)! as CFData
query[kSecAttrAccessControl as String] = accessControl
// 3. save item
let status = SecItemAdd(query as CFDictionary, nil)
if status == noErr {
// successfully saved
} else {
// error while saving
}
```
{% endtab %}
{% tab title="Português" %}
{% endtab %}
```objectivec
// 1. create AccessControl object that will represent authentication settings
CFErrorRef *err = nil;
SecAccessControlRef sacRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
kSecAccessControlUserPresence,
err);
// 2. define keychain services query. Pay attention that kSecAttrAccessControl is mutually exclusive with kSecAttrAccessible attribute
NSDictionary* query = @{
(_ _bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrLabel: @"com.me.myapp.password",
(__bridge id)kSecAttrAccount: @"OWASP Account",
(__bridge id)kSecValueData: [@"test_strong_password" dataUsingEncoding:NSUTF8StringEncoding],
(__bridge id)kSecAttrAccessControl: (__bridge_transfer id)sacRef
};
// 3. save item
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, nil);
if (status == noErr) {
// successfully saved
} else {
// error while saving
}
```
{% endtab %}
{% tab title="Portuguese" %}
Agora podemos solicitar o item salvo do keychain. Os serviços do keychain apresentarão a caixa de diálogo de autenticação ao usuário e retornarão dados ou nulo dependendo se uma impressão digital adequada foi fornecida ou não.
{% endtab %}
{% endtabs %}
```swift
// 1. define query
var query = [String: Any]()
query[kSecClass as String] = kSecClassGenericPassword
query[kSecReturnData as String] = kCFBooleanTrue
query[kSecAttrAccount as String] = "My Name" as CFString
query[kSecAttrLabel as String] = "com.me.myapp.password" as CFString
query[kSecUseOperationPrompt as String] = "Please, pass authorisation to enter this area" as CFString
// 2. get item
var queryResult: AnyObject?
let status = withUnsafeMutablePointer(to: &queryResult) {
SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
}
if status == noErr {
let password = String(data: queryResult as! Data, encoding: .utf8)!
// successfully received password
} else {
// authorization not passed
}
```
{% endtab %}
{% tab title="Português" %}
{% endtab %}
```objectivec
// 1. define query
NSDictionary *query = @{(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecReturnData: @YES,
(__bridge id)kSecAttrAccount: @"My Name1",
(__bridge id)kSecAttrLabel: @"com.me.myapp.password",
(__bridge id)kSecUseOperationPrompt: @"Please, pass authorisation to enter this area" };
// 2. get item
CFTypeRef queryResult = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &queryResult);
if (status == noErr){
NSData* resultData = ( __bridge_transfer NSData* )queryResult;
NSString* password = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
NSLog(@"%@", password);
} else {
NSLog(@"Something went wrong");
}
```
{% endtab %}
{% endtabs %}
### Detecção
O uso de frameworks em um aplicativo também pode ser detectado analisando a lista de bibliotecas dinâmicas compartilhadas do binário do aplicativo. Isso pode ser feito usando o `otool`:
```bash
$ otool -L <AppName>.app/<AppName>
```
Se o `LocalAuthentication.framework` é usado em um aplicativo, a saída conterá ambas as seguintes linhas (lembre-se de que o `LocalAuthentication.framework` usa o `Security.framework` por baixo dos panos):
```bash
/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication
/System/Library/Frameworks/Security.framework/Security
```
Se o `Security.framework` for usado, apenas o segundo será exibido.
### Bypass do Framework de Autenticação Local
#### Objeção
\*\*\*\*[**Objeção Biometrics Bypass**](https://github.com/sensepost/objection/wiki/Understanding-the-iOS-Biometrics-Bypass) \*\*\*\* pode ser usado para burlar o LocalAuthentication. A Objeção **usa o Frida para instrumentar a função `evaluatePolicy` para que ela retorne `True` mesmo que a autenticação não tenha sido realizada com sucesso**. Use o comando `ios ui biometrics_bypass` para burlar a autenticação biométrica insegura. A Objeção registrará um trabalho, que substituirá o resultado do `evaluatePolicy`. Isso funcionará tanto nas implementações Swift quanto Objective-C.
```bash
...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # ios ui biometrics_bypass
(agent) Registering job 3mhtws9x47q. Type: ios-biometrics-disable
...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # (agent) [3mhtws9x47q] Localized Reason for auth requirement: Please authenticate yourself
(agent) [3mhtws9x47q] OS authentication response: false
(agent) [3mhtws9x47q] Marking OS response as True instead
(agent) [3mhtws9x47q] Biometrics bypass hook complete
```
Se vulnerável, o módulo automaticamente irá ignorar o formulário de login.
#### Frida
Um exemplo de uso de **`evaluatePolicy`** do aplicativo [DVIA-v2](https://github.com/prateek147/DVIA-v2):
```swift
+(void)authenticateWithTouchID {
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = @"Please authenticate yourself";
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
[TouchIDAuthentication showAlert:@"Authentication Successful" withTitle:@"Success"];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[TouchIDAuthentication showAlert:@"Authentication Failed !" withTitle:@"Error"];
});
}
}];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[TouchIDAuthentication showAlert:@"Your device doesn't support Touch ID or you haven't configured Touch ID authentication on your device" withTitle:@"Error"];
});
}
}
```
Para burlar a Autenticação Local, temos que escrever um script Frida que **burla** a verificação mencionada _**evaluatePolicy**. Como você pode ver no trecho de código acima colado, o **evaluatePolicy** usa um **callback** que determina o **resultado**. Portanto, a maneira mais fácil de realizar o hack é interceptar esse callback e garantir que ele sempre retorne o **sucesso=1**.
```swift
// from https://securitycafe.ro/2022/09/05/mobile-pentesting-101-bypassing-biometric-authentication/
if(ObjC.available) {
console.log("Injecting...");
var hook = ObjC.classes.LAContext["- evaluatePolicy:localizedReason:reply:"];
Interceptor.attach(hook.implementation, {
onEnter: function(args) {
var block = new ObjC.Block(args[4]);
const callback = block.implementation;
block.implementation = function (error, value) {
console.log("Changing the result value to true")
const result = callback(1, null);
return result;
};
},
});
} else {
console.log("Objective-C Runtime is not available!");
}
```
```
frida -U -f com.highaltitudehacks.DVIAswiftv2 --no-pause -l fingerprint-bypass-ios.js
```
## Exposição de Funcionalidades Sensíveis Através de IPC
### Manipuladores de URI Personalizados / Links Profundos / Esquemas Personalizados
{% content-ref url="ios-custom-uri-handlers-deeplinks-custom-schemes.md" %}
[ios-custom-uri-handlers-deeplinks-custom-schemes.md](ios-custom-uri-handlers-deeplinks-custom-schemes.md)
{% endcontent-ref %}
### Links Universais
{% content-ref url="ios-universal-links.md" %}
[ios-universal-links.md](ios-universal-links.md)
{% endcontent-ref %}
### Compartilhamento de UIActivity
{% content-ref url="ios-uiactivity-sharing.md" %}
[ios-uiactivity-sharing.md](ios-uiactivity-sharing.md)
{% endcontent-ref %}
### UIPasteboard
{% content-ref url="ios-uipasteboard.md" %}
[ios-uipasteboard.md](ios-uipasteboard.md)
{% endcontent-ref %}
### Extensões de Aplicativos
{% content-ref url="ios-app-extensions.md" %}
[ios-app-extensions.md](ios-app-extensions.md)
{% endcontent-ref %}
### WebViews
{% content-ref url="ios-webviews.md" %}
[ios-webviews.md](ios-webviews.md)
{% endcontent-ref %}
### Serialização e Codificação
{% content-ref url="ios-serialisation-and-encoding.md" %}
[ios-serialisation-and-encoding.md](ios-serialisation-and-encoding.md)
{% endcontent-ref %}
## Comunicação de Rede
É importante verificar se não há comunicação ocorrendo **sem criptografia** e também se o aplicativo está **validando corretamente o certificado TLS** do servidor.\
Para verificar esses tipos de problemas, você pode usar um proxy como o **Burp**:
{% content-ref url="burp-configuration-for-ios.md" %}
[burp-configuration-for-ios.md](burp-configuration-for-ios.md)
{% endcontent-ref %}
### Verificação de Nome de Host
Um problema comum na validação do certificado TLS é verificar se o certificado foi assinado por uma **CA confiável**, mas **não verificar** se **o nome do host** do certificado é o nome do host sendo acessado.\
Para verificar esse problema usando o Burp, depois de confiar no CA do Burp no iPhone, você pode **criar um novo certificado com o Burp para um nome de host diferente** e usá-lo. Se o aplicativo ainda funcionar, então algo está vulnerável.
### Pinagem de Certificado
Se um aplicativo estiver usando a Pinagem SSL corretamente, o aplicativo só funcionará se o certificado for o esperado. Ao testar um aplicativo, **isso pode ser um problema, pois o Burp servirá seu próprio certificado.**\
Para ignorar essa proteção dentro de um dispositivo com jailbreak, você pode instalar o aplicativo [**SSL Kill Switch**](https://github.com/nabla-c0d3/ssl-kill-switch2) ou instalar \[**Burp Mobile Assistant\_\*]\(\_**[**https://portswigger.net/burp/documentation/desktop/tools/mobile-assistant/installing)\\**](https://portswigger.net/burp/documentation/desktop/tools/mobile-assistant/installing\)/)\*
Você também pode usar o `ios sslpinning disable` do **objection**
## Misc
* Em **`/System/Library`**, você pode encontrar os frameworks instalados no telefone usados pelos aplicativos do sistema
* Os aplicativos instalados pelo usuário na App Store estão localizados dentro de **`/User/Applications`**
* E o **`/User/Library`** contém dados salvos pelos aplicativos de nível de usuário
* Você pode acessar **`/User/Library/Notes/notes.sqlite`** para ler as notas salvas dentro do aplicativo.
* Dentro da pasta de um aplicativo instalado (**`/User/Applications/<APP ID>/`**), você pode encontrar alguns arquivos interessantes:
* **`iTunesArtwork`**: O ícone usado pelo aplicativo
* **`iTunesMetadata.plist`**: Informações do aplicativo usadas na App Store
* **`/Library/*`**: Contém as preferências e cache. Em **`/Library/Cache/Snapshots/*`** você pode encontrar o snapshot realizado no aplicativo antes de enviá-lo para o segundo plano.
### Hot Patching/Atualização Forçada
Os desenvolvedores podem **corrigir remotamente todas as instalações de seu aplicativo instantaneamente** sem precisar reenviar o aplicativo para a App Store e esperar até que seja aprovado.\
Para esse propósito, geralmente é usado o [**JSPatch**](https://github.com/bang590/JSPatch)**.** Mas existem outras opções também, como [Siren](https://github.com/ArtSabintsev/Siren) e [react-native-appstore-version-checker](https://www.npmjs.com/package/react-native-appstore-version-checker).\
**Este é um mecanismo perigoso que pode ser abusado por SDKs de terceiros maliciosos, portanto, é recomendável verificar qual método é usado para atualização automática (se houver) e testá-lo.** Você pode tentar baixar uma versão anterior do aplicativo para esse fim.
### Terceiros
Um problema dos SDKs de terceiros é que não há **controle granular sobre as funcionalidades oferecidas pelo SDK**. Você pode usar o SDK e ter todas as funcionalidades (incluindo vazamentos de diagnóstico e conexões HTTP inseguras), ou não usá-lo. Além disso, geralmente não é possível para os desenvolvedores de aplicativos **corrigir uma vulnerabilidade** no SDK.\
Além disso, alguns SDKs começam a **conter malware quando são muito confiáveis** pela comunidade.
Além disso, as funcionalidades que esses serviços fornecem podem envolver serviços de **rastreamento para monitorar o comportamento do usuário** ao usar o aplicativo, vender anúncios em banner ou melhorar a experiência do usuário. A desvantagem dos serviços de terceiros é que os desenvolvedores não conhecem os detalhes do código executado por meio de bibliotecas de terceiros. Consequentemente, não deve ser enviado mais informações do que o necessário para um serviço e nenhuma informação confidencial deve ser divulgada.
A desvantagem é que um **desenvolvedor não sabe em detalhes qual código é executado via