iOS Pentesting

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Podstawy iOS

iOS Basics

Środowisko testowe

Na tej stronie znajdziesz informacje o iOS simulator, emulators i jailbreaking:

iOS Testing Environment

Wstępna analiza

Podstawowe operacje testowania iOS

Podczas testów zostanie zasugerowanych kilka operacji (połączenie z urządzeniem, odczyt/zapis/upload/download plików, użycie narzędzi…). Jeśli nie wiesz jak wykonać którąkolwiek z tych czynności, rozpocznij czytanie strony:

iOS Basic Testing Operations

Tip

For the following steps the app should be installed in the device and should have already obtained the IPA file of the application.
Read the Basic iOS Testing Operations page to learn how to do this.

Podstawowa analiza statyczna

Kilka ciekawych dekompilatorów iOS - IPA files:

Zaleca się użycie narzędzia MobSF do wykonania automatycznej analizy statycznej pliku IPA.

Identyfikacja zabezpieczeń obecnych w binarnym pliku:

  • PIE (Position Independent Executable): Gdy jest włączone, aplikacja ładuje się pod losowy adres pamięci przy każdym uruchomieniu, co utrudnia przewidzenie początkowego adresu pamięci.
otool -hv <app-binary> | grep PIE   # It should include the PIE flag
  • Stack Canaries: Aby zweryfikować integralność stosu, przed wywołaniem funkcji umieszczana jest wartość „canary”, która jest sprawdzana po zakończeniu funkcji.
otool -I -v <app-binary> | grep stack_chk   # It should include the symbols: stack_chk_guard and stack_chk_fail
  • ARC (Automatic Reference Counting): Aby zapobiegać typowym błędom korupcji pamięci
otool -I -v <app-binary> | grep objc_release   # It should include the _objc_release symbol
  • Encrypted Binary: Binar powinien być zaszyfrowany
otool -arch all -Vl <app-binary> | grep -A5 LC_ENCRYPT   # The cryptid should be 1

Identyfikacja wrażliwych/niebezpiecznych funkcji

  • Weak Hashing Algorithms
# On the iOS device
otool -Iv <app> | grep -w "_CC_MD5"
otool -Iv <app> | grep -w "_CC_SHA1"

# On linux
grep -iER "_CC_MD5"
grep -iER "_CC_SHA1"
  • Insecure Random Functions
# On the iOS device
otool -Iv <app> | grep -w "_random"
otool -Iv <app> | grep -w "_srand"
otool -Iv <app> | grep -w "_rand"

# On linux
grep -iER "_random"
grep -iER "_srand"
grep -iER "_rand"
  • Insecure ‘Malloc’ Function
# On the iOS device
otool -Iv <app> | grep -w "_malloc"

# On linux
grep -iER "_malloc"
  • Insecure and Vulnerable Functions
# On the iOS device
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"

# On 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"

Typowe metody wykrywania jailbreak

  • File System Checks: Sprawdzanie obecności typowych plików i katalogów jailbreak, takich jak /Applications/Cydia.app lub /Library/MobileSubstrate/MobileSubstrate.dylib.
  • Sandbox Violations: Próba dostępu do zastrzeżonych obszarów systemu plików, które powinny być zablokowane na urządzeniach bez jailbreak.
  • API Checks: Sprawdzenie czy można użyć zabronionych wywołań takich jak fork() do utworzenia procesu potomnego lub system() aby sprawdzić czy istnieje /bin/sh.
  • Process Checks: Monitorowanie obecności znanych procesów związanych z jailbreak, takich jak Cydia, Substrate, lub ssh.
  • Kernel Exploits: Sprawdzenie obecności exploitów jądra, które są często używane w jailbreakach.
  • Environment Variables: Inspekcja zmiennych środowiskowych pod kątem oznak jailbreak, takich jak DYLD_INSERT_LIBRARIES.
  • Libraries Check: Sprawdzenie bibliotek załadowanych do procesu aplikacji.
  • Check schemes: Na przykład canOpenURL(URL(string: "cydia://")).

Typowe metody wykrywania anti-debugging

  • Check for Debugger Presence: Użycie sysctl lub innych metod do sprawdzenia, czy debugger jest podłączony.
  • Anti-Debugging APIs: Szukanie wywołań API anti-debugging takich jak ptrace lub SIGSTOP, np. ptrace(PT_DENY_ATTACH, 0, 0, 0).
  • Timing Checks: Pomiar czasu wykonania pewnych operacji i szukanie rozbieżności mogących wskazywać debugowanie.
  • Memory Checks: Inspekcja pamięci pod kątem znanych artefaktów debuggera lub modyfikacji.
  • Environment Variables: Sprawdzanie zmiennych środowiskowych, które mogą wskazywać sesję debugowania.
  • Mach Ports: Wykrywanie czy mach exception ports są używane przez debugery.

Anti-Debugging & Anti-Tamper Techniques (Layered Checks)

Aplikacje z prawdziwego świata często nakładają kontrole pre-exec, on-attach oraz ciągłe. Typowe wzorce do zidentyfikowania (i sposoby ich neutralizacji podczas testów):

  • Private API side-channel fingerprinting: prywatne launch API (np. SBSLaunchApplicationWithIdentifierAndURLAndLaunchOptions) są nadużywane do sprawdzania zainstalowanych bundle ID (com.opa334.TrollStore, org.coolstar.SileoStore, com.tigisoftware.Filza, itd.) na podstawie kodów zwrotnych/logów. Zhakuj (hook) wywołanie i oczyszczaj argumenty/wartości zwracane, aby emulować czyste urządzenie.
  • Self-attestation via code-signing state: csops() z CS_OPS_ENTITLEMENTS_BLOB odczytuje entitlements; nieoczekiwane wartości powodują zakończenie działania. Łączy się to z kontrolą integralności (CRC32/MD5 zasobów, weryfikacja certyfikatów, metadane Mach-O jak LC_ENCRYPTION_INFO_64) w celu wykrycia ponownego podpisania lub załatania. Instrumentuj te rutyny i wymuszaj “oczekiwane” wyniki podczas analizy.
  • Kill-on-attach: ptrace(PT_DENY_ATTACH) w połączeniu z abort()/exit() podczas attach. Obejście przez unieszkodliwienie ścieżki zakończenia lub hookowanie ptrace tak, by zakończyło się sukcesem bez wymuszania odmowy.
  • Crash forensics sabotage: nadpisywanie rejestrów CPU przed awarią, by zniszczyć backtrace. Lepiej stosować breakpointy/hooki wcześniej w ścieżce detekcji zamiast polegać na logach awarii.
  • Jetsam-based termination: celowe wywołanie presji pamięciowej by uruchomić jetsam, który nie generuje normalnego logu awarii. Szukaj dużych alokacji wokół logiki detekcji i ogranicz/skrótuj je, aby zachować logi.
  • Continuous checks with delayed enforcement: timery heartbeat ponownie uruchamiają detekcję i egzekwują później. Śledź timery/dispatch sources i utrzymuj proces przy życiu, omijając opóźnioną ścieżkę zabicia.

Podstawowa analiza dynamiczna

Sprawdź analizę dynamiczną, którą wykonuje MobSF. Będziesz musiał przechodzić przez różne widoki i wchodzić z nimi w interakcję — narzędzie będzie hookować kilka klas przy realizowaniu różnych zadań i przygotuje raport po zakończeniu.

Wyświetlanie zainstalowanych aplikacji

Użyj polecenia frida-ps -Uai aby określić bundle identifier zainstalowanych aplikacji:

$ 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

Basic Enumeration & Hooking

Dowiedz się, jak enumerate the components of the application oraz jak łatwo hook methods and classes za pomocą objection:

iOS Hooking With Objection

Struktura IPA

Struktura pliku IPA file jest w zasadzie taka sama jak zipped package. Zmieniając jego rozszerzenie na .zip, można go dekompresować, aby odsłonić zawartość. W tej strukturze Bundle reprezentuje w pełni zapakowaną aplikację gotową do instalacji. Wewnątrz znajdziesz katalog o nazwie <NAME>.app, który kapsułkuje zasoby aplikacji.

  • Info.plist: Ten plik zawiera szczegółowe informacje konfiguracyjne aplikacji.
  • _CodeSignature/: Ten katalog zawiera plik plist, który zawiera podpis, zapewniający integralność wszystkich plików w bundle.
  • Assets.car: Skompresowane archiwum przechowujące pliki zasobów, takie jak ikony.
  • Frameworks/: Ten folder mieści natywne biblioteki aplikacji, które mogą występować w postaci plików .dylib lub .framework.
  • PlugIns/: Ten katalog może zawierać rozszerzenia aplikacji, znane jako pliki .appex, choć nie zawsze występują. * Core Data: Służy do zapisywania trwałych danych aplikacji do użytku offline, cache’owania danych tymczasowych oraz dodawania funkcji cofania (undo) w aplikacji na pojedynczym urządzeniu. Aby synchronizować dane między wieloma urządzeniami w ramach jednego konta iCloud, Core Data automatycznie odwzorowuje schemat do kontenera CloudKit.
  • PkgInfo: Plik PkgInfo jest alternatywnym sposobem określania kodów typu i twórcy twojej aplikacji lub bundle.
  • en.lproj, fr.proj, Base.lproj: To pakiety językowe zawierające zasoby dla tych konkretnych języków oraz domyślne zasoby na wypadek, gdy dany język nie jest wspierany.
  • Bezpieczeństwo: Katalog _CodeSignature/ odgrywa kluczową rolę w bezpieczeństwie aplikacji, weryfikując integralność wszystkich dołączonych plików 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 rozmiaru.
  • Frameworks and PlugIns: Te katalogi podkreślają modularność aplikacji iOS, pozwalając deweloperom dołączać wielokrotnego użytku biblioteki kodu (Frameworks/) oraz rozszerzać funkcjonalność aplikacji (PlugIns/).
  • Lokalizacja: Struktura wspiera wiele języków, ułatwiając globalne dotarcie aplikacji poprzez dołączanie zasobów dla konkretnych pakietów językowych.

Info.plist

Plik Info.plist służy jako kamień węgielny aplikacji iOS, kapsułkując kluczowe dane konfiguracyjne w postaci par key-value. Plik ten jest wymagany nie tylko dla aplikacji, lecz także dla rozszerzeń aplikacji i frameworków dołączonych w bundle. Ma strukturę w formacie XML lub binarnym i zawiera krytyczne informacje — od uprawnień aplikacji po konfiguracje bezpieczeństwa. Aby szczegółowo zapoznać się z dostępnymi kluczami, można odwołać się do Apple Developer Documentation.

Dla tych, którzy chcą pracować z tym plikiem w bardziej dostępnym formacie, konwersję do XML można łatwo przeprowadzić za pomocą plutil na macOS (dostępnego natywnie w wersjach 10.2 i nowszych) lub plistutil na Linuxie. Polecenia do konwersji są następujące:

  • Dla macOS:
$ plutil -convert xml1 Info.plist
  • Dla Linuxa:
$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist

Spośród mnogości informacji, które plik Info.plist może ujawnić, godne uwagi wpisy to ciągi uprawnień aplikacji (UsageDescription), niestandardowe schematy URL (CFBundleURLTypes) oraz konfiguracje App Transport Security (NSAppTransportSecurity). Te wpisy, wraz z innymi, takimi jak eksportowane/importowane niestandardowe typy dokumentów (UTExportedTypeDeclarations / UTImportedTypeDeclarations), można z łatwością znaleźć, przeglądając plik lub używając prostego polecenia grep:

$ grep -i <keyword> Info.plist

Ścieżki danych

W środowisku iOS katalogi są przeznaczone oddzielnie dla aplikacji systemowych i aplikacji zainstalowanych przez użytkownika. Aplikacje systemowe znajdują się w katalogu /Applications, natomiast aplikacje zainstalowane przez użytkownika są umieszczone w /var/mobile/containers/Data/Application/. Każdej z tych aplikacji przypisywany jest unikatowy identyfikator znany jako 128-bit UUID, co utrudnia ręczne odnalezienie folderu aplikacji ze względu na losowość nazw katalogów.

Warning

Ponieważ aplikacje w iOS muszą być sandboxed, każda aplikacja będzie miała również folder w $HOME/Library/Containers o nazwie będącej CFBundleIdentifier aplikacji.

Jednak oba foldery (folder danych i folder kontenera) zawierają plik .com.apple.mobile_container_manager.metadata.plist, który łączy oba foldery w kluczu MCMetadataIdentifier).

Aby ułatwić odkrycie katalogu instalacyjnego aplikacji zainstalowanej przez użytkownika, narzędzie objection udostępnia przydatne polecenie env. Polecenie to ujawnia szczegółowe informacje o katalogach dla danej aplikacji. Poniżej znajduje się przykład użycia tego polecenia:

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 katalogu /private/var/containers przy użyciu polecenia find:

find /private/var/containers -name "Progname*"

Polecenia takie jak ps i lsof można również wykorzystać odpowiednio do zidentyfikowania procesu aplikacji oraz wypisania otwartych plików, co daje wgląd w aktywne ścieżki katalogów aplikacji:

ps -ef | grep -i <app-name>
lsof -p <pid> | grep -i "/containers" | head -n 1

Bundle directory:

  • AppName.app
  • Jest to Application Bundle, jak wcześniej w IPA — zawiera istotne dane aplikacji, statyczne zasoby oraz skompilowany binarny plik aplikacji.
  • Ten katalog jest widoczny dla użytkowników, ale użytkownicy nie mogą w nim zapisywać.
  • Zawartość tego katalogu nie jest objęta kopią zapasową.
  • Zawartość tego folderu jest używana do weryfikacji podpisu kodu.

Data directory:

  • Documents/
  • Zawiera wszystkie dane generowane przez użytkownika. Końcowy użytkownik aplikacji inicjuje tworzenie tych danych.
  • Widoczne dla użytkowników i użytkownicy mogą w nim zapisywać.
  • Zawartość tego katalogu jest objęta kopią zapasową.
  • Aplikacja może wykluczyć ścieżki ustawiając NSURLIsExcludedFromBackupKey.
  • Library/
  • Zawiera wszystkie pliki, które nie są specyficzne dla użytkownika, takie jak caches, preferences, cookies, oraz pliki konfiguracyjne property list (plist).
  • Aplikacje iOS zwykle używają podkatalogów Application Support i Caches, ale aplikacja może stworzyć własne podkatalogi.
  • Library/Caches/
  • Zawiera półtrwałe pliki cache.
  • Niewidoczne dla użytkowników i użytkownicy nie mogą w nim zapisywać.
  • Zawartość tego katalogu nie jest objęta kopią zapasową.
  • System może automatycznie usuwać pliki z tego katalogu, gdy aplikacja nie jest uruchomiona i przestrzeń dyskowa jest ograniczona.
  • Library/Application Support/
  • Zawiera trwałe pliki niezbędne do działania aplikacji.
  • Niewidoczne dla użytkowników i użytkownicy nie mogą w nim zapisywać.
  • Zawartość tego katalogu jest objęta kopią zapasową.
  • Aplikacja może wykluczyć ścieżki ustawiając NSURLIsExcludedFromBackupKey.
  • Library/Preferences/
  • Służy do przechowywania właściwości, które mogą utrzymywać się nawet po ponownym uruchomieniu aplikacji.
  • Informacje są zapisywane, niezaszyfrowane, wewnątrz sandboxa aplikacji w pliku plist o nazwie [BUNDLE_ID].plist.
  • Wszystkie pary klucz/wartość przechowywane przy użyciu NSUserDefaults można znaleźć w tym pliku.
  • tmp/
  • Użyj tego katalogu do zapisu plików tymczasowych, które nie muszą przetrwać między uruchomieniami aplikacji.
  • Zawiera niepermanentne pliki cache.
  • Niewidoczne dla użytkowników.
  • Zawartość tego katalogu nie jest objęta kopią zapasową.
  • System może automatycznie usuwać pliki z tego katalogu, gdy aplikacja nie jest uruchomiona i przestrzeń dyskowa jest ograniczona.

Przyjrzyjmy się bliżej katalogowi Application Bundle (.app) iGoat-Swift wewnątrz katalogu Bundle (/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app):

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ę binarki za pomocą narzędzia otool:

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 jakikolwiek output dla:

otool -l <app-binary> | grep -A 4 LC_ENCRYPTION_INFO

Dysasemblacja pliku binarnego

Disasembluj sekcję .text:

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ć:

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 kompaktowy kod Objective-C, możesz użyć class-dump:

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;
};

However, the best options to disassemble the binary are: Hopper and IDA.

Przechowywanie danych

Aby dowiedzieć się, jak iOS przechowuje dane na urządzeniu, przeczytaj tę stronę:

iOS Basics

Warning

Następujące miejsca przechowywania informacji powinny być sprawdzone bezpośrednio po zainstalowaniu aplikacji, po sprawdzeniu wszystkich funkcjonalności aplikacji oraz nawet po wylogowaniu się z jednego użytkownika i zalogowaniu do innego.
Celem jest znalezienie niechronionych poufnych informacji aplikacji (hasła, tokeny), danych bieżącego użytkownika oraz wcześniej zalogowanych użytkowników.

Plist

Pliki plist to uporządkowane pliki XML, które zawierają pary klucz-wartość. To sposób przechowywania danych trwałych, więc czasami możesz znaleźć w tych plikach poufne informacje. Zaleca się sprawdzić te pliki po zainstalowaniu aplikacji oraz po intensywnym jej używaniu, aby zobaczyć, czy zapisywane są nowe dane.

Najczęstszym sposobem utrwalania danych w plikach plist jest użycie NSUserDefaults. Ten plik plist jest zapisywany w sandboxie aplikacji w Library/Preferences/<appBundleID>.plist

Klasa NSUserDefaults zapewnia programowy interfejs do interakcji z systemem domyślnym. System domyślny pozwala aplikacji dostosować swoje zachowanie zgodnie z preferencjami użytkownika. Dane zapisane przez NSUserDefaults można przeglądać w bundle aplikacji. Ta klasa przechowuje dane w pliku plist, ale jest przeznaczona do użycia przy niewielkich ilościach danych.

Do tych danych nie można już bezpośrednio uzyskać dostępu za pomocą zaufanego komputera, ale można uzyskać do nich dostęp wykonując backup.

Możesz dump informacji zapisanych przy użyciu NSUserDefaults za pomocą objection: ios nsuserdefaults get

Aby znaleźć wszystkie pliki plist używane przez aplikację, możesz uzyskać dostęp do /private/var/mobile/Containers/Data/Application/{APPID} i uruchomić:

find ./ -name "*.plist"

Aby przekonwertować pliki z formatu XML or binary (bplist) na XML, dostępne są różne metody w zależności od systemu operacyjnego:

Dla użytkowników macOS: Użyj polecenia plutil. To narzędzie wbudowane w macOS (10.2+), przeznaczone do tego celu:

$ plutil -convert xml1 Info.plist

Dla użytkowników Linuksa: Zainstaluj najpierw libplist-utils, a następnie użyj plistutil, aby skonwertować swój plik:

$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist

Within an Objection Session: Do analizy aplikacji mobilnych, konkretna komenda pozwala bezpośrednio konwertować pliki plist:

ios plist cat /private/var/mobile/Containers/Data/Application/<Application-UUID>/Library/Preferences/com.some.package.app.plist

Core Data

Core Data to framework służący do zarządzania warstwą modelu obiektów w aplikacji. Core Data może używać SQLite jako persistent store, ale sam framework nie jest bazą danych.
CoreData nie szyfruje danych domyślnie. Można jednak dodać dodatkową warstwę szyfrowania do CoreData. Zobacz GitHub Repo po więcej informacji.

Informacje SQLite Core Data aplikacji znajdują się pod ścieżką /private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support

Jeśli możesz otworzyć SQLite i uzyskać dostęp do wrażliwych informacji, oznacza to, że wykryto nieprawidłową konfigurację.

-(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 to magazyn klucz/wartość zbudowany na SQLite.
Ponieważ bazy Yap są bazami SQLite, możesz je znaleźć używając polecenia podanego w poprzedniej sekcji.

Other SQLite Databases

Aplikacje często tworzą własne bazy danych SQLite. Mogą w nich przechowywać wrażliwe dane i pozostawiać je niezaszyfrowane. Dlatego zawsze warto sprawdzić każdą bazę danych w katalogu aplikacji. Przejdź do katalogu aplikacji, w którym zapisywane są dane (/private/var/mobile/Containers/Data/Application/{APPID})

find ./ -name "*.sqlite" -or -name "*.db"

Firebase Real-Time Databases

Programiści mogą przechowywać i synchronizować dane w NoSQL bazie danych hostowanej w chmurze za pomocą Firebase Real-Time Databases. Dane są przechowywane w formacie JSON i synchronizowane ze wszystkimi połączonymi klientami w czasie rzeczywistym.

You can find how to check for misconfigured Firebase databases here:

Firebase Database

Realm databases

Realm Objective-C and Realm Swift oferują potężną alternatywę dla przechowywania danych, której nie zapewnia Apple. Domyślnie przechowują dane bez szyfrowania, a szyfrowanie jest dostępne po odpowiedniej konfiguracji.

Bazy danych znajdują się pod ścieżką: /private/var/mobile/Containers/Data/Application/{APPID}. Aby przeglądać te pliki, można użyć poleceń takich jak:

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*"

Do przeglądania tych plików bazy danych rekomendowane jest narzędzie Realm Studio.

Aby zaimplementować encryption w bazie danych Realm, można użyć następującego fragmentu kodu:

// 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)")
}

Couchbase Lite Bazy danych

Couchbase Lite jest opisywana jako lekki i wbudowany silnik bazy danych, który stosuje podejście zorientowane na dokumenty (NoSQL). Zaprojektowany jako natywny dla iOS i macOS, umożliwia bezproblemową synchronizację danych.

Aby zidentyfikować potencjalne bazy danych Couchbase na urządzeniu, należy sprawdzić następujący katalog:

ls /private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support/

Ciasteczka

iOS przechowuje cookies aplikacji w Library/Cookies/cookies.binarycookies w folderze każdej aplikacji. Jednak deweloperzy czasami decydują się zapisać je w keychain, ponieważ wspomniany plik cookie może być dostępny w kopiach zapasowych.

Aby przejrzeć plik cookie możesz użyć this python script lub użyć objection z poleceniem ios cookies get.\ Możesz też użyć objection, aby skonwertować te pliki do formatu JSON i przeanalizować dane.

...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"
}
]

Pamięć podręczna

Domyślnie NSURLSession przechowuje dane, takie jak żądania i odpowiedzi HTTP w Cache.db. Ta baza danych może zawierać wrażliwe dane, jeśli tokeny, nazwy użytkowników lub inne poufne 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>. WebKit cache jest również przechowywany w pliku Cache.db. Objection może otworzyć i operować na bazie poleceniem sqlite connect Cache.db, ponieważ jest to zwykła baza SQLite.

Zaleca się wyłączenie przechowywania w pamięci podręcznej tych danych, ponieważ mogą one zawierać poufne informacje w żądaniu lub odpowiedzi. Poniższa lista pokazuje różne sposoby osiągnięcia tego:

  1. Zaleca się usuwanie zbuforowanych odpowiedzi po wylogowaniu. Można to zrobić za pomocą metody udostępnionej przez Apple o nazwie 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.

  1. Jeśli nie potrzebujesz korzystać z zalet cookies, zaleca się użycie właściwości konfiguracyjnej .ephemeral URLSession, która wyłączy zapisywanie cookies oraz Cache.

Apple documentation:

An ephemeral session configuration object is similar to a default session configuration (see default), except that the corresponding session object doesn’t store caches, credential stores, or any session-related data to disk. Instead, session-related data is stored in RAM. The only time an ephemeral session writes data to disk is when you tell it to write the contents of a URL to a file.

  1. Cache można również wyłączyć, ustawiając politykę Cache na .notAllowed. Spowoduje to wyłączenie zapisywania Cache w jakikolwiek sposób, zarówno w pamięci, jak i na dysku.

Snapshoty

Za każdym razem, gdy naciśniesz przycisk home, iOS wykonuje snapshot bieżącego ekranu, aby przejście do aplikacji było znacznie płynniejsze. 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ą snapshoty, do których masz dostęp także przez podwójne tapnięcie przycisku home, aby przełączać się między aplikacjami.

O ile iPhone nie jest jailbroken, atakujący musi mieć dostęp do odblokowanego urządzenia, aby zobaczyć te zrzuty ekranu. Domyślnie ostatni snapshot jest przechowywany w sandboxie aplikacji w katalogu Library/Caches/Snapshots/ lub Library/SplashBoard/Snapshots (the trusted computers can’ t access the filesystem from iOX 7.0).

Jednym ze sposobów zapobiegania temu niepożądanemu zachowaniu jest wyświetlenie pustego ekranu lub usunięcie wrażliwych danych przed wykonaniem snapshotu, używając funkcji ApplicationDidEnterBackground().

Poniżej znajduje się przykładowa metoda remediacji, która ustawi domyślny zrzut ekranu.

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 ustawia obraz tła na overlayImage.png za każdym razem, gdy aplikacja zostanie przeniesiona do tła. Zapobiega sensitive data leaks, ponieważ overlayImage.png zawsze nadpisze bieżący widok.

Keychain

Do uzyskiwania dostępu i zarządzania iOS keychain dostępne są narzędzia takie jak Keychain-Dumper, odpowiednie dla urządzeń jailbroken. Dodatkowo, Objection udostępnia komendę ios keychain dump do podobnych celów.

Przechowywanie poświadczeń

Klasa NSURLCredential jest idealna do zapisywania wrażliwych informacji bezpośrednio w keychain, omijając konieczność użycia NSUserDefaults lub innych wrapperów. Aby zapisać poświadczenia po logowaniu, używany jest następujący kod Swift:

NSURLCredential *credential;
credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistencePermanent];
[[NSURLCredentialStorage sharedCredentialStorage] setCredential:credential forProtectionSpace:self.loginProtectionSpace];

Aby wyodrębnić te przechowywane poświadczenia, używa się polecenia Objection ios nsurlcredentialstorage dump.

Klawiatury zewnętrzne i pamięć podręczna klawiatury

Od iOS 8.0 użytkownicy mogą instalować rozszerzenia klawiatur, którymi można zarządzać w Settings > General > Keyboard > Keyboards. Choć te klawiatury oferują rozszerzone funkcje, stwarzają ryzyko logowania naciśnięć klawiszy i przesyłania danych do zewnętrznych serwerów; użytkownicy są jednak informowani o klawiaturach wymagających dostępu do sieci. Aplikacje mogą — i powinny — ograniczać użycie klawiatur zewnętrznych do wprowadzania informacji wrażliwych.

Zalecenia dotyczące bezpieczeństwa:

  • Zaleca się wyłączenie klawiatur firm trzecich w celu zwiększenia bezpieczeństwa.
  • Zwróć uwagę na funkcje autokorekty i automatycznych sugestii domyślnej klawiatury iOS, które mogą przechowywać wrażliwe informacje w plikach cache znajdujących się w Library/Keyboard/{locale}-dynamic-text.dat lub /private/var/mobile/Library/Keyboard/dynamic-text.dat. Należy regularnie sprawdzać te pliki cache pod kątem wrażliwych danych. Zaleca się zresetowanie słownika klawiatury przez Settings > General > Reset > Reset Keyboard Dictionary w celu usunięcia danych z cache.
  • Przechwytywanie ruchu sieciowego może ujawnić, czy klawiatura zewnętrzna przesyła naciśnięcia klawiszy zdalnie.

Zapobieganie buforowaniu pól tekstowych

The UITextInputTraits protocol offers properties to manage autocorrection and secure text entry, essential for preventing sensitive information caching. For example, disabling autocorrection and enabling secure text entry can be achieved with:

textObject.autocorrectionType = UITextAutocorrectionTypeNo;
textObject.secureTextEntry = YES;

Ponadto deweloperzy powinni upewnić się, że pola tekstowe, szczególnie te przeznaczone do wprowadzania informacji wrażliwych, takich jak hasła i PIN-y, wyłączają buforowanie poprzez ustawienie autocorrectionType na UITextAutocorrectionTypeNo oraz secureTextEntry na YES.

UITextField *textField = [[UITextField alloc] initWithFrame:frame];
textField.autocorrectionType = UITextAutocorrectionTypeNo;

Logi

Debugowanie kodu często wymaga użycia logging. Wiąże się to z ryzykiem, ponieważ logi mogą zawierać poufne informacje. W przeszłości, w iOS 6 i wcześniejszych wersjach, logi były dostępne dla wszystkich aplikacji, co stwarzało ryzyko sensitive data leak. Obecnie aplikacje mają ograniczony dostęp tylko do własnych logów.

Pomimo tych ograniczeń, atakujący z fizycznym dostępem do odblokowanego urządzenia nadal może to wykorzystać, podłączając urządzenie do komputera i odczytując logi. Należy pamiętać, że logi pozostają na dysku nawet po odinstalowaniu aplikacji.

Aby zmniejszyć ryzyko, zaleca się dokładnie przetestować aplikację, sprawdzając wszystkie funkcjonalności i pola wejściowe, aby upewnić się, że żadne poufne informacje nie są przypadkowo logowane.

Przeglądając kod źródłowy aplikacji w poszukiwaniu potencjalnych leaków, szukaj zarówno wbudowanych, jak i niestandardowych instrukcji logowania używając słów kluczowych takich jak NSLog, NSAssert, NSCAssert, fprintf dla funkcji wbudowanych, oraz wszelkich wzmianek o Logging lub Logfile dla implementacji niestandardowych.

Monitorowanie logów systemowych

Aplikacje logują różne informacje, które mogą być poufne. Aby monitorować te logi, narzędzia i polecenia takie jak:

idevice_id --list   # To find the device ID
idevicesyslog -u <id> (| grep <app>)   # To capture the device logs

są przydatne. Dodatkowo, Xcode umożliwia zbieranie logów konsoli:

  1. Otwórz Xcode.
  2. Podłącz urządzenie iOS.
  3. Przejdź do Okno -> Urządzenia i symulatory.
  4. Wybierz swoje urządzenie.
  5. Wywołaj problem, który badasz.
  6. Użyj przycisku Otwórz konsolę, aby zobaczyć logi w nowym oknie.

Dla bardziej zaawansowanego logowania, połączenie z powłoką urządzenia i użycie socat umożliwia monitorowanie logów w czasie rzeczywistym:

iPhone:~ root# socat - UNIX-CONNECT:/var/run/lockdown/syslog.sock

Następują polecenia do obserwowania aktywności logów, które mogą być nieocenione przy diagnozowaniu problemów lub identyfikowaniu potencjalnego data leak w logach.

Kopie zapasowe

Funkcje automatycznych kopii zapasowych są zintegrowane z iOS, ułatwiając tworzenie kopii danych urządzenia przez iTunes (do macOS Catalina), Finder (od macOS Catalina wzwyż) lub iCloud. Te kopie zapasowe obejmują niemal wszystkie dane urządzenia, z wyłączeniem bardzo 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 rodzi problem potencjalnego data leakage oraz ryzyko, że modyfikacje backupu mogą zmienić działanie aplikacji. Zaleca się nie przechowywać wrażliwych informacji w plaintext w katalogu jakiejkolwiek aplikacji ani jego podkatalogach, aby zminimalizować te ryzyka.

Wykluczanie plików z kopii zapasowych

Pliki w Documents/ i Library/Application Support/ są domyślnie uwzględniane w kopiach zapasowych. Deweloperzy mogą wykluczyć konkretne pliki lub katalogi z backupów, używając NSURL setResourceValue:forKey:error: z kluczem NSURLIsExcludedFromBackupKey. Ta praktyka jest kluczowa dla ochrony wrażliwych danych przed dołączeniem do backupu.

Testowanie podatności

Aby ocenić bezpieczeństwo backupu aplikacji, zacznij od utworzenia kopii zapasowej przy użyciu Finder, a następnie zlokalizuj ją korzystając z instrukcji w Apple’s official documentation. Przeanalizuj backup pod kątem wrażliwych danych lub konfiguracji, które mogłyby zostać zmienione w celu wpływu na działanie aplikacji.

Na wrażliwe informacje można polować używając narzędzi wiersza poleceń lub aplikacji takich jak iMazing. W przypadku zaszyfrowanych kopii zapasowych obecność szyfrowania można potwierdzić, sprawdzając klucz “IsEncrypted” w pliku “Manifest.plist” w katalogu głównym backupu.

<?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>

W radzeniu sobie z zaszyfrowanymi backupami, skrypty Python dostępne w DinoSec’s GitHub repo, takie jak backup_tool.py i backup_passwd.py, mogą być przydatne, choć mogą wymagać dostosowań, aby były kompatybilne z najnowszymi wersjami iTunes/Finder. Narzędzie iOSbackup tool to kolejna opcja umożliwiająca dostęp do plików w backupach chronionych hasłem.

Modyfikowanie zachowania aplikacji

Przykład zmiany zachowania aplikacji poprzez modyfikację backupu pokazuje Bither bitcoin wallet app, gdzie PIN blokady UI jest przechowywany w net.bither.plist pod kluczem pin_code. Usunięcie tego klucza z plist i przywrócenie backupu usuwa wymóg PIN, zapewniając nieograniczony dostęp.

Podsumowanie testowania pamięci pod kątem danych wrażliwych

Przy pracy z danymi wrażliwymi przechowywanymi w pamięci aplikacji istotne jest ograniczenie czasu ekspozycji tych danych. Istnieją dwa podstawowe podejścia do badania zawartości pamięci: creating a memory dump i analyzing the memory in real time. Obie metody mają swoje wyzwania, w tym możliwość pominięcia krytycznych danych podczas procesu dumpu lub analizy.

Retrieving and Analyzing a Memory Dump

Dla urządzeń zarówno jailbroken, jak i non-jailbroken, narzędzia takie jak objection i Fridump pozwalają na zrzut pamięci procesu aplikacji. Po zrzuceniu, analiza tych danych wymaga różnych narzędzi, w zależności od rodzaju poszukiwanych informacji.

Aby wyodrębnić ciągi znaków z memory dumpu, można użyć poleceń takich jak strings lub rabin2 -zz:

# Extracting strings using strings command
$ strings memory > strings.txt

# Extracting strings using rabin2
$ rabin2 -ZZ memory > strings.txt

Dla bardziej szczegółowej analizy, w tym wyszukiwania konkretnych typów danych lub wzorców, radare2 oferuje rozbudowane możliwości wyszukiwania:

$ r2 <name_of_your_dump_file>
[0x00000000]> /?
...

Runtime Memory Analysis

r2frida oferuje potężną alternatywę do inspekcji pamięci aplikacji w czasie rzeczywistym, bez potrzeby wykonania memory dump. To narzędzie umożliwia wykonywanie poleceń wyszukiwania bezpośrednio w pamięci uruchomionej aplikacji:

$ r2 frida://usb//<name_of_your_app>
[0x00000000]> /\ <search_command>

Słaba kryptografia

Słabe procesy zarządzania kluczami

Niektórzy deweloperzy zapisują dane wrażliwe w local storage i szyfrują je przy użyciu klucza hardcoded/predictable w code. Nie powinno się tego robić, ponieważ reversing może pozwolić atakującym na wydobycie informacji poufnych.

Użycie niebezpiecznych i/lub przestarzałych algorytmów

Deweloperzy nie powinni używać przestarzałych algorytmów do wykonywania authorisation checks, do 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, należy stosować hashes odporne na brute-force wraz z salt.

Sprawdzenie

Główne checks do wykonania to sprawdzenie, czy możesz znaleźć hardcoded passwords/secrets w code, czy są one predictable, oraz czy code używa jakiegoś rodzaju weak cryptography algorytmów.

Warto wiedzieć, że można automatycznie monitorować niektóre crypto libraries za pomocą objection z:

ios monitor crypt

For more information about iOS cryptographic APIs and libraries access https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06e-testing-cryptography

Uwierzytelnianie lokalne

Uwierzytelnianie lokalne odgrywa kluczową rolę, szczególnie gdy chodzi o zabezpieczanie dostępu w zdalnym punkcie końcowym za pomocą metod kryptograficznych. Istota polega na tym, że bez właściwej implementacji mechanizmy uwierzytelniania lokalnego można obejść.

Apple’s Local Authentication framework and the keychain provide robust APIs for developers to facilitate user authentication dialogs and securely handle secret data, respectively. Secure Enclave zabezpiecza identyfikator odcisku palca dla Touch ID, natomiast Face ID opiera się na rozpoznawaniu twarzy, nie narażając danych biometrycznych.

Aby zintegrować Touch ID/Face ID, deweloperzy mają do wyboru dwa interfejsy API:

  • LocalAuthentication.framework for high-level user authentication without access to biometric data.
  • Security.framework for lower-level keychain services access, securing secret data with biometric authentication. Various open-source wrappers make keychain access simpler.

Caution

Jednak zarówno LocalAuthentication.framework, jak i Security.framework wykazują podatności, ponieważ głównie zwracają wartości boolean bez przesyłania danych w procesach uwierzytelniania, co czyni je podatnymi na obejścia (zob. Don’t touch me that way, by David Lindner et al).

Implementacja uwierzytelniania lokalnego

Aby wywołać monit o uwierzytelnienie użytkownika, deweloperzy powinni użyć metody evaluatePolicy w klasie LAContext, wybierając pomiędzy:

  • deviceOwnerAuthentication: Wyświetla monit o Touch ID lub kod urządzenia, kończy się niepowodzeniem, jeśli żaden z nich nie jest włączony.
  • deviceOwnerAuthenticationWithBiometrics: Wyświetla wyłącznie monit o Touch ID.

Pomyślne uwierzytelnienie jest sygnalizowane przez wartość boolean zwracaną przez evaluatePolicy, co wskazuje na potencjalną wadę bezpieczeństwa.

Uwierzytelnianie lokalne z użyciem keychain

Implementacja uwierzytelniania lokalnego w aplikacjach iOS obejmuje użycie keychain APIs do bezpiecznego przechowywania tajnych danych, takich jak tokeny uwierzytelniające. Proces ten zapewnia, że dane mogą być dostępne tylko dla użytkownika, przy użyciu kodu urządzenia lub uwierzytelniania biometrycznego, takiego jak Touch ID.

Keychain oferuje możliwość ustawienia elementów z atrybutem SecAccessControl, który ogranicza dostęp do elementu do momentu, aż użytkownik pomyślnie uwierzytelni się za pomocą Touch ID lub kodu urządzenia. Ta funkcja jest kluczowa dla zwiększenia bezpieczeństwa.

Poniżej znajdują się przykłady kodu w Swift i Objective-C pokazujące, jak zapisać i odczytać string do/z keychain, wykorzystując te funkcje bezpieczeństwa. Przykłady pokazują w szczególności, jak skonfigurować kontrolę dostępu wymagającą uwierzytelnienia Touch ID oraz zapewnić, że dane będą dostępne tylko na urządzeniu, na którym zostały zapisane, pod warunkiem że skonfigurowano kod urządzenia.

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

Teraz możemy zażądać zapisanego elementu z keychain. Usługi keychain wyświetlą użytkownikowi dialog uwierzytelniania i zwrócą dane lub nil w zależności od tego, czy został dostarczony odpowiedni fingerprint.

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

Wykrywanie

Użycie frameworków w aplikacji można także wykryć, analizując listę współdzielonych bibliotek dynamicznych binarki aplikacji. Można to zrobić za pomocą otool:

$ otool -L <AppName>.app/<AppName>

Jeśli LocalAuthentication.framework jest używany w aplikacji, output będzie zawierać obie z następujących linii (pamiętaj, że LocalAuthentication.framework używa Security.framework pod spodem):

/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication
/System/Library/Frameworks/Security.framework/Security

Jeśli używany jest Security.framework, wyświetlany będzie tylko drugi.

Local Authentication Framework Bypass

Objection

Dzięki Objection Biometrics Bypass, znajdującemu się na this GitHub page, dostępna jest technika pozwalająca obejść mechanizm LocalAuthentication. Istota podejścia polega na wykorzystaniu Frida do manipulowania funkcją evaluatePolicy, tak aby zawsze zwracała wartość True, niezależnie od rzeczywistego wyniku uwierzytelniania. Jest to szczególnie przydatne do obejścia wadliwych procesów uwierzytelniania biometrycznego.

Aby aktywować ten bypass, użyj następującego polecenia:

...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 faktycznie zmienia wynik sprawdzenia evaluatePolicy na True.

Frida

Przykład użycia evaluatePolicy z DVIA-v2 application:

+(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ąć bypass Local Authentication, napisano skrypt Frida. Skrypt ten celuje w sprawdzenie evaluatePolicy, przechwytując jego callback, aby upewnić się, że zwraca success=1. Poprzez zmianę zachowania callbacka, weryfikacja uwierzytelnienia jest efektywnie pominięta.

Poniższy skrypt jest wstrzykiwany, by zmodyfikować wynik metody evaluatePolicy. Zmienia wynik callbacka tak, aby zawsze wskazywał success.

// 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 ominąć uwierzytelnianie biometryczne, używane jest następujące polecenie:

frida -U -f com.highaltitudehacks.DVIAswiftv2 --no-pause -l fingerprint-bypass-ios.js

Ujawnienie wrażliwej funkcjonalności przez IPC

iOS Custom URI Handlers / Deeplinks / Custom Schemes

iOS Universal Links

UIActivity Sharing

iOS UIActivity Sharing

UIPasteboard

iOS UIPasteboard

App Extensions

iOS App Extensions

WebViews

iOS WebViews

Serialisation and Encoding

iOS Serialisation and Encoding

Network Communication

Ważne jest sprawdzenie, czy żadna komunikacja nie odbywa się bez szyfrowania oraz czy aplikacja poprawnie weryfikuje certyfikat TLS serwera.
Aby sprawdzić tego typu problemy możesz użyć proxy takiego jak Burp:

iOS Burp Suite Configuration

Hostname check

Częstym problemem przy weryfikacji certyfikatu TLS jest sprawdzenie, czy certyfikat został podpisany przez zaufane CA, ale nie sprawdzenie, czy hostname certyfikatu odpowiada odwiedzanemu hostowi.
Aby sprawdzić ten problem przy użyciu Burp, po zaufaniu Burp CA na iPhone, możesz utworzyć nowy certyfikat w Burp dla innego hostname i go użyć. Jeśli aplikacja nadal działa, to oznacza, że jest podatna.

Certificate Pinning

Jeśli aplikacja poprawnie używa SSL Pinning, aplikacja będzie działać tylko wtedy, gdy certyfikat jest tym oczekiwanym. Podczas testowania aplikacji może to być problem, ponieważ Burp będzie serwował własny certyfikat.
Aby obejść tę ochronę na urządzeniu z jailbreakiem, możesz zainstalować aplikację SSL Kill Switch lub zainstalować Burp Mobile Assistant

Możesz też użyć objection’s ios sslpinning disable

Misc

  • 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
  • Natomiast /User/Library zawiera dane zapisywane przez aplikacje na poziomie użytkownika
  • Możesz uzyskać dostęp do /User/Library/Notes/notes.sqlite, aby przeczytać notatki zapisane w aplikacji.
  • Wewnątrz folderu zainstalowanej aplikacji (/User/Applications/<APP ID>/) możesz znaleźć kilka ciekawych plików:
  • iTunesArtwork: Ikona używana przez aplikację
  • iTunesMetadata.plist: Informacje o aplikacji wykorzystywane w App Store
  • /Library/*: Zawiera preferencje i cache. W /Library/Cache/Snapshots/* możesz znaleźć snapshot wykonany dla aplikacji przed wysłaniem jej w tło.

Hot Patching/Enforced Updateing

Deweloperzy mogą zdalnie załatać wszystkie instalacje swojej aplikacji natychmiast bez konieczności ponownego zgłaszania aplikacji do App Store i oczekiwania na jej zatwierdzenie.
Do tego celu zwykle używa się JSPatch. Są też inne opcje, takie jak Siren i react-native-appstore-version-checker.
Jest to niebezpieczny mechanizm, który może być nadużyty przez złośliwe SDK stron trzecich, dlatego zaleca się sprawdzenie, jaka metoda jest używana do automatycznego aktualizowania (jeśli w ogóle) i przetestowanie jej. Możesz spróbować pobrać poprzednią wersję aplikacji w tym celu.

Third Parties

Znaczącym wyzwaniem związanym z 3rd party SDKs 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 zagrożenia prywatności, albo zrezygnować z jego korzyści. Często deweloperzy nie są w stanie sami załatać podatności w tych SDK. Ponadto, wraz ze wzrostem zaufania do niektórych SDK w społeczności, niektóre z nich mogą zacząć zawierać malware.

Usługi świadczone przez SDK stron trzecich mogą obejmować śledzenie zachowań użytkowników, wyświetlanie reklam lub ulepszanie doświadczenia użytkownika. Jednakże 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. Kluczowe jest ograniczenie informacji udostępnianych usługom stron trzecich do niezbędnego minimum oraz upewnienie się, że żadne dane wrażliwe nie są ujawniane.

Implementacja usług stron trzecich zwykle występuje w dwóch formach: samodzielnej biblioteki lub pełnego SDK. Aby chronić prywatność użytkowników, wszelkie dane udostępniane tym usługom powinny być anonymized, aby zapobiec ujawnieniu danych identyfikujących osobę (PII).

Aby zidentyfikować biblioteki używane przez aplikację, można użyć polecenia otool. To narzędzie powinno być uruchomione przeciwko aplikacji oraz każdej współdzielonej bibliotece, której używa, aby odkryć dodatkowe biblioteki.

otool -L <application_path>

Interesujące luki i studia przypadków

Air Keyboard Remote Input Injection

Itunesstored Bookassetd Sandbox Escape

Zero Click Messaging Image Parser Chains

Referencje i dodatkowe zasoby

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks