1089 lines
62 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# iOS Pentesting
{{#include ../../banners/hacktricks-training.md}}
## iOS Basics
{{#ref}}
ios-basics.md
{{#endref}}
## Testing Environment
Na tej stronie znajdziesz informacje o **symulatorze iOS**, **emulatorach** i **jailbreaku:**
{{#ref}}
ios-testing-environment.md
{{#endref}}
## Initial Analysis
### Basic iOS Testing Operations
Podczas testowania **zostanie zasugerowanych kilka operacji** (połączenie z urządzeniem, odczyt/zapis/przesyłanie/pobieranie plików, użycie niektórych narzędzi...). Dlatego, jeśli nie wiesz, jak wykonać którąkolwiek z tych czynności, proszę, **zacznij czytać stronę**:
{{#ref}}
basic-ios-testing-operations.md
{{#endref}}
> [!TIP]
> W kolejnych krokach **aplikacja powinna być zainstalowana** na urządzeniu i powinna już mieć uzyskany **plik IPA** aplikacji.\
> Przeczytaj stronę [Basic iOS Testing Operations](basic-ios-testing-operations.md), aby dowiedzieć się, jak to zrobić.
### Basic Static Analysis
Kilka interesujących dekompilatorów plików iOS - IPA:
- [https://github.com/LaurieWired/Malimite](https://github.com/LaurieWired/Malimite)
- [https://ghidra-sre.org/](https://ghidra-sre.org/)
Zaleca się użycie narzędzia [**MobSF**](https://github.com/MobSF/Mobile-Security-Framework-MobSF) do przeprowadzenia automatycznej analizy statycznej pliku IPA.
Identyfikacja **ochron obecnych w binarnym**:
- **PIE (Position Independent Executable)**: Gdy jest włączone, aplikacja ładowana jest do losowego adresu pamięci za każdym razem, gdy jest uruchamiana, co utrudnia przewidywanie jej początkowego adresu pamięci.
```bash
otool -hv <app-binary> | grep PIE # Powinien zawierać flagę PIE
```
- **Stack Canaries**: Aby zweryfikować integralność stosu, wartość „canary” jest umieszczana na stosie przed wywołaniem funkcji i jest weryfikowana ponownie po zakończeniu funkcji.
```bash
otool -I -v <app-binary> | grep stack_chk # Powinien zawierać symbole: stack_chk_guard i stack_chk_fail
```
- **ARC (Automatic Reference Counting)**: Aby zapobiec powszechnym błędom związanym z uszkodzeniem pamięci
```bash
otool -I -v <app-binary> | grep objc_release # Powinien zawierać symbol _objc_release
```
- **Encrypted Binary**: Binarna powinna być zaszyfrowana
```bash
otool -arch all -Vl <app-binary> | grep -A5 LC_ENCRYPT # Cryptid powinien wynosić 1
```
**Identyfikacja Wrażliwych/Niezabezpieczonych Funkcji**
- **Słabe Algorytmy Hashujące**
```bash
# Na urządzeniu iOS
otool -Iv <app> | grep -w "_CC_MD5"
otool -Iv <app> | grep -w "_CC_SHA1"
# Na linuxie
grep -iER "_CC_MD5"
grep -iER "_CC_SHA1"
```
- **Niezabezpieczone Funkcje Losowe**
```bash
# Na urządzeniu iOS
otool -Iv <app> | grep -w "_random"
otool -Iv <app> | grep -w "_srand"
otool -Iv <app> | grep -w "_rand"
# Na linuxie
grep -iER "_random"
grep -iER "_srand"
grep -iER "_rand"
```
- **Niezabezpieczona Funkcja Malloc**
```bash
# Na urządzeniu iOS
otool -Iv <app> | grep -w "_malloc"
# Na linuxie
grep -iER "_malloc"
```
- **Niezabezpieczone i Wrażliwe Funkcje**
```bash
# Na urządzeniu 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"
# Na linuxie
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"
```
### Basic Dynamic Analysis
Sprawdź analizę dynamiczną, którą wykonuje [**MobSF**](https://github.com/MobSF/Mobile-Security-Framework-MobSF). Będziesz musiał przejść przez różne widoki i wchodzić z nimi w interakcje, ale będzie to podłączać kilka klas podczas wykonywania innych czynności i przygotuje raport, gdy skończysz.
### Listing Installed Apps
Użyj polecenia `frida-ps -Uai`, aby określić **identyfikator pakietu** zainstalowanych aplikacji:
```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
```
### Podstawowa Enumeracja i Hooking
Dowiedz się, jak **enumerować komponenty aplikacji** oraz jak łatwo **hookować metody i klasy** za pomocą objection:
{{#ref}}
ios-hooking-with-objection.md
{{#endref}}
### Struktura IPA
Struktura **pliku IPA** jest zasadniczo taka sama jak **spakowanego pakietu**. Zmieniając jego rozszerzenie na `.zip`, można go **rozpakować**, aby ujawnić jego zawartość. W tej strukturze, **Bundle** reprezentuje w pełni zapakowaną aplikację gotową do instalacji. Wewnątrz znajdziesz katalog o nazwie `<NAME>.app`, który zawiera zasoby aplikacji.
- **`Info.plist`**: Ten plik zawiera szczegółowe informacje konfiguracyjne aplikacji.
- **`_CodeSignature/`**: Ten katalog zawiera plik plist, który zawiera podpis, zapewniając integralność wszystkich plików w pakiecie.
- **`Assets.car`**: Skompresowany archiwum, które przechowuje pliki zasobów, takie jak ikony.
- **`Frameworks/`**: Ten folder zawiera natywne biblioteki aplikacji, które mogą być w formie plików `.dylib` lub `.framework`.
- **`PlugIns/`**: Może zawierać rozszerzenia aplikacji, znane jako pliki `.appex`, chociaż nie zawsze są obecne. \* [**`Core Data`**](https://developer.apple.com/documentation/coredata): Jest używane do zapisywania trwałych danych aplikacji do użytku offline, do buforowania danych tymczasowych oraz do dodawania funkcji cofania do aplikacji na jednym urządzeniu. Aby synchronizować dane między wieloma urządzeniami w jednym koncie iCloud, Core Data automatycznie odzwierciedla schemat w kontenerze CloudKit.
- [**`PkgInfo`**](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/ConfigApplications.html): Plik `PkgInfo` jest alternatywnym sposobem określenia typu i kodów twórcy aplikacji lub pakietu.
- **en.lproj, fr.proj, Base.lproj**: To pakiety językowe, które zawierają zasoby dla tych konkretnych języków oraz domyślny zasób na wypadek, gdy dany język nie jest obsługiwany.
- **Bezpieczeństwo**: Katalog `_CodeSignature/` odgrywa kluczową rolę w bezpieczeństwie aplikacji, weryfikując integralność wszystkich plików w pakiecie za pomocą podpisów cyfrowych.
- **Zarządzanie zasobami**: Plik `Assets.car` wykorzystuje kompresję do efektywnego zarządzania zasobami graficznymi, co jest kluczowe dla optymalizacji wydajności aplikacji i zmniejszenia jej ogólnego rozmiaru.
- **Frameworki i PlugIns**: Te katalogi podkreślają modułowość aplikacji iOS, umożliwiając deweloperom dołączanie bibliotek kodu do ponownego użycia (`Frameworks/`) oraz rozszerzanie funkcjonalności aplikacji (`PlugIns/`).
- **Lokalizacja**: Struktura wspiera wiele języków, ułatwiając globalny zasięg aplikacji poprzez dołączanie zasobów dla konkretnych pakietów językowych.
**Info.plist**
**Info.plist** jest fundamentem aplikacji iOS, zawierającym kluczowe dane konfiguracyjne w formie par **klucz-wartość**. Ten plik jest wymagany nie tylko dla aplikacji, ale także dla rozszerzeń aplikacji i frameworków w pakiecie. Jest zorganizowany w formacie XML lub binarnym i zawiera krytyczne informacje, od uprawnień aplikacji po konfiguracje bezpieczeństwa. Aby szczegółowo zbadać dostępne klucze, można odwołać się do [**Dokumentacji Dewelopera Apple**](https://developer.apple.com/documentation/bundleresources/information_property_list?language=objc).
Dla tych, którzy chcą pracować z tym plikiem w bardziej dostępnym formacie, konwersję XML można łatwo osiągnąć za pomocą `plutil` na macOS (dostępne natywnie w wersjach 10.2 i nowszych) lub `plistutil` na Linuxie. Komendy do konwersji są następujące:
- **Dla macOS**:
```bash
$ plutil -convert xml1 Info.plist
```
- **Dla Linuksa**:
```bash
$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist
```
Wśród niezliczonych informacji, które plik **Info.plist** może ujawnić, istotne wpisy to ciągi uprawnień aplikacji (`UsageDescription`), niestandardowe schematy URL (`CFBundleURLTypes`) oraz konfiguracje dla App Transport Security (`NSAppTransportSecurity`). Wpisy te, wraz z innymi, takimi jak eksportowane/importowane niestandardowe typy dokumentów (`UTExportedTypeDeclarations` / `UTImportedTypeDeclarations`), można łatwo zlokalizować, przeglądając plik lub używając prostego polecenia `grep`:
```bash
$ grep -i <keyword> Info.plist
```
**Ścieżki danych**
W środowisku iOS katalogi są wyznaczone specjalnie dla **aplikacji systemowych** i **aplikacji zainstalowanych przez użytkownika**. Aplikacje systemowe znajdują się w katalogu `/Applications`, podczas gdy aplikacje zainstalowane przez użytkownika są umieszczane w `/var/mobile/containers/Data/Application/`. Te aplikacje mają przypisany unikalny identyfikator znany jako **128-bitowy UUID**, co utrudnia ręczne zlokalizowanie folderu aplikacji z powodu losowości nazw katalogów.
> [!WARNING]
> Ponieważ aplikacje w iOS muszą być izolowane, każda aplikacja będzie miała również folder wewnątrz **`$HOME/Library/Containers`** z **`CFBundleIdentifier`** aplikacji jako nazwą folderu.
>
> Jednak oba foldery (foldery danych i kontenerów) mają plik **`.com.apple.mobile_container_manager.metadata.plist`**, który łączy oba pliki w kluczu `MCMetadataIdentifier`.
Aby ułatwić odkrycie katalogu instalacyjnego aplikacji zainstalowanej przez użytkownika, narzędzie **objection** oferuje przydatne polecenie, `env`. To polecenie ujawnia szczegółowe informacje o katalogu dla danej aplikacji. Poniżej znajduje się przykład użycia tego polecenia:
```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
```
Alternatywnie, nazwę aplikacji można wyszukać w `/private/var/containers` za pomocą polecenia `find`:
```bash
find /private/var/containers -name "Progname*"
```
Polecenia takie jak `ps` i `lsof` mogą być również wykorzystane do identyfikacji procesu aplikacji i listowania otwartych plików, odpowiednio, dostarczając informacji o aktywnych ścieżkach katalogów aplikacji:
```bash
ps -ef | grep -i <app-name>
lsof -p <pid> | grep -i "/containers" | head -n 1
```
**Katalog pakietu:**
- **AppName.app**
- To jest pakiet aplikacji, jak wcześniej widziano w IPA, zawiera niezbędne dane aplikacji, statyczne treści oraz skompilowany plik binarny aplikacji.
- Ten katalog jest widoczny dla użytkowników, ale **użytkownicy nie mogą do niego pisać**.
- Zawartość tego katalogu **nie jest kopiowana**.
- Zawartość tego folderu jest używana do **walidacji podpisu kodu**.
**Katalog danych:**
- **Documents/**
- Zawiera wszystkie dane generowane przez użytkownika. Użytkownik końcowy aplikacji inicjuje tworzenie tych danych.
- Widoczny dla użytkowników i **użytkownicy mogą do niego pisać**.
- Zawartość tego katalogu **jest kopiowana**.
- Aplikacja może wyłączyć ścieżki, ustawiając `NSURLIsExcludedFromBackupKey`.
- **Library/**
- Zawiera wszystkie **pliki, które nie są specyficzne dla użytkownika**, takie jak **cache**, **preferencje**, **ciasteczka** oraz pliki konfiguracyjne listy właściwości (plist).
- Aplikacje iOS zazwyczaj używają podkatalogów `Application Support` i `Caches`, ale aplikacja może tworzyć własne podkatalogi.
- **Library/Caches/**
- Zawiera **półtrwałe pliki cache.**
- Niewidoczny dla użytkowników i **użytkownicy nie mogą do niego pisać**.
- Zawartość tego katalogu **nie jest kopiowana**.
- System operacyjny może automatycznie usunąć pliki z tego katalogu, gdy aplikacja nie jest uruchomiona, a miejsce na dysku jest ograniczone.
- **Library/Application Support/**
- Zawiera **trwałe** **pliki** niezbędne do działania aplikacji.
- **Niewidoczny** **dla** **użytkowników** i użytkownicy nie mogą do niego pisać.
- Zawartość tego katalogu **jest kopiowana**.
- Aplikacja może wyłączyć ścieżki, ustawiając `NSURLIsExcludedFromBackupKey`.
- **Library/Preferences/**
- Używany do przechowywania właściwości, które mogą **utrzymywać się nawet po ponownym uruchomieniu aplikacji**.
- Informacje są zapisywane, niezaszyfrowane, wewnątrz piaskownicy aplikacji w pliku plist o nazwie \[BUNDLE_ID].plist.
- Wszystkie pary klucz/wartość przechowywane za pomocą `NSUserDefaults` można znaleźć w tym pliku.
- **tmp/**
- Użyj tego katalogu do zapisywania **plików tymczasowych**, które nie muszą się utrzymywać między uruchomieniami aplikacji.
- Zawiera nietrwałe pliki cache.
- **Niewidoczny** dla użytkowników.
- Zawartość tego katalogu nie jest kopiowana.
- System operacyjny może automatycznie usunąć pliki z tego katalogu, gdy aplikacja nie jest uruchomiona, a miejsce na dysku jest ograniczone.
Przyjrzyjmy się bliżej katalogowi pakietu aplikacji iGoat-Swift (.app) wewnątrz katalogu pakietu (`/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
```
### Binary Reversing
W folderze `<application-name>.app` znajdziesz plik binarny o nazwie `<application-name>`. To jest plik, który będzie **wykonywany**. Możesz przeprowadzić podstawową inspekcję binarnego pliku za pomocą narzędzia **`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)
[...]
```
**Sprawdź, czy aplikacja jest zaszyfrowana**
Zobacz, czy jest jakiekolwiek wyjście dla:
```bash
otool -l <app-binary> | grep -A 4 LC_ENCRYPTION_INFO
```
**Rozkładanie binarnego**
Rozłóż sekcję tekstową:
```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
```
Aby wydrukować **segment Objective-C** przykładowej aplikacji, można użyć:
```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
```
Aby uzyskać bardziej zwarty kod Objective-C, możesz użyć [**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;
};
```
Jednak najlepszymi opcjami do dekompilacji binariów są: [**Hopper**](https://www.hopperapp.com/download.html?) i [**IDA**](https://www.hex-rays.com/products/ida/support/download_freeware/).
## Przechowywanie danych
Aby dowiedzieć się, jak iOS przechowuje dane na urządzeniu, przeczytaj tę stronę:
{{#ref}}
ios-basics.md
{{#endref}}
> [!WARNING]
> Następujące miejsca do przechowywania informacji powinny być sprawdzone **tuż po zainstalowaniu aplikacji**, **po sprawdzeniu wszystkich funkcjonalności** aplikacji, a nawet po **wylogowaniu się z jednego użytkownika i zalogowaniu się na innego**.\
> Celem jest znalezienie **niechronionych wrażliwych informacji** aplikacji (hasła, tokeny), bieżącego użytkownika oraz wcześniej zalogowanych użytkowników.
### Plist
Pliki **plist** to strukturalne pliki XML, które **zawierają pary klucz-wartość**. To sposób na przechowywanie danych trwałych, więc czasami możesz znaleźć **wrażliwe informacje w tych plikach**. Zaleca się sprawdzenie tych plików po zainstalowaniu aplikacji i po intensywnym korzystaniu z niej, aby zobaczyć, czy zapisano nowe dane.
Najczęstszym sposobem na trwałe przechowywanie danych w plikach plist jest użycie **NSUserDefaults**. Ten plik plist jest zapisywany wewnątrz piaskownicy aplikacji w **`Library/Preferences/<appBundleID>.plist`**.
Klasa [`NSUserDefaults`](https://developer.apple.com/documentation/foundation/nsuserdefaults) zapewnia programowy interfejs do interakcji z domyślnym systemem. Domyślny system pozwala aplikacji dostosować swoje zachowanie zgodnie z **preferencjami użytkownika**. Dane zapisane przez `NSUserDefaults` można przeglądać w pakiecie aplikacji. Ta klasa przechowuje **dane** w pliku **plist**, ale jest przeznaczona do użycia z małymi ilościami danych.
Dane te nie mogą być dłużej bezpośrednio dostępne za pomocą zaufanego komputera, ale można uzyskać do nich dostęp, wykonując **kopię zapasową**.
Możesz **zrzucić** informacje zapisane za pomocą **`NSUserDefaults`** używając `ios nsuserdefaults get` z objection.
Aby znaleźć wszystkie pliki plist używane przez aplikację, możesz uzyskać dostęp do `/private/var/mobile/Containers/Data/Application/{APPID}` i uruchomić:
```bash
find ./ -name "*.plist"
```
Aby przekonwertować pliki z formatu **XML lub binarnego (bplist)** na XML, dostępne są różne metody w zależności od systemu operacyjnego:
**Dla użytkowników macOS:** Wykorzystaj polecenie `plutil`. To wbudowane narzędzie w macOS (10.2+), zaprojektowane do tego celu:
```bash
$ plutil -convert xml1 Info.plist
```
**Dla użytkowników Linuxa:** Najpierw zainstaluj `libplist-utils`, a następnie użyj `plistutil`, aby przekonwertować swój plik:
```bash
$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist
```
**W sesji Objection:** Do analizy aplikacji mobilnych, konkretne polecenie pozwala na bezpośrednie konwertowanie plików plist:
```bash
ios plist cat /private/var/mobile/Containers/Data/Application/<Application-UUID>/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) to framework do zarządzania warstwą modelu obiektów w Twojej aplikacji. [Core Data może używać SQLite jako swojego trwałego magazynu](https://cocoacasts.com/what-is-the-difference-between-core-data-and-sqlite/), ale samo framework nie jest bazą danych.\
CoreData domyślnie nie szyfruje swoich danych. Jednak dodatkowa warstwa szyfrowania może być dodana do CoreData. Zobacz [GitHub Repo](https://github.com/project-imas/encrypted-core-data) po więcej szczegółów.
Możesz znaleźć informacje o SQLite Core Data aplikacji w ścieżce `/private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support`
**Jeśli możesz otworzyć SQLite i uzyskać dostęp do wrażliwych informacji, to znalazłeś błędną konfigurację.**
```objectivec:Code from iGoat
-(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");
}
}
```
### YapDatabase
[YapDatabase](https://github.com/yapstudios/YapDatabase) to magazyn klucz/wartość zbudowany na bazie SQLite.\
Ponieważ bazy danych Yap są bazami danych sqlite, możesz je znaleźć, używając zaproponowanej komendy w poprzedniej sekcji.
### Inne bazy danych SQLite
Powszechną praktyką jest, że aplikacje tworzą własne bazy danych sqlite. Mogą one **przechowywać** **wrażliwe** **dane** i pozostawiać je niezaszyfrowane. Dlatego zawsze warto sprawdzić każdą bazę danych w katalogu aplikacji. Przejdź więc do katalogu aplikacji, w którym zapisane są dane (`/private/var/mobile/Containers/Data/Application/{APPID}`)
```bash
find ./ -name "*.sqlite" -or -name "*.db"
```
### Firebase Real-Time Databases
Programiści mogą **przechowywać i synchronizować dane** w **bazie danych NoSQL hostowanej w chmurze** za pomocą Firebase Real-Time Databases. Przechowywane w formacie JSON, dane są synchronizowane do wszystkich podłączonych klientów w czasie rzeczywistym.
Możesz znaleźć informacje, jak sprawdzić źle skonfigurowane bazy danych Firebase tutaj:
{{#ref}}
../../network-services-pentesting/pentesting-web/buckets/firebase-database.md
{{#endref}}
### Realm databases
[Realm Objective-C](https://realm.io/docs/objc/latest/) i [Realm Swift](https://realm.io/docs/swift/latest/) oferują potężną alternatywę dla przechowywania danych, której nie zapewnia Apple. Domyślnie **przechowują dane w postaci niezaszyfrowanej**, z możliwością szyfrowania poprzez odpowiednią konfigurację.
Bazy danych znajdują się w: `/private/var/mobile/Containers/Data/Application/{APPID}`. Aby zbadać te pliki, można wykorzystać polecenia takie jak:
```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*"
```
Aby wyświetlić te pliki bazy danych, zaleca się użycie narzędzia [**Realm Studio**](https://github.com/realm/realm-studio).
Aby wdrożyć szyfrowanie w bazie danych Realm, można użyć następującego fragmentu kodu:
```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)")
}
```
### Bazy danych Couchbase Lite
[Couchbase Lite](https://github.com/couchbase/couchbase-lite-ios) jest opisywany jako **lekki** i **wbudowany** silnik bazy danych, który stosuje podejście **zorientowane na dokumenty** (NoSQL). Zaprojektowany z myślą o **iOS** i **macOS**, oferuje możliwość bezproblemowej synchronizacji danych.
Aby zidentyfikować potencjalne bazy danych Couchbase na urządzeniu, należy sprawdzić następujący katalog:
```bash
ls /private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support/
```
### Cookies
iOS przechowuje pliki cookie aplikacji w **`Library/Cookies/cookies.binarycookies`** wewnątrz folderu każdej aplikacji. Jednak deweloperzy czasami decydują się na zapisanie ich w **keychain**, ponieważ wspomniany **plik cookie może być dostępny w kopiach zapasowych**.
Aby sprawdzić plik cookie, możesz użyć [**tego skryptu python**](https://github.com/mdegrazia/Safari-Binary-Cookie-Parser) lub użyć **`ios cookies get`** z objection.\
**Możesz także użyć objection, aby** przekonwertować te pliki na format JSON i sprawdzić dane.
```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
Domyślnie NSURLSession przechowuje dane, takie jak **żądania i odpowiedzi HTTP w bazie danych Cache.db**. Ta baza danych może zawierać **wrażliwe dane**, jeśli tokeny, nazwy użytkowników lub jakiekolwiek inne wrażliwe informacje zostały zbuforowane. Aby znaleźć zbuforowane informacje, otwórz katalog danych aplikacji (`/var/mobile/Containers/Data/Application/<UUID>`) i przejdź do `/Library/Caches/<Bundle Identifier>`. **Cache WebKit jest również przechowywany w pliku Cache.db**. **Objection** może otworzyć i interagować z bazą danych za pomocą polecenia `sqlite connect Cache.db`, ponieważ jest to n**ormalna baza danych SQLite**.
Zaleca się **wyłączenie buforowania tych danych**, ponieważ mogą one zawierać wrażliwe informacje w żądaniu lub odpowiedzi. Poniższa lista pokazuje różne sposoby osiągnięcia tego:
1. Zaleca się usunięcie zbuforowanych odpowiedzi po wylogowaniu. Można to zrobić za pomocą metody dostarczonej przez Apple o nazwie [`removeAllCachedResponses`](https://developer.apple.com/documentation/foundation/urlcache/1417802-removeallcachedresponses). Możesz wywołać tę metodę w następujący sposób:
`URLCache.shared.removeAllCachedResponses()`
Ta metoda usunie wszystkie zbuforowane żądania i odpowiedzi z pliku Cache.db.
2. Jeśli nie musisz korzystać z zalet ciasteczek, zaleca się po prostu użycie właściwości konfiguracyjnej [.ephemeral](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1410529-ephemeral) URLSession, która wyłączy zapisywanie ciasteczek i buforów.
[Dokumentacja Apple](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1410529-ephemeral):
`Obiekt konfiguracyjny sesji ephemerowej jest podobny do domyślnego obiektu konfiguracyjnego sesji (patrz default), z wyjątkiem tego, że odpowiadający obiekt sesji nie przechowuje buforów, magazynów poświadczeń ani żadnych danych związanych z sesją na dysku. Zamiast tego dane związane z sesją są przechowywane w RAM. Jedynym razem, gdy sesja ephemerowa zapisuje dane na dysku, jest wtedy, gdy powiesz jej, aby zapisała zawartość URL do pliku.`
3. Bufor można również wyłączyć, ustawiając politykę buforowania na [.notAllowed](https://developer.apple.com/documentation/foundation/urlcache/storagepolicy/notallowed). Wyłączy to przechowywanie buforu w jakiejkolwiek formie, zarówno w pamięci, jak i na dysku.
### Snapshots
Kiedy naciśniesz przycisk home, iOS **robi zrzut ekranu bieżącego ekranu**, aby móc przejść do aplikacji w znacznie płynniejszy sposób. Jednak jeśli na bieżącym ekranie znajdują się **wrażliwe** **dane**, zostaną one **zapisane** w **obrazie** (który **utrzymuje się** **po** **ponownych uruchomieniach**). To są zrzuty ekranu, do których możesz również uzyskać dostęp, podwójnie stukając ekran główny, aby przełączać się między aplikacjami.
O ile iPhone nie jest zrootowany, **atakujący** musi mieć **dostęp** do **urządzenia** **odblokowanego**, aby zobaczyć te zrzuty ekranu. Domyślnie ostatni zrzut ekranu jest przechowywany w piaskownicy aplikacji w folderze `Library/Caches/Snapshots/` lub `Library/SplashBoard/Snapshots` (zaufane komputery nie mogą uzyskać dostępu do systemu plików od iOX 7.0).
Jednym ze sposobów zapobiegania temu złemu zachowaniu jest umieszczenie pustego ekranu lub usunięcie wrażliwych danych przed zrobieniem zrzutu ekranu za pomocą funkcji `ApplicationDidEnterBackground()`.
Poniżej znajduje się przykładowa metoda naprawcza, która ustawi domyślny zrzut ekranu.
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:
```
@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];
}
```
To ustawienie obrazu tła na `overlayImage.png` za każdym razem, gdy aplikacja jest w tle. Zapobiega to wyciekom wrażliwych danych, ponieważ `overlayImage.png` zawsze zastępuje bieżący widok.
### Keychain
Do uzyskiwania dostępu i zarządzania keychainem iOS, dostępne są narzędzia takie jak [**Keychain-Dumper**](https://github.com/ptoomey3/Keychain-Dumper), odpowiednie dla urządzeń z jailbreakiem. Dodatkowo, [**Objection**](https://github.com/sensepost/objection) oferuje polecenie `ios keychain dump` do podobnych celów.
#### **Przechowywanie poświadczeń**
Klasa **NSURLCredential** jest idealna do zapisywania wrażliwych informacji bezpośrednio w keychainie, omijając potrzebę używania NSUserDefaults lub innych opakowań. Aby przechować poświadczenia po zalogowaniu, używany jest następujący kod Swift:
```swift
NSURLCredential *credential;
credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistencePermanent];
[[NSURLCredentialStorage sharedCredentialStorage] setCredential:credential forProtectionSpace:self.loginProtectionSpace];
```
Aby wyodrębnić te zapisane dane uwierzytelniające, używana jest komenda Objection `ios nsurlcredentialstorage dump`.
## **Niestandardowe Klawiatury i Pamięć Klawiatury**
Od iOS 8.0 użytkownicy mogą instalować rozszerzenia niestandardowych klawiatur, które są zarządzane w **Ustawienia > Ogólne > Klawiatura > Klawiatury**. Chociaż te klawiatury oferują rozszerzoną funkcjonalność, niosą ze sobą ryzyko rejestrowania naciśnięć klawiszy i przesyłania danych do zewnętrznych serwerów, chociaż użytkownicy są informowani o klawiaturach wymagających dostępu do sieci. Aplikacje mogą i powinny ograniczać użycie niestandardowych klawiatur do wprowadzania wrażliwych informacji.
**Zalecenia dotyczące bezpieczeństwa:**
- Zaleca się wyłączenie klawiatur firm trzecich w celu zwiększenia bezpieczeństwa.
- Należy być świadomym funkcji automatycznej korekty i podpowiedzi w domyślnej klawiaturze iOS, które mogą przechowywać wrażliwe informacje w plikach pamięci podręcznej znajdujących się w `Library/Keyboard/{locale}-dynamic-text.dat` lub `/private/var/mobile/Library/Keyboard/dynamic-text.dat`. Pliki pamięci podręcznej powinny być regularnie sprawdzane pod kątem wrażliwych danych. Zaleca się zresetowanie słownika klawiatury za pomocą **Ustawienia > Ogólne > Resetuj > Zresetuj słownik klawiatury** w celu usunięcia danych z pamięci podręcznej.
- Przechwytywanie ruchu sieciowego może ujawnić, czy niestandardowa klawiatura przesyła naciśnięcia klawiszy zdalnie.
### **Zapobieganie Pamięci Podręcznej Pola Tekstowego**
Protokół [UITextInputTraits](https://developer.apple.com/reference/uikit/uitextinputtraits) oferuje właściwości do zarządzania automatyczną korektą i bezpiecznym wprowadzaniem tekstu, co jest niezbędne do zapobiegania pamięci podręcznej wrażliwych informacji. Na przykład, wyłączenie automatycznej korekty i włączenie bezpiecznego wprowadzania tekstu można osiągnąć za pomocą:
```objectivec
textObject.autocorrectionType = UITextAutocorrectionTypeNo;
textObject.secureTextEntry = YES;
```
Dodatkowo, deweloperzy powinni upewnić się, że pola tekstowe, szczególnie te do wprowadzania wrażliwych informacji, takich jak hasła i PIN-y, wyłączają pamięć podręczną, ustawiając `autocorrectionType` na `UITextAutocorrectionTypeNo` i `secureTextEntry` na `YES`.
```objectivec
UITextField *textField = [[UITextField alloc] initWithFrame:frame];
textField.autocorrectionType = UITextAutocorrectionTypeNo;
```
## **Logi**
Debugowanie kodu często wiąże się z użyciem **logowania**. Istnieje ryzyko, ponieważ **logi mogą zawierać wrażliwe informacje**. Wcześniej, w iOS 6 i wcześniejszych wersjach, logi były dostępne dla wszystkich aplikacji, co stwarzało ryzyko wycieku wrażliwych danych. **Teraz aplikacje mają ograniczony dostęp tylko do swoich logów**.
Pomimo tych ograniczeń, **atakujący z fizycznym dostępem** do odblokowanego urządzenia może nadal to wykorzystać, podłączając urządzenie do komputera i **czytając logi**. Ważne jest, aby zauważyć, że logi pozostają na dysku nawet po odinstalowaniu aplikacji.
Aby zminimalizować ryzyko, zaleca się **dokładne interakcje z aplikacją**, eksplorując wszystkie jej funkcjonalności i dane wejściowe, aby upewnić się, że żadne wrażliwe informacje nie są rejestrowane przypadkowo.
Przy przeglądaniu kodu źródłowego aplikacji w poszukiwaniu potencjalnych wycieków, należy szukać zarówno **zdefiniowanych**, jak i **niestandardowych instrukcji logowania** używając słów kluczowych takich jak `NSLog`, `NSAssert`, `NSCAssert`, `fprintf` dla funkcji wbudowanych oraz wszelkich wzmiankach o `Logging` lub `Logfile` dla niestandardowych implementacji.
### **Monitorowanie logów systemowych**
Aplikacje rejestrują różne informacje, które mogą być wrażliwe. Aby monitorować te logi, użyj narzędzi i poleceń takich jak:
```bash
idevice_id --list # To find the device ID
idevicesyslog -u <id> (| grep <app>) # To capture the device logs
```
są przydatne. Dodatkowo, **Xcode** oferuje sposób na zbieranie logów konsoli:
1. Otwórz Xcode.
2. Podłącz urządzenie iOS.
3. Przejdź do **Window** -> **Devices and Simulators**.
4. Wybierz swoje urządzenie.
5. Wywołaj problem, który badałeś.
6. Użyj przycisku **Open Console**, aby wyświetlić logi w nowym oknie.
Dla bardziej zaawansowanego logowania, połączenie z powłoką urządzenia i użycie **socat** może zapewnić monitorowanie logów w czasie rzeczywistym:
```bash
iPhone:~ root# socat - UNIX-CONNECT:/var/run/lockdown/syslog.sock
```
Śledzone są polecenia do obserwacji aktywności logów, które mogą być nieocenione w diagnozowaniu problemów lub identyfikowaniu potencjalnych wycieków danych w logach.
## Kopie zapasowe
**Funkcje automatycznego tworzenia kopii zapasowych** są zintegrowane z iOS, ułatwiając tworzenie kopii danych urządzenia za pomocą iTunes (do macOS Catalina), Findera (od macOS Catalina) lub iCloud. Te kopie zapasowe obejmują prawie wszystkie dane urządzenia, z wyjątkiem wysoce wrażliwych elementów, takich jak szczegóły Apple Pay i konfiguracje Touch ID.
### Ryzyka bezpieczeństwa
Włączenie **zainstalowanych aplikacji i ich danych** do kopii zapasowych podnosi kwestię potencjalnego **wycieku danych** oraz ryzyko, że **zmiany w kopiach zapasowych mogą wpłynąć na funkcjonalność aplikacji**. Zaleca się **nieprzechowywanie wrażliwych informacji w postaci tekstu jawnego** w katalogu aplikacji ani jej podkatalogach, aby zminimalizować te ryzyka.
### Wykluczanie plików z kopii zapasowych
Pliki w `Documents/` i `Library/Application Support/` są domyślnie tworzone w kopiach zapasowych. Programiści mogą wykluczyć konkretne pliki lub katalogi z kopii zapasowych, używając `NSURL setResourceValue:forKey:error:` z `NSURLIsExcludedFromBackupKey`. Ta praktyka jest kluczowa dla ochrony wrażliwych danych przed uwzględnieniem w kopiach zapasowych.
### Testowanie pod kątem podatności
Aby ocenić bezpieczeństwo kopii zapasowych aplikacji, zacznij od **utworzenia kopii zapasowej** za pomocą Findera, a następnie zlokalizuj ją, korzystając z wskazówek zawartych w [oficjalnej dokumentacji Apple](https://support.apple.com/en-us/HT204215). Analizuj kopię zapasową pod kątem wrażliwych danych lub konfiguracji, które mogą być zmieniane, aby wpłynąć na zachowanie aplikacji.
Wrażliwe informacje można wyszukiwać za pomocą narzędzi wiersza poleceń lub aplikacji takich jak [iMazing](https://imazing.com). W przypadku zaszyfrowanych kopii zapasowych obecność szyfrowania można potwierdzić, sprawdzając klucz "IsEncrypted" w pliku "Manifest.plist" w katalogu głównym kopii zapasowej.
```xml
<?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>
```
Aby poradzić sobie z zaszyfrowanymi kopiami zapasowymi, przydatne mogą być skrypty Pythona dostępne w [repozytorium GitHub DinoSec](https://github.com/dinosec/iphone-dataprotection/tree/master/python_scripts), takie jak **backup_tool.py** i **backup_passwd.py**, chociaż mogą wymagać dostosowań w celu zapewnienia zgodności z najnowszymi wersjami iTunes/Finder. Narzędzie [**iOSbackup**](https://pypi.org/project/iOSbackup/) to kolejna opcja do uzyskiwania dostępu do plików w zabezpieczonych hasłem kopiach zapasowych.
### Modyfikowanie zachowania aplikacji
Przykład zmiany zachowania aplikacji poprzez modyfikacje kopii zapasowej można zobaczyć w aplikacji portfela bitcoin [Bither](https://github.com/bither/bither-ios), gdzie PIN blokady interfejsu użytkownika jest przechowywany w `net.bither.plist` pod kluczem **pin_code**. Usunięcie tego klucza z plist i przywrócenie kopii zapasowej usuwa wymóg podawania PIN-u, zapewniając nieograniczony dostęp.
## Podsumowanie testowania pamięci dla danych wrażliwych
Podczas pracy z wrażliwymi informacjami przechowywanymi w pamięci aplikacji, kluczowe jest ograniczenie czasu ekspozycji tych danych. Istnieją dwa główne podejścia do badania zawartości pamięci: **tworzenie zrzutu pamięci** i **analiza pamięci w czasie rzeczywistym**. Obie metody mają swoje wyzwania, w tym możliwość pominięcia krytycznych danych podczas procesu zrzutu lub analizy.
## **Odzyskiwanie i analiza zrzutu pamięci**
Dla urządzeń z jailbreakiem i bez jailbreaka, narzędzia takie jak [objection](https://github.com/sensepost/objection) i [Fridump](https://github.com/Nightbringer21/fridump) umożliwiają zrzut pamięci procesu aplikacji. Po zrzuceniu, analiza tych danych wymaga różnych narzędzi, w zależności od charakteru informacji, których szukasz.
Aby wyodrębnić ciągi ze zrzutu pamięci, można użyć poleceń takich jak `strings` lub `rabin2 -zz`:
```bash
# Extracting strings using strings command
$ strings memory > strings.txt
# Extracting strings using rabin2
$ rabin2 -ZZ memory > strings.txt
```
Aby uzyskać bardziej szczegółową analizę, w tym wyszukiwanie konkretnych typów danych lub wzorców, **radare2** oferuje rozbudowane możliwości wyszukiwania:
```bash
$ r2 <name_of_your_dump_file>
[0x00000000]> /?
...
```
## **Analiza pamięci w czasie rzeczywistym**
**r2frida** oferuje potężną alternatywę do inspekcji pamięci aplikacji w czasie rzeczywistym, bez potrzeby posiadania zrzutu pamięci. To narzędzie umożliwia wykonywanie poleceń wyszukiwania bezpośrednio w pamięci działającej aplikacji:
```bash
$ r2 frida://usb//<name_of_your_app>
[0x00000000]> /\ <search_command>
```
## Broken Cryptography
### Poor Key Management Processes
Niektórzy deweloperzy zapisują wrażliwe dane w lokalnej pamięci i szyfrują je kluczem zakodowanym/łatwym do przewidzenia w kodzie. Nie powinno się tego robić, ponieważ pewne techniki odwracania mogą pozwolić atakującym na wydobycie poufnych informacji.
### Use of Insecure and/or Deprecated Algorithms
Deweloperzy nie powinni używać **deprecated algorithms** do przeprowadzania **checks** autoryzacji, **store** lub **send** danych. Niektóre z tych algorytmów to: RC4, MD4, MD5, SHA1... Jeśli **hashes** są używane do przechowywania haseł, na przykład, powinny być używane **hashes** odporne na brute-force z solą.
### Check
Główne kontrole, które należy przeprowadzić, to sprawdzenie, czy można znaleźć **hardcoded** hasła/tajemnice w kodzie, czy są one **predictable**, oraz czy kod używa jakiegoś rodzaju **weak** **cryptography** algorithms.
Ciekawe jest to, że można **monitor** niektóre **crypto** **libraries** automatycznie za pomocą **objection** z:
```swift
ios monitor crypt
```
Dla **więcej informacji** na temat iOS kryptograficznych API i bibliotek, odwiedź [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)
## Uwierzytelnianie lokalne
**Uwierzytelnianie lokalne** odgrywa kluczową rolę, szczególnie w kontekście zabezpieczania dostępu do zdalnego punktu końcowego za pomocą metod kryptograficznych. Istotą jest to, że bez odpowiedniej implementacji mechanizmy uwierzytelniania lokalnego mogą być obejście.
Framework [**Local Authentication**](https://developer.apple.com/documentation/localauthentication) firmy Apple oraz [**keychain**](https://developer.apple.com/library/content/documentation/Security/Conceptual/keychainServConcepts/01introduction/introduction.html) oferują solidne API dla deweloperów, aby ułatwić dialogi uwierzytelniające użytkowników i bezpiecznie obsługiwać dane tajne. Secure Enclave zabezpiecza identyfikację odcisku palca dla Touch ID, podczas gdy Face ID opiera się na rozpoznawaniu twarzy bez kompromitowania danych biometrycznych.
Aby zintegrować Touch ID/Face ID, deweloperzy mają do wyboru dwa API:
- **`LocalAuthentication.framework`** do uwierzytelniania użytkowników na wysokim poziomie bez dostępu do danych biometrycznych.
- **`Security.framework`** do dostępu do usług keychain na niższym poziomie, zabezpieczając dane tajne za pomocą uwierzytelniania biometrycznego. Różne [open-source wrappers](https://www.raywenderlich.com/147308/secure-ios-user-data-keychain-touch-id) ułatwiają dostęp do keychain.
> [!CAUTION]
> Jednak zarówno `LocalAuthentication.framework`, jak i `Security.framework` mają luki, ponieważ głównie zwracają wartości boolean bez przesyłania danych do procesów uwierzytelniania, co czyni je podatnymi na obejście (zobacz [Don't touch me that way, by David Lindner et al](https://www.youtube.com/watch?v=XhXIHVGCFFM)).
### Implementacja uwierzytelniania lokalnego
Aby poprosić użytkowników o uwierzytelnienie, deweloperzy powinni wykorzystać metodę **`evaluatePolicy`** w klasie **`LAContext`**, wybierając między:
- **`deviceOwnerAuthentication`**: Prosi o Touch ID lub kod dostępu do urządzenia, niepowodzenie, jeśli żadne z nich nie jest włączone.
- **`deviceOwnerAuthenticationWithBiometrics`**: Wyłącznie prosi o Touch ID.
Sukces uwierzytelnienia jest wskazywany przez wartość boolean zwracaną z **`evaluatePolicy`**, co podkreśla potencjalną lukę w zabezpieczeniach.
### Uwierzytelnianie lokalne z użyciem Keychain
Implementacja **uwierzytelniania lokalnego** w aplikacjach iOS polega na użyciu **keychain APIs** do bezpiecznego przechowywania danych tajnych, takich jak tokeny uwierzytelniające. Proces ten zapewnia, że dane mogą być dostępne tylko dla użytkownika, korzystającego z kodu dostępu do urządzenia lub uwierzytelnienia biometrycznego, takiego jak Touch ID.
Keychain oferuje możliwość ustawienia elementów z atrybutem `SecAccessControl`, który ogranicza dostęp do elementu, dopóki użytkownik nie uwierzytelni się pomyślnie za pomocą Touch ID lub kodu dostępu do urządzenia. Ta funkcja jest kluczowa dla zwiększenia bezpieczeństwa.
Poniżej znajdują się przykłady kodu w Swift i Objective-C demonstrujące, jak zapisać i odzyskać ciąg z keychain, wykorzystując te funkcje zabezpieczeń. Przykłady pokazują, jak skonfigurować kontrolę dostępu, aby wymagała uwierzytelnienia Touch ID i zapewniała, że dane są dostępne tylko na urządzeniu, na którym zostały skonfigurowane, pod warunkiem, że kod dostępu do urządzenia jest skonfigurowany.
{{#tabs}}
{{#tab name="Swift"}}
```swift
// From https://github.com/mufambisi/owasp-mstg/blob/master/Document/0x06f-Testing-Local-Authentication.md
// 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 name="Objective-C"}}
```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}}
{{#endtabs}}
Teraz możemy zażądać zapisanej pozycji z keychain. Usługi keychain wyświetlą użytkownikowi okno dialogowe uwierzytelniania i zwrócą dane lub nil w zależności od tego, czy podano odpowiedni odcisk palca, czy nie.
{{#tabs}}
{{#tab name="Swift"}}
```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 name="Objective-C"}}
```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}}
### Wykrywanie
Użycie frameworków w aplikacji można również wykryć, analizując listę współdzielonych bibliotek dynamicznych w binarnej wersji aplikacji. Można to zrobić za pomocą `otool`:
```bash
$ otool -L <AppName>.app/<AppName>
```
Jeśli `LocalAuthentication.framework` jest używany w aplikacji, wynik będzie zawierał obie poniższe linie (pamiętaj, że `LocalAuthentication.framework` używa `Security.framework` w tle):
```bash
/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication
/System/Library/Frameworks/Security.framework/Security
```
Jeśli używany jest `Security.framework`, tylko drugi zostanie wyświetlony.
### Ominięcie lokalnego uwierzytelniania
#### **Objection**
Dzięki **Objection Biometrics Bypass**, znajdującemu się na [tej stronie GitHub](https://github.com/sensepost/objection/wiki/Understanding-the-iOS-Biometrics-Bypass), dostępna jest technika umożliwiająca pokonanie mechanizmu **LocalAuthentication**. Sedno tego podejścia polega na wykorzystaniu **Frida** do manipulacji funkcją `evaluatePolicy`, zapewniając, że zawsze zwraca wynik `True`, niezależnie od rzeczywistego sukcesu uwierzytelnienia. Jest to szczególnie przydatne do omijania wadliwych procesów uwierzytelniania biometrycznego.
Aby aktywować to ominięcie, używana jest następująca komenda:
```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
```
To polecenie uruchamia sekwencję, w której Objection rejestruje zadanie, które skutecznie zmienia wynik sprawdzenia `evaluatePolicy` na `True`.
#### Frida
Przykład użycia **`evaluatePolicy`** z aplikacji [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"];
});
}
}
```
Aby osiągnąć **obejście** lokalnej autoryzacji, napisano skrypt Frida. Skrypt ten celuje w kontrolę **evaluatePolicy**, przechwytując jej callback, aby upewnić się, że zwraca **success=1**. Poprzez zmianę zachowania callbacka, kontrola autoryzacji jest skutecznie omijana.
Poniższy skrypt jest wstrzykiwany, aby zmodyfikować wynik metody **evaluatePolicy**. Zmienia wynik callbacka, aby zawsze wskazywał na sukces.
```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!");
}
```
Aby wstrzyknąć skrypt Frida i obejść uwierzytelnianie biometryczne, używa się następującego polecenia:
```bash
frida -U -f com.highaltitudehacks.DVIAswiftv2 --no-pause -l fingerprint-bypass-ios.js
```
## Ekspozycja Wrażliwej Funkcjonalności przez IPC
### Niestandardowe Obsługiwacze URI / Deeplinks / Niestandardowe Schematy
{{#ref}}
ios-custom-uri-handlers-deeplinks-custom-schemes.md
{{#endref}}
### Uniwersalne Linki
{{#ref}}
ios-universal-links.md
{{#endref}}
### Udostępnianie UIActivity
{{#ref}}
ios-uiactivity-sharing.md
{{#endref}}
### UIPasteboard
{{#ref}}
ios-uipasteboard.md
{{#endref}}
### Rozszerzenia Aplikacji
{{#ref}}
ios-app-extensions.md
{{#endref}}
### WebViews
{{#ref}}
ios-webviews.md
{{#endref}}
### Serializacja i Kodowanie
{{#ref}}
ios-serialisation-and-encoding.md
{{#endref}}
## Komunikacja Sieciowa
Ważne jest, aby sprawdzić, czy nie zachodzi żadna komunikacja **bez szyfrowania** oraz czy aplikacja poprawnie **waliduje certyfikat TLS** serwera.\
Aby sprawdzić te problemy, możesz użyć proxy, takiego jak **Burp**:
{{#ref}}
burp-configuration-for-ios.md
{{#endref}}
### Sprawdzenie Nazwy Host
Jednym z powszechnych problemów przy walidacji certyfikatu TLS jest sprawdzenie, czy certyfikat został podpisany przez **zaufane** **CA**, ale **nie sprawdzenie**, czy **nazwa hosta** certyfikatu jest nazwą hosta, do której się uzyskuje dostęp.\
Aby sprawdzić ten problem za pomocą Burp, po zaufaniu Burp CA na iPhonie, możesz **utworzyć nowy certyfikat z Burp dla innej nazwy hosta** i go użyć. Jeśli aplikacja nadal działa, to coś jest podatne.
### Pinning Certyfikatu
Jeśli aplikacja poprawnie używa SSL Pinning, to aplikacja będzie działać tylko wtedy, gdy certyfikat jest tym, którego się oczekuje. Podczas testowania aplikacji **może to być problem, ponieważ Burp będzie serwować swój własny certyfikat.**\
Aby obejść tę ochronę na urządzeniu z jailbreakiem, możesz zainstalować aplikację [**SSL Kill Switch**](https://github.com/nabla-c0d3/ssl-kill-switch2) lub zainstalować [**Burp Mobile Assistant**](https://portswigger.net/burp/documentation/desktop/mobile/config-ios-device)
Możesz również użyć **objection's** `ios sslpinning disable`
## Różne
- W **`/System/Library`** możesz znaleźć frameworki zainstalowane w telefonie używane przez aplikacje systemowe
- Aplikacje zainstalowane przez użytkownika z App Store znajdują się w **`/User/Applications`**
- A **`/User/Library`** zawiera dane zapisane przez aplikacje na poziomie użytkownika
- Możesz uzyskać dostęp do **`/User/Library/Notes/notes.sqlite`**, aby przeczytać notatki zapisane w aplikacji.
- W folderze zainstalowanej aplikacji (**`/User/Applications/<APP ID>/`**) możesz znaleźć kilka interesujących plików:
- **`iTunesArtwork`**: Ikona używana przez aplikację
- **`iTunesMetadata.plist`**: Informacje o aplikacji używane w App Store
- **`/Library/*`**: Zawiera preferencje i pamięć podręczną. W **`/Library/Cache/Snapshots/*`** możesz znaleźć zrzut wykonany dla aplikacji przed wysłaniem jej w tle.
### Hot Patching/Wymuszone Aktualizacje
Deweloperzy mogą zdalnie **natychmiastowo łatać wszystkie instalacje swojej aplikacji** bez konieczności ponownego przesyłania aplikacji do App Store i czekania na jej zatwierdzenie.\
W tym celu zazwyczaj używa się [**JSPatch**](https://github.com/bang590/JSPatch)**.** Istnieją jednak również inne opcje, takie jak [Siren](https://github.com/ArtSabintsev/Siren) i [react-native-appstore-version-checker](https://www.npmjs.com/package/react-native-appstore-version-checker).\
**To niebezpieczny mechanizm, który może być nadużywany przez złośliwe SDK, dlatego zaleca się sprawdzenie, która metoda jest używana do automatycznych aktualizacji (jeśli w ogóle) i przetestowanie jej.** Możesz spróbować pobrać wcześniejszą wersję aplikacji w tym celu.
### Strony Trzecie
Znaczącym wyzwaniem związanym z **SDK stron trzecich** jest **brak szczegółowej kontroli** nad ich funkcjonalnościami. Deweloperzy stają przed wyborem: albo zintegrować SDK i zaakceptować wszystkie jego funkcje, w tym potencjalne luki w zabezpieczeniach i obawy dotyczące prywatności, albo całkowicie zrezygnować z jego korzyści. Często deweloperzy nie są w stanie sami łatać luk w tych SDK. Ponadto, gdy SDK zyskują zaufanie w społeczności, niektóre mogą zacząć zawierać złośliwe oprogramowanie.
Usługi świadczone przez SDK stron trzecich mogą obejmować śledzenie zachowań użytkowników, wyświetlanie reklam lub ulepszanie doświadczeń użytkowników. Jednak wprowadza to ryzyko, ponieważ deweloperzy mogą nie być w pełni świadomi kodu wykonywanego przez te biblioteki, co prowadzi do potencjalnych zagrożeń dla prywatności i bezpieczeństwa. Ważne jest, aby ograniczyć informacje udostępniane usługom stron trzecich do niezbędnych i upewnić się, że żadne wrażliwe dane nie są ujawniane.
Implementacja usług stron trzecich zazwyczaj występuje w dwóch formach: jako samodzielna biblioteka lub pełne SDK. Aby chronić prywatność użytkowników, wszelkie dane udostępniane tym usługom powinny być **anonimizowane**, aby zapobiec ujawnieniu Osobowych Danych Identyfikowalnych (PII).
Aby zidentyfikować biblioteki używane przez aplikację, można użyć polecenia **`otool`**. To narzędzie powinno być uruchamiane w odniesieniu do aplikacji i każdej używanej przez nią biblioteki współdzielonej, aby odkryć dodatkowe biblioteki.
```bash
otool -L <application_path>
```
## **Odnośniki i dodatkowe zasoby**
- [https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06b-basic-security-testing#information-gathering](https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06b-basic-security-testing#information-gathering)
- [iOS & Mobile App Pentesting - INE](https://my.ine.com/CyberSecurity/courses/089d060b/ios-mobile-app-pentesting)
- [https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0057/](https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0057/)
- [https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0058/](https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0058/)
- [https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0059/](https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0059/)
- [https://mas.owasp.org/MASTG/iOS/0x06d-Testing-Data-Storage](https://mas.owasp.org/MASTG/iOS/0x06d-Testing-Data-Storage)
- [https://coderwall.com/p/kjb3lw/storing-password-in-keychain-the-smart-way](https://coderwall.com/p/kjb3lw/storing-password-in-keychain-the-smart-way)
- [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0055/](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0055/)
- [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0053](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0053)
- [https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0060/](https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0060/)
- [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0058](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0058)
- [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0060](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0060)
- [https://mas.owasp.org/MASTG/Android/0x05f-Testing-Local-Authentication/](https://mas.owasp.org/MASTG/Android/0x05f-Testing-Local-Authentication/)
- [https://mas.owasp.org/MASTG/tests/ios/MASVS-AUTH/MASTG-TEST-0064](https://mas.owasp.org/MASTG/tests/ios/MASVS-AUTH/MASTG-TEST-0064)
- [https://medium.com/securing/bypassing-your-apps-biometric-checks-on-ios-c2555c81a2dc](https://medium.com/securing/bypassing-your-apps-biometric-checks-on-ios-c2555c81a2dc)
- [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0054](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0054)
- [https://github.com/ivRodriguezCA/RE-iOS-Apps/](https://github.com/ivRodriguezCA/RE-iOS-Apps/) kurs IOS za darmo([https://syrion.me/blog/ios-swift-antijailbreak-bypass-frida/](https://syrion.me/blog/ios-swift-antijailbreak-bypass-frida/))
- [https://www.sans.org/reading-room/whitepapers/testing/ipwn-apps-pentesting-ios-applications-34577](https://www.sans.org/reading-room/whitepapers/testing/ipwn-apps-pentesting-ios-applications-34577)
- [https://www.slideshare.net/RyanISI/ios-appsecurityminicourse](https://www.slideshare.net/RyanISI/ios-appsecurityminicourse)
- [https://github.com/prateek147/DVIA](https://github.com/prateek147/DVIA)
- [https://github.com/prateek147/DVIA-v2](https://github.com/prateek147/DVIA-v2)
- [https://github.com/OWASP/MSTG-Hacking-Playground%20](https://github.com/OWASP/MSTG-Hacking-Playground)
- OWASP iGoat [_https://github.com/OWASP/igoat_](https://github.com/OWASP/igoat) <<< wersja Objective-C [_https://github.com/OWASP/iGoat-Swift_](https://github.com/OWASP/iGoat-Swift) <<< wersja Swift
- [https://github.com/authenticationfailure/WheresMyBrowser.iOS](https://github.com/authenticationfailure/WheresMyBrowser.iOS)
- [https://github.com/nabla-c0d3/ssl-kill-switch2](https://github.com/nabla-c0d3/ssl-kill-switch2)
{{#include ../../banners/hacktricks-training.md}}