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 możesz znaleźć informacje o iOS simulator, emulators i jailbreaking:

iOS Testing Environment

Wstępna analiza

Podstawowe operacje testowania iOS

Podczas testowania zostanie zasugerowanych kilka operacji (połączenie z urządzeniem, odczyt/zapis/upload/download plików, użycie narzędzi…). W związku z tym, jeśli nie wiesz jak wykonać którąkolwiek z tych czynności, proszę, rozpocznij od przeczytania strony:

iOS Basic Testing Operations

Tip

Dla poniższych kroków aplikacja powinna być zainstalowana na urządzeniu i powinien być już pozyskany plik IPA aplikacji.
Przeczytaj stronę Basic iOS Testing Operations aby dowiedzieć się, jak to zrobić.

Podstawowa analiza statyczna

Kilka interesujących dekompilatorów iOS - IPA:

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

Identyfikacja zabezpieczeń obecnych w binarium:

  • PIE (Position Independent Executable): Gdy jest włączone, aplikacja ładuje się pod losowy adres pamięci przy każdym uruchomieniu, co utrudnia przewidzenie jej początkowego adresu pamięci.
otool -hv <app-binary> | grep PIE   # It should include the PIE flag
  • Stack Canaries: Aby zweryfikować integralność stosu, wartość „canary” jest umieszczana na stosie przed wywołaniem funkcji i weryfikowana ponownie 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: Binarium powinno być zaszyfrowane
otool -arch all -Vl <app-binary> | grep -A5 LC_ENCRYPT   # The cryptid should be 1

Identyfikacja funkcji wrażliwych/niebezpiecznych

  • 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: Sprawdź obecność typowych plików i katalogów związanych z jailbreakiem, takich jak /Applications/Cydia.app lub /Library/MobileSubstrate/MobileSubstrate.dylib.
  • Sandbox Violations: Spróbuj uzyskać dostęp do zastrzeżonych obszarów systemu plików, które powinny być zablokowane na urządzeniach bez jailbreaka.
  • API Checks: Sprawdź, czy możliwe jest użycie zabronionych wywołań jak fork() do utworzenia procesu potomnego lub system() aby sprawdzić czy istnieje /bin/sh.
  • Process Checks: Monitoruj obecność znanych procesów związanych z jailbreakiem, takich jak Cydia, Substrate lub ssh.
  • Kernel Exploits: Sprawdź obecność exploitów jądra, które są powszechnie używane w jailbreakach.
  • Environment Variables: Zbadaj zmienne środowiskowe pod kątem śladów jailbreaka, takich jak DYLD_INSERT_LIBRARIES.
  • Libraries Check: Sprawdź biblioteki ładowane do procesu aplikacji.
  • Check schemes: Na przykład canOpenURL(URL(string: "cydia://")).

Typowe metody wykrywania anti-debugging

  • Check for Debugger Presence: Użyj sysctl lub innych metod, aby sprawdzić czy debugger jest dołączony.
  • Anti-Debugging APIs: Szukaj wywołań do API anty-debuggingowych jak ptrace lub SIGSTOP, np. ptrace(PT_DENY_ATTACH, 0, 0, 0).
  • Timing Checks: Mierz czas wykonania pewnych operacji i szukaj rozbieżności, które mogą wskazywać na debugowanie.
  • Memory Checks: Przejrzyj pamięć w poszukiwaniu znanych artefaktów debuggera lub modyfikacji.
  • Environment Variables: Sprawdź zmienne środowiskowe, które mogą wskazywać na sesję debugowania.
  • Mach Ports: Wykryj, czy porty mach exception są używane przez debugery.

Podstawowa analiza dynamiczna

Sprawdź analizę dynamiczną, którą wykonuje MobSF. Będziesz musiał nawigować przez różne widoki i wchodzić z nimi w interakcję — narzędzie będzie hookować kilka klas i wykonywać inne czynności oraz przygotuje raport po zakończeniu.

Wylistowanie 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 w prosty sposób hook methods and classes z użyciem objection:

iOS Hooking With Objection

IPA Structure

Struktura pliku IPA jest zasadniczo taka sama jak spakowanego archiwum ZIP. Po zmianie rozszerzenia na .zip można je rozpakować, aby zobaczyć zawartość. W obrębie tej struktury Bundle oznacza w pełni spakowaną aplikację gotową do instalacji. W środku znajdziesz katalog o nazwie <NAME>.app, który zawiera zasoby aplikacji.

  • Info.plist: Ten plik zawiera szczegółowe ustawienia konfiguracyjne aplikacji.
  • _CodeSignature/: Ten katalog zawiera plik plist z podpisem, który zapewnia integralność wszystkich plików w bundle.
  • Assets.car: Skompresowane archiwum przechowujące pliki zasobów, takie jak ikony.
  • Frameworks/: Ten folder zawiera natywne biblioteki aplikacji, które mogą występować w postaci plików .dylib lub .framework.
  • PlugIns/: Może zawierać rozszerzenia aplikacji, znane jako pliki .appex, chociaż nie zawsze są obecne. * Core Data: Służy do zapisywania trwałych danych aplikacji do użytku offline, buforowania danych tymczasowych oraz dodawania funkcji cofania (undo) na pojedynczym urządzeniu. Aby zsynchronizować dane między wieloma urządzeniami w ramach jednego konta iCloud, Core Data automatycznie odzwierciedla schemat w kontenerze CloudKit.
  • PkgInfo: Plik PkgInfo jest alternatywnym sposobem określenia type i creator codes Twojej aplikacji lub bundle.
  • en.lproj, fr.proj, Base.lproj: To pakiety językowe zawierające zasoby dla konkretnych języków oraz zasób domyślny na wypadek, gdy dany język nie jest obsługiwany.
  • Bezpieczeństwo: Katalog _CodeSignature/ odgrywa kluczową rolę w zabezpieczeniach aplikacji, weryfikując integralność wszystkich dołączonych plików za pomocą podpisów cyfrowych.
  • Zarządzanie zasobami: Plik Assets.car używa kompresji do efektywnego zarządzania zasobami graficznymi, co jest kluczowe dla optymalizacji wydajności aplikacji i zmniejszenia jej rozmiaru.
  • Frameworks i PlugIns: Te katalogi podkreślają modularność aplikacji iOS, umożliwiając deweloperom dołączanie wielokrotnego użytku bibliotek kodu (Frameworks/) oraz rozszerzanie funkcjonalności 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 jest fundamentem aplikacji iOS, zawierając kluczowe dane konfiguracyjne w postaci par key-value. Ten plik jest wymagany nie tylko dla aplikacji, ale także dla rozszerzeń i frameworków dołączonych do pakietu. Może być zapisany 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, zobacz Apple Developer Documentation.

Dla osób chcących pracować z tym plikiem w bardziej przystępnym formacie, konwersję do XML można bez trudu wykonać przy użyciu plutil na macOS (natywnie dostępny od wersji 10.2) lub plistutil na Linux. Polecenia do konwersji są następujące:

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

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

$ grep -i <keyword> Info.plist

Ścieżki danych

W środowisku iOS katalogi są przypisane specjalnie dla aplikacji systemowych i aplikacji zainstalowanych przez użytkownika. Aplikacje systemowe znajdują się w katalogu /Applications, natomiast aplikacje zainstalowane przez użytkownika są umieszczane w /var/mobile/containers/Data/Application/. Tym aplikacjom przypisywany jest unikalny identyfikator znany jako 128-bit UUID, co utrudnia ręczne zlokalizowanie folderu aplikacji z powodu losowości nazw katalogów.

Warning

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

Jednak oba foldery (data & container folders) zawierają plik .com.apple.mobile_container_manager.metadata.plist, który łączy oba foldery przez klucz MCMetadataIdentifier).

Aby ułatwić odnalezienie katalogu instalacyjnego aplikacji zainstalowanej przez użytkownika, objection tool 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, nazwa aplikacji może być wyszukana w /private/var/containers za pomocą polecenia find:

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

Polecenia takie jak ps i lsof można również wykorzystać do zidentyfikowania procesu aplikacji i odpowiednio wylistowania 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

Katalog Bundle:

  • AppName.app
  • To jest bundle aplikacji, jak widziano wcześniej w IPA; zawiera niezbędne dane aplikacji, zawartość statyczną 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 służy do weryfikacji podpisu kodu.

Katalog danych:

  • Documents/
  • Zawiera wszystkie dane generowane przez użytkownika. To użytkownik końcowy aplikacji inicjuje tworzenie tych danych.
  • Widoczny dla użytkowników i użytkownicy mogą w nim zapisywać.
  • Zawartość tego katalogu jest objęta kopią zapasową.
  • Aplikacja może wyłączyć ś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 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ą w nim zapisywać.
  • Zawartość tego katalogu nie jest objęta kopią zapasową.
  • System operacyjny może automatycznie usunąć pliki z tego katalogu, gdy aplikacja nie działa i zabraknie miejsca na dysku.
  • Library/Application Support/
  • Zawiera trwałe pliki niezbędne do uruchomienia aplikacji.
  • Niewidoczny dla użytkowników i użytkownicy nie mogą w nim zapisywać.
  • Zawartość w tym katalogu jest objęta kopią zapasową.
  • Aplikacja może wyłączyć ścieżki, ustawiając NSURLIsExcludedFromBackupKey.
  • Library/Preferences/
  • Służy do przechowywania właściwości, które mogą przetrwać nawet po ponownym uruchomieniu aplikacji.
  • Informacje są zapisywane, niezaszyfrowane, wewnątrz sandboxu aplikacji w pliku plist o nazwie [BUNDLE_ID].plist.
  • Wszystkie pary klucz/wartość zapisane za pomocą NSUserDefaults można znaleźć w tym pliku.
  • tmp/
  • Użyj tego katalogu do zapisywania tymczasowych plików, które nie muszą być zachowane między uruchomieniami aplikacji.
  • Zawiera niepermanentne pliki cache.
  • Niewidoczny dla użytkowników.
  • Zawartość tego katalogu nie jest objęta kopią zapasową.
  • System operacyjny może automatycznie usunąć pliki z tego katalogu, gdy aplikacja nie działa i brakuje miejsca na dysku.

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

Wewnątrz folderu <application-name>.app znajdziesz plik binarny o nazwie <application-name>. To jest plik, który zostanie uruchomiony. 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

Disassembling the binary

Disassemble the text section:

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ć Objective-C segment 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 zwięzły 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 należy sprawdzić tuż po zainstalowaniu aplikacji, po sprawdzeniu wszystkich funkcjonalności aplikacji i nawet po wylogowaniu się z jednego użytkownika i zalogowaniu się jako inny.
Celem jest znalezienie niechronionych wrażliwych informacji aplikacji (hasła, tokeny), bieżącego użytkownika oraz wcześniej zalogowanych użytkowników.

Plist

plist files są uporządkowanymi plikami XML, które zawierają pary klucz-wartość. To sposób przechowywania danych trwałych, więc czasami możesz znaleźć w tych plikach wrażliwe informacje. Zaleca się sprawdzenie tych plików po zainstalowaniu aplikacji oraz po intensywnym korzystaniu z niej, aby sprawdzić, czy zapisywane są nowe dane.

Najczęstszym sposobem utrwalania danych w 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 plist pliku, ale jest przeznaczona do użycia z niewielkimi ilościami danych.

Do tych danych nie można już dłużej uzyskać dostępu bezpośrednio za pomocą zaufanego komputera, ale można je odzyskać wykonując backup.

Możesz zrzucić informacje zapisane za pomocą NSUserDefaults używając 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 konwertować pliki z formatu XML or binary (bplist) do XML, dostępne są różne metody w zależności od systemu operacyjnego:

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

$ plutil -convert xml1 Info.plist

Dla użytkowników Linuksa: Najpierw zainstaluj libplist-utils, a następnie użyj plistutil, aby przekonwertować swój plik:

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

Within an Objection Session: Dla analizy aplikacji mobilnych, konkretne polecenie 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 is a framework for managing the model layer of objects in your application. Core Data can use SQLite as its persistent store, but the framework itself is not a database.
CoreData domyślnie nie szyfruje swoich danych. Jednak można dodać dodatkową warstwę szyfrowania do CoreData. Więcej szczegółów w GitHub Repo.

Informacje SQLite Core Data danej aplikacji znajdują się 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, oznacza to 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 jest bazą klucz-wartość zbudowaną na SQLite.
Ponieważ bazy Yap są bazami sqlite, możesz je znaleźć używając polecenia opisanego w poprzedniej sekcji.

Inne bazy danych SQLite

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

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

Firebase Real-Time Databases

Deweloperzy mogą przechowywać i synchronizować dane w NoSQL bazie danych hostowanej w chmurze za pomocą Firebase Real-Time Databases. Przechowywane w formacie JSON, dane są synchronizowane ze wszystkimi podłączonymi klientami w czasie rzeczywistym.

Instrukcje sprawdzania nieprawidłowo skonfigurowanych baz Firebase znajdziesz tutaj:

Firebase Database

Realm databases

Realm Objective-C i Realm Swift oferują potężną alternatywę dla przechowywania danych, której Apple nie zapewnia. Domyślnie przechowują dane bez szyfrowania, przy czym szyfrowanie jest dostępne poprzez odpowiednią konfigurację.

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

Aby przeglądać te pliki bazy danych, zalecane jest użycie narzędzia Realm Studio.

Aby zaimplementować szyfrowanie w bazie 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)")
}

Bazy danych Couchbase Lite

Couchbase Lite jest opisywany jako lekki i wbudowany silnik bazy danych, który stosuje podejście zorientowane na dokumenty (NoSQL). Zaprojektowany jako natywny dla iOS i macOS, oferuje możliwość płynnej synchronizacji 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/

Cookies

iOS przechowuje cookies aplikacji w Library/Cookies/cookies.binarycookies wewnątrz folderu każdej aplikacji. Jednak deweloperzy czasami zapisują je w keychain, ponieważ wspomniany cookie file może być dostępny w backupach.

Aby przeanalizować plik cookies możesz użyć this python script lub skorzystać z objection i wykonać ios cookies get.
Możesz też użyć objection, aby przekonwertować te pliki do formatu JSON i przejrzeć 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"
}
]

Cache

Domyślnie NSURLSession przechowuje dane, takie jak żądania i odpowiedzi HTTP w Cache.db. Ta baza może zawierać poufne dane, jeśli tokeny, nazwy użytkowników lub 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 manipulować tą bazą poleceniem sqlite connect Cache.db, ponieważ jest to zwykła baza SQLite.

Zaleca się wyłączenie przechowywania tych danych w pamięci podręcznej, ponieważ mogą zawierać wrażliwe 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 Apple removeAllCachedResponses. Wywołuje się ją tak:

URLCache.shared.removeAllCachedResponses()

Ta metoda usunie wszystkie zbuforowane żądania i odpowiedzi z pliku Cache.db.

  1. Jeśli nie potrzebujesz mechanizmu ciasteczek, zaleca się użycie właściwości konfiguracji .ephemeral URLSession, która uniemożliwia zapisywanie ciasteczek i cache.

Apple documentation:

Obiekt konfiguracji sesji ephemeral jest podobny do domyślnej konfiguracji sesji (zob. default), z tą różnicą, że odpowiadający mu obiekt sesji nie zapisuje cache, 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 przypadkiem, gdy sesja ephemeral zapisuje dane na dysku, jest sytuacja, gdy polecisz jej zapisanie zawartości URL do pliku.

  1. Cache można też wyłączyć ustawiając politykę cache na .notAllowed. Spowoduje to wyłączenie przechowywania cache w pamięci lub na dysku.

Migawki

Za każdym razem, gdy naciśniesz przycisk Home, iOS tworzy migawkę bieżącego ekranu, aby umożliwić płynniejsze przejście do aplikacji. Jeśli jednak na ekranie znajdują się wrażliwe dane, zostaną one zapisane w obrazie (który przetrwa ponowne uruchomienia). To są migawki, do których można uzyskać dostęp także przez dwukrotne naciśnięcie przycisku Home, aby przełączać aplikacje.

Jeżeli iPhone nie jest jailbroken, attacker musi mieć niezablokowany dostęp do urządzenia, aby zobaczyć te zrzuty ekranu. Domyślnie ostatnia migawka jest przechowywana w sandboxie aplikacji w Library/Caches/Snapshots/ lub Library/SplashBoard/Snapshots (zaufane komputery nie mają dostępu do systemu plików od iOS 7.0).

Jednym ze sposobów zapobiegania temu jest pokazanie pustego ekranu lub usunięcie wrażliwych danych przed wykonaniem migawki, używając funkcji ApplicationDidEnterBackground().

Poniżej znajduje się przykładowa metoda naprawcza, 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];
}

Ustawia obraz tła na overlayImage.png za każdym razem, gdy aplikacja jest przenoszona do tła. Zapobiega sensitive data leaks, ponieważ overlayImage.png zawsze nadpisze aktualny widok.

Keychain

Do uzyskiwania dostępu i zarządzania iOS keychain dostępne są narzędzia takie jak Keychain-Dumper, odpowiednie dla urządzeń z jailbreak. Dodatkowo, Objection udostępnia polecenie 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 zalogowaniu, używa się następującego kodu 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żywane jest polecenie Objection ios nsurlcredentialstorage dump.

Custom Keyboards and Keyboard Cache

Od iOS 8.0 użytkownicy mogą instalować rozszerzenia niestandardowych klawiatur, którymi można zarządzać w Ustawienia > Ogólne > Klawiatura > Klawiatury. Chociaż te klawiatury oferują rozszerzoną funkcjonalność, 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 niestandardowych klawiatur przy wprowadzaniu informacji wrażliwych.

Zalecenia bezpieczeństwa:

  • Zaleca się wyłączyć klawiatury firm trzecich w celu zwiększenia bezpieczeństwa.
  • Zwróć uwagę na funkcje autocorrect i auto-suggestions domyślnej klawiatury iOS, które mogą przechowywać informacje wrażliwe w plikach cache znajdujących się w Library/Keyboard/{locale}-dynamic-text.dat lub /private/var/mobile/Library/Keyboard/dynamic-text.dat. Te pliki cache powinny być regularnie sprawdzane pod kątem danych wrażliwych. Aby wyczyścić dane z pamięci podręcznej, zaleca się zresetowanie słownika klawiatury poprzez Ustawienia > Ogólne > Resetuj > Resetuj słownik klawiatury.
  • Przechwytywanie ruchu sieciowego może ujawnić, czy niestandardowa klawiatura przesyła naciśnięcia klawiszy zdalnie.

Preventing Text Field Caching

The UITextInputTraits protocol oferuje właściwości do zarządzania autocorrection i secure text entry, niezbędne do zapobiegania buforowaniu informacji wrażliwych. Na przykład wyłączenie autocorrection i włączenie secure text entry można osiągnąć za pomocą:

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

Dodatkowo deweloperzy powinni upewnić się, że pola tekstowe, zwłaszcza te służące do wprowadzania wrażliwych informacji, takich jak hasła i PIN-y, wyłączają przechowywanie w pamięci podręcznej, ustawiając autocorrectionType na UITextAutocorrectionTypeNo i secureTextEntry na YES.

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

Logs

Debugowanie kodu często obejmuje użycie logging. Istnieje ryzyko, ponieważ logs mogą zawierać poufne informacje. Wcześniej, w iOS 6 i wcześniejszych wersjach, logs były dostępne dla wszystkich aplikacji, co stwarzało ryzyko potential leaks. Obecnie aplikacje mają ograniczony dostęp tylko do swoich logs.

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

Aby zminimalizować ryzyko, zaleca się dokładne korzystanie z aplikacji, sprawdzając wszystkie jej funkcje i wejścia, aby upewnić się, że żadne poufne informacje nie są przypadkowo logowane.

Podczas przeglądu kodu źródłowego aplikacji pod kątem potencjalnych leaks, szukaj zarówno predefined, jak i custom logging statements używając takich słów kluczowych jak NSLog, NSAssert, NSCAssert, fprintf dla funkcji wbudowanych oraz wszelkich odniesień do Logging lub Logfile dla własnych implementacji.

Monitorowanie System Logs

Aby monitorować te logs, 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 udostępnia 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 analizujesz.
  6. Użyj przycisku Open Console, aby wyświetlić logi w nowym oknie.

Do bardziej zaawansowanego logowania, połączenie z powłoką urządzenia i użycie socat może zapewnić monitorowanie logów w czasie rzeczywistym:

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

Poniżej polecenia do obserwowania aktywności logów, które mogą być nieocenione przy diagnozowaniu problemów lub identyfikowaniu potencjalnego data leak.

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), Finder (od macOS Catalina) lub iCloud. Te kopie zapasowe obejmują niemal wszystkie dane urządzenia, z wyłączeniem wysoce wrażliwych elementów, takich jak dane Apple Pay i konfiguracje Touch ID.

Zagrożenia bezpieczeństwa

Dołączanie zainstalowanych aplikacji i ich danych do kopii zapasowych powoduje ryzyko potencjalnego data leak i ryzyko, że modyfikacje backupu mogą zmienić działanie aplikacji. Zaleca się nie przechowywać wrażliwych informacji w postaci plaintext w katalogu aplikacji ani jego podkatalogach, aby zmniejszyć te ryzyka.

Wykluczanie plików z kopii zapasowych

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

Testowanie pod kątem podatności

Aby ocenić bezpieczeństwo kopii zapasowych aplikacji, zacznij od utworzenia kopii zapasowej za pomocą Finder, a następnie znajdź ją korzystając z wytycznych z Apple’s official documentation. Przeanalizuj kopię zapasową pod kątem wrażliwych danych lub konfiguracji, które mogłyby zostać zmienione i wpłynąć na działanie aplikacji.

Wrażliwe informacje można wyszukiwać za pomocą narzędzi wiersza poleceń lub aplikacji takich jak iMazing. Dla zaszyfrowanych kopii zapasowych, obecność szyfrowania można potwierdzić, sprawdzając klucz “IsEncrypted” w pliku “Manifest.plist” w katalogu głównym kopii zapasowej.

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

For dealing with encrypted backups, Python scripts available in DinoSec’s GitHub repo, like backup_tool.py and backup_passwd.py, may be useful, albeit potentially requiring adjustments for compatibility with the latest iTunes/Finder versions. The iOSbackup tool is another option for accessing files within password-protected backups.

Modyfikowanie zachowania aplikacji

An example of altering app behavior through backup modifications is demonstrated in the Bither bitcoin wallet app, where the UI lock PIN is stored within net.bither.plist under the pin_code key. Removing this key from the plist and restoring the backup removes the PIN requirement, providing unrestricted access.

Podsumowanie testów pamięci pod kątem danych wrażliwych

When dealing with sensitive information stored in an application’s memory, it is crucial to limit the exposure time of this data. There are two primary approaches to investigate memory content: creating a memory dump and analyzing the memory in real time. Both methods have their challenges, including the potential to miss critical data during the dump process or analysis.

Pobieranie i analizowanie zrzutu pamięci

For both jailbroken and non-jailbroken devices, tools like objection and Fridump allow for the dumping of an app’s process memory. Once dumped, analyzing this data requires various tools, depending on the nature of the information you’re searching for.

To extract strings from a memory dump, commands such as strings or rabin2 -zz can be used:

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

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

Do bardziej szczegółowej analizy, włącznie z wyszukiwaniem konkretnych typów danych lub wzorców, radare2 oferuje rozbudowane możliwości wyszukiwania:

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

Analiza pamięci w czasie wykonywania

r2frida zapewnia potężną alternatywę do inspekcji pamięci aplikacji w czasie rzeczywistym, bez konieczności 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 kluczem zakodowanym na stałe/przewidywalnym w kodzie. Nie należy tego robić, ponieważ analiza wsteczna może pozwolić atakującym na wydobycie poufnych informacji.

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

Deweloperzy nie powinni używać deprecated algorithms do wykonywania sprawdzeń autoryzacji, przechowywania lub wysyłania danych. Niektóre z tych algorytmów to: RC4, MD4, MD5, SHA1… Jeśli do przechowywania haseł na przykład używane są hashes, należy stosować funkcje odporne na brute-force z salt.

Sprawdzenie

Główne kontrole polegają na sprawdzeniu, czy w kodzie nie ma hardcoded haseł/sekretów, czy są one przewidywalne, oraz czy kod używa jakiegoś rodzaju weak cryptography algorytmów.

Warto wiedzieć, że można automatycznie monitor niektóre crypto libraries przy użyciu objection:

ios monitor crypt

For więcej informacji o kryptograficznych API i bibliotekach iOS odwiedź https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06e-testing-cryptography

Uwierzytelnianie lokalne

Uwierzytelnianie lokalne odgrywa kluczową rolę, zwłaszcza jeśli chodzi o zabezpieczanie dostępu na zdalnym końcu przy użyciu metod kryptograficznych. Sedno sprawy jest takie, że bez poprawnej implementacji mechanizmy uwierzytelniania lokalnego mogą zostać ominięte.

Apple’s Local Authentication framework i keychain dostarczają solidnych interfejsów API dla deweloperów do wyświetlania dialogów uwierzytelniania użytkownika oraz bezpiecznego przechowywania tajnych danych. Secure Enclave zabezpiecza odciski palców dla Touch ID, podczas gdy Face ID opiera się na rozpoznawaniu twarzy bez narażania danych biometrycznych.

Aby zintegrować Touch ID/Face ID, deweloperzy mają dwie możliwości API:

  • LocalAuthentication.framework — dla wysokopoziomowego uwierzytelniania użytkownika bez dostępu do danych biometrycznych.
  • Security.framework — do niskopoziomowego dostępu do usług keychain, zabezpieczając tajne dane za pomocą uwierzytelniania biometrycznego. Różne open-source wrappers upraszczają dostęp do keychain.

Caution

Jednak zarówno LocalAuthentication.framework, jak i Security.framework mają podatności, ponieważ w głównej mierze zwracają wartości boolean bez przesyłania danych do procesów uwierzytelniania, co sprawia, że są podatne na obejścia (zob. Don’t touch me that way, by David Lindner et al).

Implementacja uwierzytelniania lokalnego

Aby wywołać uwierzytelnianie użytkownika, deweloperzy powinni użyć metody evaluatePolicy w klasie LAContext, wybierając między:

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

Pomyślne uwierzytelnienie jest sygnalizowane przez wartość boolean zwracaną przez evaluatePolicy, co wskazuje na potencjalny problem 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 przez użytkownika, za pomocą kodu urządzenia (device passcode) lub uwierzytelniania biometrycznego, takiego jak Touch ID.

Keychain oferuje możliwość ustawienia elementów z atrybutem SecAccessControl, który ogranicza dostęp do elementu aż do momentu, gdy użytkownik pomyślnie uwierzytelni się przy użyciu Touch ID lub device passcode. 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 pobrać string z keychain, wykorzystując te funkcje bezpieczeństwa. Przykłady konkretnie pokazują, jak skonfigurować kontrolę dostępu wymagającą uwierzytelnienia Touch ID i zapewnić, że dane będą dostępne tylko na urządzeniu, na którym zostały zapisane, pod warunkiem, że skonfigurowano device passcode.

// 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 podano odpowiedni odcisk palca.

// 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 frameworks w aplikacji można również wykryć, analizując listę shared dynamic libraries binarki aplikacji. Można to zrobić przy użyciu otool:

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

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

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

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

Omijanie Local Authentication Framework

Objection

Poprzez Objection Biometrics Bypass, dostępny na this GitHub page, istnieje technika pozwalająca obejść mechanizm LocalAuthentication. Rdzeń tego podejścia polega na użyciu Frida do manipulacji funkcją evaluatePolicy, zapewniając, że zawsze zwraca True, niezależnie od rzeczywistego powodzenia uwierzytelnienia. Jest to szczególnie przydatne do obejścia wadliwych procesów uwierzytelniania biometrycznego.

Aby aktywować ten bypass, używane jest następujące polecenie:

...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 w praktyce 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. Modyfikując zachowanie callbacku, sprawdzenie uwierzytelniania zostaje skutecznie ominięte.

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

// 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żyj następującego polecenia:

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

Udostępnianie UIActivity

iOS UIActivity Sharing

UIPasteboard

iOS UIPasteboard

Rozszerzenia aplikacji

iOS App Extensions

WebViews

iOS WebViews

Serializacja i kodowanie

iOS Serialisation and Encoding

Komunikacja sieciowa

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

iOS Burp Suite Configuration

Sprawdzanie nazwy hosta

Jednym z częstych problemów przy weryfikacji certyfikatu TLS jest to, że sprawdza się, czy certyfikat został podpisany przez zaufaną CA, ale nie sprawdza się, czy nazwa hosta w certyfikacie odpowiada nazwie hosta, do której nawiązywane jest połączenie.
Aby zweryfikować ten problem za pomocą Burp, po zaufaniu CA Burp na iPhonie, możesz utworzyć nowy certyfikat w Burp dla innej nazwy hosta i go użyć. Jeśli aplikacja nadal działa, oznacza to, że jest podatna.

Certificate Pinning

Jeśli aplikacja poprawnie używa SSL Pinning, będzie działać tylko wtedy, gdy certyfikat jest tym, którego się spodziewa. Podczas testów 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 Burp Mobile Assistant

Możesz również użyć objection: 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
  • Natomiast /User/Library zawiera dane zapisywane przez aplikacje poziomu użytkownika
  • Możesz uzyskać dostęp do /User/Library/Notes/notes.sqlite, aby odczytać 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 cache. W /Library/Cache/Snapshots/* możesz znaleźć snapshot wykonany aplikacji przed wysłaniem jej w tle.

Hot Patching/Wymuszone aktualizacje

Deweloperzy mogą zdalnie załatać wszystkie instalacje swojej aplikacji natychmiast bez konieczności ponownego przesyłania aplikacji do App Store i oczekiwania na zatwierdzenie.
W tym celu zwykle używa się JSPatch. Ale są też inne opcje, takie jak Siren i react-native-appstore-version-checker.
To niebezpieczny mechanizm, który może zostać nadużyty przez złośliwe SDK firm trzecich, dlatego zaleca się sprawdzenie, która metoda jest używana do automatycznych aktualizacji (jeśli w ogóle) i jej przetestowanie. Możesz spróbować pobrać wcześniejszą wersję aplikacji do tego celu.

Podmioty trzecie

Znaczącym wyzwaniem związanym z 3rd party SDKs jest brak granularnej kontroli nad ich funkcjonalnościami. Deweloperzy stoją przed wyborem: albo zintegrować SDK i zaakceptować wszystkie jego funkcje, w tym potencjalne luki bezpieczeństwa i problemy z prywatnością, albo zrezygnować z jego korzyści w całości. Często deweloperzy nie są w stanie samodzielnie załatać luk w tych SDK. Co więcej, w miarę jak SDK zyskują zaufanie społeczności, niektóre mogą zacząć zawierać malware.

Usługi oferowane przez SDK firm trzecich mogą obejmować śledzenie zachowań użytkowników, wyświetlanie reklam lub ulepszenia UX. Wprowadza to jednak 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 firm trzecich tylko do niezbędnych oraz upewnienie się, że żadne wrażliwe dane nie są ujawniane.

Implementacja usług firm 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ć zanonimizowane, aby zapobiec ujawnieniu Personal Identifiable Information (PII).

Aby zidentyfikować biblioteki używane przez aplikację, można użyć polecenia otool. Narzędzie to należy uruchomić na aplikacji oraz na każdej bibliotece współdzielonej, której używa, aby odkryć dodatkowe biblioteki.

otool -L <application_path>

Interesujące podatności i studia przypadków

Air Keyboard Remote Input Injection

Itunesstored Bookassetd Sandbox Escape

Bibliografia 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