hacktricks/mobile-pentesting/ios-pentesting
2024-05-06 11:16:10 +00:00
..
basic-ios-testing-operations.md Translated to Korean 2024-02-10 21:30:13 +00:00
burp-configuration-for-ios.md Translated ['crypto-and-stego/certificates.md', 'generic-methodologies-a 2024-05-06 11:16:10 +00:00
extracting-entitlements-from-compiled-application.md Translated to Korean 2024-02-10 21:30:13 +00:00
frida-configuration-in-ios.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-05-05 22:46:17 +00:00
ios-app-extensions.md Translated to Korean 2024-02-10 21:30:13 +00:00
ios-basics.md Translated to Korean 2024-02-10 21:30:13 +00:00
ios-custom-uri-handlers-deeplinks-custom-schemes.md Translated to Korean 2024-02-10 21:30:13 +00:00
ios-hooking-with-objection.md Translated to Korean 2024-02-10 21:30:13 +00:00
ios-protocol-handlers.md Translated to Korean 2024-02-10 21:30:13 +00:00
ios-serialisation-and-encoding.md Translated to Korean 2024-02-10 21:30:13 +00:00
ios-testing-environment.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-05-05 22:46:17 +00:00
ios-uiactivity-sharing.md Translated to Korean 2024-02-10 21:30:13 +00:00
ios-uipasteboard.md Translated ['binary-exploitation/rop-return-oriented-programing/ret2lib/ 2024-05-02 15:11:39 +00:00
ios-universal-links.md Translated to Korean 2024-02-10 21:30:13 +00:00
ios-webviews.md Translated to Korean 2024-02-10 21:30:13 +00:00
README.md Translated ['crypto-and-stego/certificates.md', 'generic-methodologies-a 2024-05-06 11:16:10 +00:00

iOS Pentesting


Trickest를 사용하여 세계에서 가장 고급 커뮤니티 도구로 구동되는 워크플로우를 쉽게 구축하고 자동화하세요.
오늘 바로 액세스하세요:

{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=ios-pentesting" %}

htARTE (HackTricks AWS Red Team Expert)로부터 제로에서 영웅까지의 AWS 해킹을 배우세요

HackTricks를 지원하는 다른 방법:

iOS 기본 사항

{% content-ref url="ios-basics.md" %} ios-basics.md {% endcontent-ref %}

테스트 환경

이 페이지에서 iOS 시뮬레이터, 에뮬레이터탈옥에 대한 정보를 찾을 수 있습니다:

{% content-ref url="ios-testing-environment.md" %} ios-testing-environment.md {% endcontent-ref %}

초기 분석

기본 iOS 테스트 작업

테스트 중에 여러 작업이 제안될 것입니다(장치에 연결, 파일 읽기/쓰기/업로드/다운로드, 일부 도구 사용...). 따라서 이러한 작업 중 어떤 것을 수행해야 하는지 모르는 경우 페이지를 읽기 시작하세요:

{% content-ref url="basic-ios-testing-operations.md" %} basic-ios-testing-operations.md {% endcontent-ref %}

{% hint style="info" %} 다음 단계를 위해 앱이 장치에 설치되어 있어야 하며 이미 앱의 IPA 파일을 얻었어야합니다.
이를 수행하는 방법을 알아보려면 기본 iOS 테스트 작업 페이지를 읽으세요. {% endhint %}

기본 정적 분석

MobSF 도구를 사용하여 IPA 파일에 대한 자동 정적 분석을 수행하는 것이 좋습니다.

바이너리에 존재하는 보호 기능 식별:

  • PIE (Position Independent Executable): 활성화되면 애플리케이션이 시작할 때마다 무작위 메모리 주소로 로드되어 초기 메모리 주소를 예측하기 어렵게 만듭니다.
otool -hv <app-binary> | grep PIE   # PIE 플래그를 포함해야 함
  • 스택 캐너리: 스택의 무결성을 확인하기 위해 함수를 호출하기 전에 스택에 'canary' 값이 배치되고 함수가 종료될 때 다시 확인됩니다.
otool -I -v <app-binary> | grep stack_chk   # stack_chk_guard 및 stack_chk_fail 심볼을 포함해야 함
  • ARC (Automatic Reference Counting): 일반적인 메모리 손상 결함을 방지하기 위해
otool -I -v <app-binary> | grep objc_release   # _objc_release 심볼을 포함해야 함
  • 암호화된 바이너리: 바이너리는 암호화되어 있어야 함
otool -arch all -Vl <app-binary> | grep -A5 LC_ENCRYPT   # cryptid가 1이어야 함

민감하거나 취약한 함수 식별

  • 약한 해싱 알고리즘
# iOS 장치에서
otool -Iv <app> | grep -w "_CC_MD5"
otool -Iv <app> | grep -w "_CC_SHA1"

# 리눅스에서
grep -iER "_CC_MD5"
grep -iER "_CC_SHA1"
  • 보안되지 않은 난수 함수
# iOS 장치에서
otool -Iv <app> | grep -w "_random"
otool -Iv <app> | grep -w "_srand"
otool -Iv <app> | grep -w "_rand"

# 리눅스에서
grep -iER "_random"
grep -iER "_srand"
grep -iER "_rand"
  • 보안되지 않은 'Malloc' 함수
# iOS 장치에서
otool -Iv <app> | grep -w "_malloc"

# 리눅스에서
grep -iER "_malloc"
  • 보안되지 않고 취약한 함수
# 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"

# 리눅스에서
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"

기본 동적 분석

MobSF가 수행하는 동적 분석을 확인하세요. 다양한 뷰를 탐색하고 상호 작용해야 하지만 여러 클래스를 후킹하고 다른 작업을 수행하며 완료되면 보고서를 준비할 것입니다.

설치된 앱 목록

명령어 frida-ps -Uai를 사용하여 설치된 앱의 번들 식별자를 결정하세요:

$ 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

기본 열거 및 후킹

어플리케이션의 구성 요소를 열거하는 방법과 objection을 사용하여 쉽게 메소드와 클래스를 후킹하는 방법을 배우세요:

{% content-ref url="ios-hooking-with-objection.md" %} ios-hooking-with-objection.md {% endcontent-ref %}

IPA 구조

IPA 파일의 구조는 본질적으로 압축된 패키지입니다. 확장자를 .zip으로 변경하여 압축을 풀면 내용물이 나타납니다. 이 구조 안에서 **번들(Bundle)**은 설치 준비가 된 완전히 패키지된 어플리케이션을 나타냅니다. 내부에는 어플리케이션의 리소스를 캡슐화하는 <NAME>.app이라는 디렉토리가 포함되어 있습니다.

  • Info.plist: 이 파일은 어플리케이션의 구체적인 구성 세부 정보를 보유합니다.
  • _CodeSignature/: 이 디렉토리에는 번들 내 모든 파일의 무결성을 보장하는 서명을 포함하는 plist 파일이 포함되어 있습니다.
  • Assets.car: 아이콘과 같은 에셋 파일을 저장하는 압축된 아카이브입니다.
  • Frameworks/: 이 폴더에는 어플리케이션의 네이티브 라이브러리가 포함되어 있으며, .dylib 또는 .framework 파일 형식일 수 있습니다.
  • PlugIns/: 이 폴더에는 .appex 파일로 알려진 어플리케이션의 확장이 포함될 수 있지만 항상 존재하는 것은 아닙니다.
  • Core Data: 이것은 오프라인 사용을 위해 어플리케이션의 영구 데이터를 저장하고, 임시 데이터를 캐시하며, 단일 장치에서 앱에 되돌리기 기능을 추가하는 데 사용됩니다. 단일 iCloud 계정의 여러 장치 간 데이터를 동기화하려면 Core Data가 스키마를 CloudKit 컨테이너로 자동으로 미러링합니다.
  • PkgInfo: PkgInfo 파일은 어플리케이션 또는 번들의 유형 및 생성자 코드를 지정하는 대체 방법입니다.
  • en.lproj, fr.proj, Base.lproj: 특정 언어에 대한 리소스를 포함하며, 지원되지 않는 언어의 경우 기본 리소스가 포함된 언어 팩입니다.
  • 보안: _CodeSignature/ 디렉토리는 디지털 서명을 통해 번들된 모든 파일의 무결성을 확인하여 어플리케이션의 보안에 중요한 역할을 합니다.
  • 에셋 관리: Assets.car 파일은 그래픽 에셋을 효율적으로 관리하기 위해 압축을 사용하며, 어플리케이션 성능 최적화와 전체 크기 축소에 중요합니다.
  • 프레임워크 및 플러그인: 이러한 디렉토리는 iOS 어플리케이션의 모듈성을 강조하며, 재사용 가능한 코드 라이브러리(Frameworks/)를 포함하고 앱 기능을 확장(PlugIns/)할 수 있도록 합니다.
  • 로컬라이제이션: 이 구조는 여러 언어를 지원하여 특정 언어 팩의 리소스를 포함함으로써 글로벌 어플리케이션 접근을 용이하게 합니다.

Info.plist

Info.plist는 iOS 어플리케이션의 중추적인 역할을 하며, 키-값 쌍 형식으로 주요 구성 데이터를 캡슐화합니다. 이 파일은 어플리케이션 뿐만 아니라 번들 내에 번들된 앱 확장 및 프레임워크에 대해서도 필수적입니다. XML 또는 이진 형식으로 구성되어 있으며, 앱 권한부터 보안 구성까지 핵심 정보를 보유합니다. 사용 가능한 키에 대한 자세한 탐구를 위해 Apple Developer Documentation를 참조할 수 있습니다.

이 파일을 더 쉽게 다루고자 하는 사용자를 위해 macOS의 plutil을 사용하여 XML 변환을 손쉽게 수행할 수 있습니다(버전 10.2 이상에서 네이티브로 제공) 또는 Linux에서 plistutil을 사용할 수 있습니다. 변환을 위한 명령어는 다음과 같습니다:

  • macOS용:
$ plutil -convert xml1 Info.plist
  • 리눅스용:
$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist

다양한 정보 중 Info.plist 파일이 누설할 수 있는 주목할만한 항목으로는 앱 권한 문자열(UsageDescription), 사용자 정의 URL schemes(CFBundleURLTypes), 그리고 App Transport Security 구성(NSAppTransportSecurity)이 있습니다. 이러한 항목들과 함께 내보낸/수입한 사용자 정의 문서 유형(UTExportedTypeDeclarations / UTImportedTypeDeclarations)과 같은 다른 항목들은 파일을 검사하거나 간단한 grep 명령을 사용하여 쉽게 찾을 수 있습니다:

$ grep -i <keyword> Info.plist

데이터 경로

iOS 환경에서는 디렉토리가 시스템 애플리케이션사용자 설치 애플리케이션을 위해 명시적으로 지정됩니다. 시스템 애플리케이션은 /Applications 디렉토리에 있으며, 사용자 설치 앱은 /var/mobile/containers/Data/Application/ 아래에 배치됩니다. 이러한 애플리케이션들은 128비트 UUID라고 불리는 고유 식별자가 할당되어 있어 디렉토리 이름의 무작위성 때문에 앱 폴더를 수동으로 찾는 작업이 어려울 수 있습니다.

{% hint style="warning" %} iOS의 애플리케이션은 샌드박스화되어야 하므로, 각 앱은 $HOME/Library/Containers 내에 앱의 **CFBundleIdentifier**를 폴더 이름으로 하는 폴더도 가지고 있습니다.

그러나 두 폴더 (데이터 및 컨테이너 폴더) 모두 .com.apple.mobile_container_manager.metadata.plist 파일을 가지고 있으며, 이 파일은 MCMetadataIdentifier 키에서 두 파일을 연결합니다. {% endhint %}

사용자 설치 앱의 설치 디렉토리를 발견하기 위해 objection 도구는 유용한 env 명령을 제공합니다. 이 명령은 해당 앱에 대한 자세한 디렉토리 정보를 나타냅니다. 아래는 이 명령을 사용하는 예시입니다:

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

또는 find 명령을 사용하여 /private/var/containers 내에서 앱 이름을 검색할 수 있습니다:

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

명령어 pslsof와 같은 것들을 활용하여 앱의 프로세스를 식별하고 각각 열린 파일을 나열할 수도 있습니다. 이를 통해 애플리케이션의 활성 디렉토리 경로에 대한 통찰을 얻을 수 있습니다:

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

번들 디렉토리:

  • AppName.app
  • 이것은 IPA에서 본 것과 같은 애플리케이션 번들로, 필수적인 애플리케이션 데이터, 정적 콘텐츠 및 애플리케이션의 컴파일된 이진 파일을 포함합니다.
  • 이 디렉토리는 사용자에게 가시적이지만 사용자는 쓸 수 없습니다.
  • 이 디렉토리의 콘텐츠는 백업되지 않습니다.
  • 이 폴더의 내용은 코드 서명을 확인하는 데 사용됩니다.

데이터 디렉토리:

  • Documents/
  • 모든 사용자 생성 데이터를 포함합니다. 애플리케이션 최종 사용자가 이 데이터를 생성합니다.
  • 사용자에게 가시적이며 사용자는 쓸 수 있습니다.
  • 이 디렉토리의 콘텐츠는 백업됩니다.
  • 앱은 NSURLIsExcludedFromBackupKey를 설정하여 경로를 비활성화할 수 있습니다.
  • Library/
  • 사용자별이 아닌 파일캐시, 환경 설정, 쿠키 및 속성 목록 (plist) 구성 파일 등을 포함합니다.
  • iOS 앱은 일반적으로 Application SupportCaches 하위 디렉토리를 사용하지만 앱은 사용자 정의 하위 디렉토리를 생성할 수 있습니다.
  • Library/Caches/
  • 반영구적인 캐시 파일을 포함합니다.
  • 사용자에게 **보이지 않으며 사용자는 쓸 수 없습니다.
  • 이 디렉토리의 콘텐츠는 백업되지 않습니다.
  • 저장 공간이 부족하고 앱이 실행되지 않을 때 OS가 이 디렉토리의 파일을 자동으로 삭제할 수 있습니다.
  • Library/Application Support/
  • 앱 실행에 필요한 지속적인 파일을 포함합니다.
  • 사용자에게 **보이지 않으며 사용자는 쓸 수 없습니다.
  • 이 디렉토리의 콘텐츠는 백업됩니다.
  • 앱은 NSURLIsExcludedFromBackupKey를 설정하여 경로를 비활성화할 수 있습니다.
  • Library/Preferences/
  • 애플리케이션이 다시 시작되어도 지속될 수 있는 속성을 저장하는 데 사용됩니다.
  • 정보는 [BUNDLE_ID].plist라는 plist 파일에 암호화되지 않은 상태로 애플리케이션 샌드박스 내에 저장됩니다.
  • NSUserDefaults를 사용하여 저장된 모든 키/값 쌍은 이 파일에서 찾을 수 있습니다.
  • tmp/
  • 앱 시작 간에 지속되지 않아도 되는 임시 파일을 작성하는 데 사용합니다.
  • 비지속적인 캐시 파일을 포함합니다.
  • 사용자에게 보이지 않습니다.
  • 이 디렉토리의 콘텐츠는 백업되지 않습니다.
  • 저장 공간이 부족하고 앱이 실행되지 않을 때 OS가 이 디렉토리의 파일을 자동으로 삭제할 수 있습니다.

iGoat-Swift의 Application Bundle (.app) 디렉토리를 번들 디렉토리 내에서 더 자세히 살펴봅시다 (/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app):

OWASP.iGoat-Swift on (iPhone: 11.1.2) [usb] # ls
NSFileType      Perms  NSFileProtection    ...  Name
------------  -------  ------------------  ...  --------------------------------------
Regular           420  None                ...  rutger.html
Regular           420  None                ...  mansi.html
Regular           420  None                ...  splash.html
Regular           420  None                ...  about.html

Regular           420  None                ...  LICENSE.txt
Regular           420  None                ...  Sentinel.txt
Regular           420  None                ...  README.txt

이진 반전

<application-name>.app 폴더 안에 <application-name>이라는 바이너리 파일이 있습니다. 이 파일이 실행되는 파일입니다. otool 도구를 사용하여 이진 파일을 기본적으로 검사할 수 있습니다:

otool -Vh DVIA-v2 #Check some compilation attributes
magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64    ARM64        ALL  0x00     EXECUTE    65       7112   NOUNDEFS DYLDLINK TWOLEVEL WEAK_DEFINES BINDS_TO_WEAK PIE

otool -L DVIA-v2 #Get third party libraries
DVIA-v2:
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.1)
/usr/lib/libsqlite3.dylib (compatibility version 9.0.0, current version 274.6.0)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
@rpath/Bolts.framework/Bolts (compatibility version 1.0.0, current version 1.0.0)
[...]

앱이 암호화되었는지 확인

다음을 확인하십시오:

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

바이너리 해석

텍스트 섹션을 해석하십시오:

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

샘플 애플리케이션의 Objective-C 세그먼트를 출력하려면 다음을 사용할 수 있습니다:

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

Objective-C 코드를 더 간결하게 얻으려면 class-dump를 사용할 수 있습니다:

class-dump some-app
//
//     Generated by class-dump 3.5 (64 bit).
//
//     class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard.
//

#pragma mark Named Structures

struct CGPoint {
double _field1;
double _field2;
};

struct CGRect {
struct CGPoint _field1;
struct CGSize _field2;
};

struct CGSize {
double _field1;
double _field2;
};

그러나 이진 파일을 분해하는 가장 좋은 옵션은: HopperIDA.


Trickest를 사용하여 세계에서 가장 고급 커뮤니티 도구로 구동되는 워크플로우를 쉽게 구축하고 자동화하세요.
오늘 바로 액세스하세요:

{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=ios-pentesting" %}

데이터 저장

iOS가 기기에 데이터를 저장하는 방법에 대해 알아보려면 이 페이지를 읽어보세요:

{% content-ref url="ios-basics.md" %} ios-basics.md {% endcontent-ref %}

{% hint style="warning" %} 애플리케이션을 설치한 직후, 애플리케이션의 모든 기능을 확인한 후한 사용자에서 로그아웃한 후 다른 사용자로 로그인한 후에는 다음 위치에 정보를 저장해야 합니다.
목표는 애플리케이션의 민감한 정보(암호, 토큰), 현재 사용자 및 이전에 로그인한 사용자의를 찾는 것입니다. {% endhint %}

Plist

plist 파일은 키-값 쌍을 포함하는 구조화된 XML 파일입니다. 이는 영구 데이터를 저장하는 방법이므로 때로는 이러한 파일에서 민감한 정보를 찾을 수 있습니다. 앱을 설치한 후 및 강도 높게 사용한 후에 이러한 파일을 확인하는 것이 좋습니다.

plist 파일에 데이터를 영구적으로 저장하는 가장 일반적인 방법은 NSUserDefaults를 사용하는 것입니다. 이 plist 파일은 **Library/Preferences/<appBundleID>.plist**에 앱 샌드박스 내에 저장됩니다.

NSUserDefaults 클래스는 기본 시스템과 상호 작용하기 위한 프로그래밍 인터페이스를 제공합니다. 기본 시스템을 통해 애플리케이션이 사용자 환경 설정에 따라 동작을 사용자 정의할 수 있습니다. NSUserDefaults에 의해 저장된 데이터는 애플리케이션 번들에서 볼 수 있습니다. 이 클래스는 plist 파일데이터를 저장하지만 소량의 데이터와 함께 사용하기 위해 설계되었습니다.

이 데이터는 신뢰할 수 있는 컴퓨터를 통해 직접 액세스할 수 없지만 백업을 수행하여 액세스할 수 있습니다.

NSUserDefaults를 사용하여 저장된 정보를 덤프할 수 있으며 objection의 ios nsuserdefaults get을 사용할 수 있습니다.

애플리케이션이 사용하는 모든 plist를 찾으려면 /private/var/mobile/Containers/Data/Application/{APPID}에 액세스하여 다음을 실행하세요:

find ./ -name "*.plist"

XML 또는 이진 (bplist) 형식의 파일을 XML로 변환하는 방법은 운영 체제에 따라 다양합니다:

macOS 사용자를 위한: plutil 명령을 활용하십시오. 이 명령은 macOS (10.2+)에 내장된 도구로, 이 목적을 위해 설계되었습니다:

$ plutil -convert xml1 Info.plist

리눅스 사용자를 위한 안내: 먼저 libplist-utils를 설치한 후에 파일을 변환하기 위해 plistutil을 사용하십시오:

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

Objection 세션 내에서: 모바일 애플리케이션을 분석하기 위해 특정 명령어를 사용하여 plist 파일을 직접 변환할 수 있습니다:

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

Core Data

Core Data은 애플리케이션의 모델 계층을 관리하기 위한 프레임워크입니다. Core Data는 SQLite를 영구 저장소로 사용할 수 있지만, 프레임워크 자체는 데이터베이스가 아닙니다.
CoreData는 기본적으로 데이터를 암호화하지 않습니다. 그러나 CoreData에 추가 암호화 레이어를 추가할 수 있습니다. 자세한 내용은 GitHub Repo를 참조하십시오.

애플리케이션의 SQLite Core Data 정보는 다음 경로에서 찾을 수 있습니다. /private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support

만약 SQLite를 열고 민감한 정보에 액세스할 수 있다면, 설정 오류를 발견한 것입니다.

{% code title="iGoat에서 가져온 코드" %}

-(void)storeDetails {
AppDelegate * appDelegate = (AppDelegate *)(UIApplication.sharedApplication.delegate);

NSManagedObjectContext *context =[appDelegate managedObjectContext];

User *user = [self fetchUser];
if (user) {
return;
}
user = [NSEntityDescription insertNewObjectForEntityForName:@"User"
inManagedObjectContext:context];
user.email = CoreDataEmail;
user.password = CoreDataPassword;
NSError *error;
if (![context save:&error]) {
NSLog(@"Error in saving data: %@", [error localizedDescription]);

}else{
NSLog(@"data stored in core data");
}
}

{% endcode %}

YapDatabase

YapDatabase은 SQLite 위에 구축된 key/value 저장소입니다.
Yap 데이터베이스는 sqlite 데이터베이스이므로 이전 섹션에서 제안된 명령을 사용하여 해당 데이터베이스를 찾을 수 있습니다.

다른 SQLite 데이터베이스

애플리케이션이 자체 sqlite 데이터베이스를 생성하는 것이 일반적입니다. 그들은 그 안에 민감한 데이터저장할 수 있으며 이를 암호화하지 않은 채로 남겨 둘 수 있습니다. 따라서 항상 애플리케이션 디렉토리로 이동하여 저장된 데이터가 있는 곳('/private/var/mobile/Containers/Data/Application/{APPID}')에서 애플리케이션 디렉토리 내의 모든 데이터베이스를 확인하는 것이 흥미로울 수 있습니다.

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

Firebase 실시간 데이터베이스

개발자들은 Firebase 실시간 데이터베이스를 통해 NoSQL 클라우드 호스팅 데이터베이스 내에서 데이터를 저장 및 동기화할 수 있습니다. 데이터는 JSON 형식으로 저장되며, 연결된 모든 클라이언트에 실시간으로 동기화됩니다.

미구성된 Firebase 데이터베이스를 확인하는 방법은 여기에서 찾을 수 있습니다:

{% content-ref url="../../network-services-pentesting/pentesting-web/buckets/firebase-database.md" %} firebase-database.md {% endcontent-ref %}

Realm 데이터베이스

Realm Objective-CRealm Swift은 Apple에서 제공하지 않는 데이터 저장을 위한 강력한 대안을 제공합니다. 기본적으로 데이터는 암호화되지 않은 상태로 저장되며, 특정 구성을 통해 암호화할 수 있습니다.

데이터베이스는 다음 위치에 있습니다: /private/var/mobile/Containers/Data/Application/{APPID}. 이러한 파일을 탐색하기 위해 다음과 같은 명령을 활용할 수 있습니다:

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

데이터베이스 파일을 보려면 Realm Studio 도구를 추천합니다.

Realm 데이터베이스 내에서 암호화를 구현하려면 다음 코드 스니펫을 사용할 수 있습니다:

// Open the encrypted Realm file where getKey() is a method to obtain a key from the Keychain or a server
let config = Realm.Configuration(encryptionKey: getKey())
do {
let realm = try Realm(configuration: config)
// Use the Realm as normal
} catch let error as NSError {
// If the encryption key is wrong, `error` will say that it's an invalid database
fatalError("Error opening realm: \(error)")
}

Couchbase Lite 데이터베이스

Couchbase Lite가벼운내장형 데이터베이스 엔진으로, 문서 지향 (NoSQL) 접근 방식을 따릅니다. iOSmacOS에 네이티브로 설계되어 데이터를 싱크하는 기능을 제공합니다.

장치에서 Couchbase 데이터베이스를 식별하려면 다음 디렉토리를 검사해야 합니다:

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

쿠키

iOS는 각 앱 폴더 내의 **Library/Cookies/cookies.binarycookies**에 앱의 쿠키를 저장합니다. 그러나 개발자들은 때때로 백업에서 쿠키 파일에 액세스할 수 있기 때문에 이를 키체인에 저장하기로 결정하기도 합니다.

쿠키 파일을 검사하려면 이 파이썬 스크립트를 사용하거나 objection의 **ios cookies get**을 사용할 수 있습니다.
또한 objection을 사용하여 이러한 파일을 JSON 형식으로 변환하고 데이터를 검사할 수도 있습니다.

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

캐시

기본적으로 NSURLSession은 Cache.db 데이터베이스에 HTTP 요청 및 응답과 같은 데이터를 저장합니다. 이 데이터베이스에는 토큰, 사용자 이름 또는 기타 민감한 정보가 캐시된 경우 민감한 데이터가 포함될 수 있습니다. 캐시된 정보를 찾으려면 앱의 데이터 디렉토리(/var/mobile/Containers/Data/Application/<UUID>)를 열고 /Library/Caches/<Bundle Identifier>로 이동하십시오. WebKit 캐시도 Cache.db 파일에 저장됩니다. Objectionsqlite connect Cache.db 명령을 사용하여 데이터베이스를 열고 상호 작용할 수 있습니다. 이는 일반 SQLite 데이터베이스이기 때문입니다.

요청 또는 응답에 민감한 정보가 포함될 수 있기 때문에 이 데이터의 캐싱을 비활성화하는 것이 권장됩니다. 아래 목록은 이를 달성하는 다양한 방법을 보여줍니다:

  1. 로그아웃 후 캐시된 응답을 제거하는 것이 권장됩니다. Apple이 제공하는 removeAllCachedResponses 메서드를 사용하여 이 작업을 수행할 수 있습니다. 다음과 같이 이 메서드를 호출할 수 있습니다:

    URLCache.shared.removeAllCachedResponses()

    이 메서드는 Cache.db 파일에서 모든 캐시된 요청과 응답을 제거합니다.

  2. 쿠키의 이점을 사용할 필요가 없다면 URLSession의 .ephemeral 구성 속성을 사용하는 것이 좋습니다. 이는 쿠키 및 캐시 저장을 비활성화합니다.

Apple 문서:

임시 세션 구성 개체는 기본 세션 구성과 유사하지만 해당 세션 개체는 캐시, 자격 증명 저장소 또는 디스크에 세션 관련 데이터를 저장하지 않습니다. 대신, 세션 관련 데이터는 RAM에 저장됩니다. 임시 세션이 데이터를 디스크에 쓰는 유일한 시점은 URL의 내용을 파일로 쓰도록 지시할 때입니다.

캐시는 [.notAllowed](https://developer.apple.com/documentation/foundation/urlcache/storagepolicy/notallowed)로 캐시 정책을 설정하여 비활성화할 수도 있습니다. 이렇게 하면 캐시를 메모리나 디스크에 저장하지 않도록 설정됩니다.

### 스냅샷

홈 버튼을 누를 때마다 iOS는 현재 화면의 스냅샷을 찍어 애플리케이션으로의 전환을 훨씬 부드럽게 할 수 있습니다. 그러나 현재 화면에 민감한 데이터가 있는 경우 해당 데이터가 이미지에 저장되어 부팅을 거치더라도 유지됩니다. 이러한 스냅샷은 홈 화면을 두 번 탭하여 앱 간에 전환할 수도 있습니다.

아이폰이 탈옥되지 않은 경우, 공격자는 이러한 스냅샷을 보려면 장치에 액세스할 수 있어야 합니다. 기본적으로 마지막 스냅샷은 `Library/Caches/Snapshots/` 또는 `Library/SplashBoard/Snapshots` 폴더에 애플리케이션의 샌드박스에 저장됩니다 (신뢰하는 컴퓨터는 iOX 7.0부터 파일 시스템에 액세스할 수 없습니다).

이러한 부적절한 동작을 방지하는 한 가지 방법은 스냅샷을 찍기 전에 민감한 데이터를 지우거나 빈 화면을 표시하는 것입니다. 이를 위해 `ApplicationDidEnterBackground()` 함수를 사용할 수 있습니다.

다음은 기본 스크린샷을 설정하는 샘플 개선 방법입니다.

Swift:
private var backgroundImage: UIImageView?

func applicationDidEnterBackground(_ application: UIApplication) {
let myBanner = UIImageView(image: #imageLiteral(resourceName: "overlayImage"))
myBanner.frame = UIScreen.main.bounds
backgroundImage = myBanner
window?.addSubview(myBanner)
}

func applicationWillEnterForeground(_ application: UIApplication) {
backgroundImage?.removeFromSuperview()
}

Objective-C:

@property (UIImageView *)backgroundImage;

- (void)applicationDidEnterBackground:(UIApplication *)application {
UIImageView *myBanner = [[UIImageView alloc] initWithImage:@"overlayImage.png"];
self.backgroundImage = myBanner;
self.backgroundImage.bounds = UIScreen.mainScreen.bounds;
[self.window addSubview:myBanner];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
[self.backgroundImage removeFromSuperview];
}

이 코드는 애플리케이션이 백그라운드로 전환될 때 overlayImage.png로 배경 이미지를 설정합니다. overlayImage.png은 항상 현재 뷰를 덮어씁니다.

키체인

iOS 키체인에 액세스하고 관리하기 위해 Keychain-Dumper와 같은 도구가 있습니다. 이는 탈옥된 장치에 적합합니다. 또한 Objection은 비슷한 목적을 위해 ios keychain dump 명령을 제공합니다.

자격 증명 저장

NSURLCredential 클래스는 NSUserDefaults나 다른 래퍼를 우회하여 민감한 정보를 키체인에 직접 저장하는 데 이상적입니다. 로그인 후 자격 증명을 저장하려면 다음 Swift 코드를 사용합니다:

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

사용자 정의 키보드 및 키보드 캐시

iOS 8.0부터 사용자는 설정 > 일반 > 키보드 > 키보드에서 관리 가능한 사용자 정의 키보드 확장을 설치할 수 있습니다. 이러한 키보드는 확장된 기능을 제공하지만, 키 입력 로깅 및 외부 서버로 데이터 전송의 위험을 가지며, 사용자에게 네트워크 액세스가 필요한 키보드에 대해 알림이 제공됩니다. 앱은 민감한 정보 입력에 대해 사용자 정의 키보드의 사용을 제한할 수 있습니다.

보안 권장 사항:

  • 보안을 강화하기 위해 타사 키보드를 비활성화하는 것이 좋습니다.
  • 기본 iOS 키보드의 자동 수정 및 자동 제안 기능을 주의하십시오. 이 기능은 Library/Keyboard/{locale}-dynamic-text.dat 또는 /private/var/mobile/Library/Keyboard/dynamic-text.dat에 위치한 캐시 파일에 민감한 정보를 저장할 수 있습니다. 이러한 캐시 파일은 정기적으로 민감한 데이터를 확인해야 합니다. 캐시된 데이터를 지우기 위해 설정 > 일반 > 재설정 > 키보드 사전 재설정을 통해 키보드 사전을 재설정하는 것이 권장됩니다.
  • 네트워크 트래픽을 가로채면 사용자 정의 키보드가 원격으로 키 입력을 전송하는지 확인할 수 있습니다.

텍스트 필드 캐싱 방지

UITextInputTraits 프로토콜은 자동 수정 및 안전한 텍스트 입력을 관리하는 속성을 제공하여 민감한 정보 캐싱을 방지하는 데 필수적입니다. 예를 들어, 자동 수정을 비활성화하고 안전한 텍스트 입력을 활성화하는 것은 다음과 같이 할 수 있습니다:

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

또한, 개발자들은 특히 비밀번호와 PIN과 같은 민감한 정보를 입력하는 텍스트 필드에 대해 autocorrectionTypeUITextAutocorrectionTypeNo로 설정하고 secureTextEntryYES로 설정하여 캐싱을 비활성화해야 합니다.

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

로그

디버깅 코드는 종종 로그 기록을 사용합니다. 로그에는 민감한 정보가 포함될 수 있으므로 위험이 따릅니다. 이전에는 iOS 6 및 이전 버전에서 모든 앱이 액세스할 수 있는 로그로 인해 민감한 데이터 유출 위험이 있었습니다. 지금은 애플리케이션이 자체 로그에만 액세스할 수 있도록 제한됩니다.

이러한 제한에도 불구하고 잠금 해제된 장치에 물리적 액세스 권한이 있는 공격자는 컴퓨터에 장치를 연결하고 로그를 읽어내는 방식으로 이를 이용할 수 있습니다. 로그는 앱이 제거된 후에도 디스크에 남아있음을 주의해야 합니다.

위험을 완화하기 위해 앱과 철저히 상호작용하여 민감한 정보가 우연히 기록되지 않도록 확인하는 것이 좋습니다.

잠재적인 유출을 위해 앱의 소스 코드를 검토할 때 NSLog, NSAssert, NSCAssert, fprintf와 같은 내장 함수에 대한 미리 정의된사용자 정의 로깅 문장 및 사용자 정의 구현에 대한 Logging 또는 Logfile와 같은 키워드를 찾아야 합니다.

시스템 로그 모니터링

앱은 민감할 수 있는 다양한 정보를 기록합니다. 이러한 로그를 모니터링하기 위해 다음과 같은 도구 및 명령어를 사용합니다:

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

다음은 유용합니다. 또한 Xcode는 콘솔 로그를 수집하는 방법을 제공합니다:

  1. Xcode를 엽니다.
  2. iOS 장치를 연결합니다.
  3. Window -> Devices and Simulators로 이동합니다.
  4. 장치를 선택합니다.
  5. 조사 중인 문제를 트리거합니다.
  6. Open Console 버튼을 사용하여 새 창에서 로그를 확인합니다.

더 고급 로깅을 위해 장치 쉘에 연결하고 socat을 사용하여 실시간 로그 모니터링을 제공할 수 있습니다:

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

로그 활동을 관찰하는 명령어는 문제를 진단하거나 로그에서 잠재적인 데이터 누출을 식별하는 데 매우 유용할 수 있습니다.



Trickest를 사용하여 세계에서 가장 고급 커뮤니티 도구를 활용한 워크플로우를 쉽게 구축하고 자동화할 수 있습니다.
오늘 바로 액세스하세요:

{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=ios-pentesting" %}

백업

iOS에는 자동 백업 기능이 통합되어 있어 iTunes(맥OS 카탈리나까지), Finder(맥OS 카탈리나 이후) 또는 iCloud를 통해 장치 데이터 사본을 쉽게 만들 수 있습니다. 이러한 백업은 Apple Pay 세부 정보나 Touch ID 구성과 같은 매우 민감한 요소를 제외한 거의 모든 장치 데이터를 포함합니다.

보안 위험

백업에 설치된 앱 및 그 데이터가 포함되면 잠재적인 데이터 누출 문제와 백업 수정이 앱 기능을 변경할 수 있는 위험이 발생합니다. 이러한 위험을 완화하기 위해 앱 디렉토리나 하위 디렉토리에 민감한 정보를 평문으로 저장하지 않는 것이 권장됩니다.

백업에서 파일 제외

Documents/Library/Application Support/에 있는 파일은 기본적으로 백업됩니다. 개발자는 NSURLIsExcludedFromBackupKey를 사용하여 특정 파일이나 디렉토리를 백업에서 제외할 수 있습니다. 이러한 실천은 민감한 데이터가 백업에 포함되는 것을 방지하기 위해 중요합니다.

취약점 테스트

앱의 백업 보안을 평가하려면 Finder를 사용하여 백업을 생성한 다음 애플의 공식 문서의 안내에 따라 해당 백업을 찾습니다. 백업을 분석하여 앱 동작에 영향을 줄 수 있는 민감한 데이터나 구성을 확인합니다.

민감한 정보는 명령줄 도구나 iMazing와 같은 애플리케이션을 사용하여 찾을 수 있습니다. 암호화된 백업의 경우, 암호화의 존재는 백업 루트의 "Manifest.plist" 파일에서 "IsEncrypted" 키를 확인하여 확인할 수 있습니다.

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

암호화된 백업 다루기

DinoSec의 GitHub 저장소에서 제공되는 Python 스크립트인 backup_tool.pybackup_passwd.py는 최신 iTunes/Finder 버전과 호환되도록 조정이 필요할 수 있지만 유용할 수 있습니다. 비밀번호로 보호된 백업 내의 파일에 액세스하기 위한 또 다른 옵션으로 iOSbackup 도구가 있습니다.

앱 동작 수정

백업 수정을 통해 앱 동작을 변경하는 예시는 Bither 비트코인 지갑 앱에서 보여집니다. 여기서 UI 잠금 PIN은 pin_code 키 아래의 net.bither.plist에 저장됩니다. 이 키를 plist에서 제거하고 백업을 복원하면 PIN 요구 사항이 제거되어 제한 없는 액세스가 제공됩니다.

민감한 데이터에 대한 메모리 테스트 요약

애플리케이션의 메모리에 저장된 민감한 정보를 다룰 때, 이 데이터의 노출 시간을 제한하는 것이 중요합니다. 메모리 내용을 조사하는 두 가지 주요 방법이 있습니다: 메모리 덤프 생성실시간으로 메모리 분석. 두 방법 모두 덤프 프로세스나 분석 중에 중요한 데이터를 놓칠 수 있는 잠재적인 위험이 있습니다.

메모리 덤프 검색 및 분석

탈옥된 기기와 탈옥되지 않은 기기 모두에서 objectionFridump와 같은 도구를 사용하여 앱 프로세스 메모리를 덤프할 수 있습니다. 덤프한 후에는 찾고 있는 정보의 성격에 따라 다양한 도구를 사용하여 이 데이터를 분석해야 합니다.

메모리 덤프에서 문자열을 추출하려면 strings 또는 rabin2 -zz와 같은 명령을 사용할 수 있습니다:

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

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

더 자세한 분석을 위해 특정 데이터 유형이나 패턴을 검색하는 경우 radare2는 광범위한 검색 기능을 제공합니다:

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

런타임 메모리 분석

r2frida는 메모리 덤프가 필요하지 않고 실시간으로 앱의 메모리를 검사하는 강력한 대안을 제공합니다. 이 도구를 사용하면 실행 중인 애플리케이션의 메모리에 직접 검색 명령을 실행할 수 있습니다:

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

암호화가 깨진 상태

열쇠 관리 과정이 부실함

일부 개발자는 민감한 데이터를 로컬 저장소에 저장하고 코드 내에서 하드코딩/예측 가능한 키로 암호화합니다. 이렇게 하면 공격자가 기밀 정보를 추출할 수 있게 될 수 있으므로 이는 피해야 합니다.

안전하지 않거나 사용되지 않는 알고리즘 사용

개발자는 사용되지 않는 알고리즘을 사용하여 인가 확인, 저장 또는 전송 데이터를 수행해서는 안 됩니다. 이러한 알고리즘 중 일부는 다음과 같습니다: RC4, MD4, MD5, SHA1... 예를 들어 암호를 저장하기 위해 해시가 사용된다면, 소금(salt)과 함께 해시 브루트 포스 공격에 강한 것을 사용해야 합니다.

확인

코드 내에서 하드코딩된 암호/비밀을 찾을 수 있는지, 그것들이 예측 가능한지, 그리고 코드가 어떤 종류의 약한 암호화 알고리즘을 사용하는지 확인하는 것이 주요 확인 사항입니다.

감시할 수 있는 몇 가지 암호화 라이브러리objection을 사용하여 자동으로 모니터링할 수 있다는 것이 흥미로운 사실입니다:

ios monitor crypt

iOS 암호화 API 및 라이브러리에 대한 자세한 정보는 여기를 참조하십시오.

로컬 인증

로컬 인증은 특히 원격 엔드포인트에서의 접근을 보호하는 데 암호화 방법을 통해 중요한 역할을 합니다. 여기서 중요한 점은 적절한 구현 없이 로컬 인증 메커니즘은 우회될 수 있다는 것입니다.

애플의 로컬 인증 프레임워크키체인은 개발자가 사용자 인증 대화 상자를 용이하게 만들고 비밀 데이터를 안전하게 처리할 수 있도록 강력한 API를 제공합니다. Secure Enclave는 Touch ID의 지문 ID를 안전하게 보호하며, Face ID는 생체 인식 데이터를 유출하지 않고 얼굴 인식에 의존합니다.

Touch ID/Face ID를 통합하려면 개발자가 두 가지 API 선택지를 갖습니다:

  • LocalAuthentication.framework: 생체 인식 데이터에 액세스하지 않고 고수준 사용자 인증을 위한 것.
  • Security.framework: 생체 인증을 통해 비밀 데이터를 안전하게 보호하는 하위 수준 키체인 서비스 액세스. 다양한 오픈 소스 래퍼가 키체인 액세스를 간단하게 만듭니다.

{% hint style="danger" %} 그러나 LocalAuthentication.frameworkSecurity.framework 모두 인증 프로세스에 대한 데이터 전송 없이 주로 부울 값만 반환하므로 우회가 가능하며 취약점을 노출할 수 있습니다 (David Lindner et al의 Don't touch me that way 참조). {% endhint %}

로컬 인증 구현

사용자에게 인증을 요청하려면 개발자는 LAContext 클래스 내의 evaluatePolicy 메서드를 활용해야 합니다. 다음 중 하나를 선택하면 됩니다:

  • deviceOwnerAuthentication: Touch ID 또는 장치 암호를 요청하며, 둘 다 활성화되지 않은 경우 실패합니다.
  • deviceOwnerAuthenticationWithBiometrics: 오로지 Touch ID를 요청합니다.

**evaluatePolicy**에서 부울 반환 값으로 성공적인 인증을 나타내며, 잠재적인 보안 결함을 강조합니다.

키체인을 사용한 로컬 인증

iOS 앱에서 로컬 인증을 구현하려면 키체인 API를 사용하여 인증 토큰과 같은 비밀 데이터를 안전하게 저장해야 합니다. 이 프로세스를 통해 데이터는 사용자가 자신의 장치 암호 또는 Touch ID와 같은 생체 인식을 사용하여만 액세스할 수 있도록 보장됩니다.

키체인은 SecAccessControl 속성을 사용하여 항목을 설정할 수 있는 기능을 제공하며, 이는 사용자가 Touch ID 또는 장치 암호를 통해 성공적으로 인증할 때까지 항목에 대한 액세스를 제한합니다. 이 기능은 보안을 강화하는 데 중요합니다.

아래는 Swift 및 Objective-C에서 문자열을 키체인에 저장하고 검색하는 방법을 보여주는 코드 예제입니다. 이러한 보안 기능을 활용하여 Touch ID 인증이 필요하도록 액세스 제어를 설정하고, 데이터가 구성된 장치에서만 액세스 가능하도록 보장합니다.

{% tabs %} {% tab title="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 %}

// 1. create AccessControl object that will represent authentication settings
CFErrorRef *err = nil;

SecAccessControlRef sacRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
kSecAccessControlUserPresence,
err);

// 2. define keychain services query. Pay attention that kSecAttrAccessControl is mutually exclusive with kSecAttrAccessible attribute
NSDictionary* query = @{
(_ _bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrLabel: @"com.me.myapp.password",
(__bridge id)kSecAttrAccount: @"OWASP Account",
(__bridge id)kSecValueData: [@"test_strong_password" dataUsingEncoding:NSUTF8StringEncoding],
(__bridge id)kSecAttrAccessControl: (__bridge_transfer id)sacRef
};

// 3. save item
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, nil);

if (status == noErr) {
// successfully saved
} else {
// error while saving
}

{% endtab %} {% endtabs %}

이제 키체인에서 저장된 항목을 요청할 수 있습니다. 키체인 서비스는 사용자에게 인증 대화상자를 표시하고 적절한 지문이 제공되었는지에 따라 데이터 또는 nil을 반환할 것입니다.

// 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" %}Objective-C{% endtab %}

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

탐지

앱에서 프레임워크 사용은 앱 이진 파일의 공유 동적 라이브러리 목록을 분석하여 감지할 수 있습니다. 이를 위해 otool을 사용할 수 있습니다:

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

만약 앱에서 LocalAuthentication.framework가 사용된다면, 출력에는 다음 두 줄이 모두 포함됩니다 (LocalAuthentication.framework이 내부적으로 Security.framework을 사용한다는 것을 기억하세요):

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

만약 Security.framework가 사용된다면, 두 번째 것만 표시됩니다.

로컬 인증 프레임워크 우회

Objection

Objection 생체 인증 우회를 통해, 이 GitHub 페이지에 위치한 기술을 사용하여 LocalAuthentication 메커니즘을 우회할 수 있습니다. 이 접근 방식의 핵심은 Frida를 활용하여 evaluatePolicy 함수를 조작하여 실제 인증 성공 여부와 관계없이 항상 True 결과를 반환하도록 하는 것입니다. 이는 잘못된 생체 인증 프로세스를 우회하는 데 유용합니다.

이 우회를 활성화하려면 다음 명령을 사용합니다:

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

이 명령은 Objection이 일련의 작업을 시작하도록 설정하며, evaluatePolicy 확인을 True로 효과적으로 변경합니다.

Frida

DVIA-v2 애플리케이션에서 evaluatePolicy 사용 예시:

+(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"];
});
}
}

로컬 인증 바이패스를 달성하기 위해 Frida 스크립트를 작성합니다. 이 스크립트는 evaluatePolicy 확인을 대상으로 하여 해당 콜백을 가로채어 success=1을 반환하도록 보장합니다. 콜백의 동작을 변경함으로써 인증 확인이 효과적으로 우회됩니다.

아래 스크립트는 evaluatePolicy 메소드의 결과를 수정하기 위해 주입됩니다. 이는 콜백의 결과를 항상 성공으로 표시하도록 변경합니다.

// from https://securitycafe.ro/2022/09/05/mobile-pentesting-101-bypassing-biometric-authentication/
if(ObjC.available) {
console.log("Injecting...");
var hook = ObjC.classes.LAContext["- evaluatePolicy:localizedReason:reply:"];
Interceptor.attach(hook.implementation, {
onEnter: function(args) {
var block = new ObjC.Block(args[4]);
const callback = block.implementation;
block.implementation = function (error, value)  {

console.log("Changing the result value to true")
const result = callback(1, null);
return result;
};
},
});
} else {
console.log("Objective-C Runtime is not available!");
}

Frida 스크립트를 주입하고 생체 인증을 우회하기 위해 다음 명령을 사용합니다:

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

IPC를 통한 민감한 기능 노출

사용자 지정 URI 핸들러 / 딥링크 / 사용자 지정 스키마

{% content-ref url="ios-custom-uri-handlers-deeplinks-custom-schemes.md" %} ios-custom-uri-handlers-deeplinks-custom-schemes.md {% endcontent-ref %}

{% content-ref url="ios-universal-links.md" %} ios-universal-links.md {% endcontent-ref %}

UIActivity 공유

{% content-ref url="ios-uiactivity-sharing.md" %} ios-uiactivity-sharing.md {% endcontent-ref %}

UIPasteboard

{% content-ref url="ios-uipasteboard.md" %} ios-uipasteboard.md {% endcontent-ref %}

앱 확장

{% content-ref url="ios-app-extensions.md" %} ios-app-extensions.md {% endcontent-ref %}

웹뷰

{% content-ref url="ios-webviews.md" %} ios-webviews.md {% endcontent-ref %}

직렬화 및 인코딩

{% content-ref url="ios-serialisation-and-encoding.md" %} ios-serialisation-and-encoding.md {% endcontent-ref %}

네트워크 통신

통신이 암호화되지 않은 상태로 발생하지 않는지 확인하는 것과 또한 애플리케이션이 서버의 TLS 인증서를 올바르게 검증하는지 확인하는 것이 중요합니다.
이러한 문제를 확인하려면 Burp와 같은 프록시를 사용할 수 있습니다:

{% content-ref url="burp-configuration-for-ios.md" %} burp-configuration-for-ios.md {% endcontent-ref %}

호스트명 확인

TLS 인증서를 확인하는 일반적인 문제 중 하나는 인증서가 신뢰할 수 있는 CA에 의해 서명되었는지 확인하지만 인증서의 호스트명이 액세스 중인 호스트명인지 확인하지 않는 것입니다.
이 문제를 Burp를 사용하여 확인하려면 iPhone에서 Burp CA를 신뢰한 후 Burp를 사용하여 다른 호스트명을 위한 새 인증서를 생성하고 사용할 수 있습니다. 애플리케이션이 여전히 작동하는 경우 취약점이 있을 수 있습니다.

인증서 핀닝

애플리케이션이 SSL Pinning을 올바르게 사용하고 있다면, 애플리케이션은 예상되는 인증서인 경우에만 작동합니다. 애플리케이션을 테스트할 때 이것은 문제가 될 수 있습니다. Burp는 자체 인증서를 제공할 것입니다.
이 보호를 우회하기 위해 탈옥된 장치 내에서 SSL Kill Switch 애플리케이션을 설치하거나 Burp Mobile Assistant를 설치할 수 있습니다.

또한 objectionios sslpinning disable를 사용할 수도 있습니다.

기타

  • **/System/Library**에는 시스템 애플리케이션에서 사용하는 프레임워크가 설치되어 있습니다.
  • 사용자가 App Store에서 설치한 애플리케이션은 /User/Applications 내에 위치합니다.
  • **/User/Library**에는 사용자 레벨 애플리케이션에서 저장된 데이터가 포함되어 있습니다.
  • **/User/Library/Notes/notes.sqlite**에 애플리케이션 내에 저장된 노트를 읽을 수 있습니다.
  • 설치된 애플리케이션의 폴더 내부(/User/Applications/<APP ID>/)에서 몇 가지 흥미로운 파일을 찾을 수 있습니다:
    • iTunesArtwork: 앱에서 사용하는 아이콘
    • iTunesMetadata.plist: 앱 스토어에서 사용되는 앱 정보
    • /Library/*: 환경 설정 및 캐시가 포함됩니다. **/Library/Cache/Snapshots/***에는 백그라운드로 전송하기 전에 애플리케이션에 대한 스냅샷이 포함되어 있습니다.

핫 패칭/강제 업데이트

개발자는 앱을 다시 제출하고 승인될 때까지 기다리지 않고 모든 설치된 앱을 즉시 원격으로 패치할 수 있습니다.
이를 위해 보통 JSPatch와 같은 것이 사용됩니다. 그 외에도 Sirenreact-native-appstore-version-checker와 같은 다른 옵션이 있습니다.
이것은 악의적인 제3자 SDK에 의해 남용될 수 있는 위험한 메커니즘이므로 자동 업데이트에 사용되는 방법(있는 경우)을 확인하고 테스트하는 것이 권장됩니다. 이를 위해 앱의 이전 버전을 다운로드해 볼 수 있습니다.

제3자

3rd party SDK의 중요한 도전 과제 중 하나는 그들의 기능에 대한 세분화된 제어 부재입니다. 개발자는 선택을 해야 합니다: SDK를 통합하고 잠재적인 보안 취약점과 개인 정보 보호 문제를 포함한 모든 기능을 수용하거나 그 혜택을 완전히 포기해야 합니다. 종종, 개발자는 이러한 SDK 내의 취약점을 직접 수정할 수 없습니다. 더욱이, SDK가 커뮤니티 내에서 신뢰를 얻으면 일부는 악성 코드를 포함할 수도 있습니다.

제3자 SDK가 제공하는 서비스에는 사용자 행동 추적, 광고 표시 또는 사용자 경험 향상이 포함될 수 있습니다. 그러나 이는 개발자가 이러한 라이브러리에서 실행되는 코드에 대해 완전히 인식하지 못할 수 있기 때문에 개인 정보 및 보안 위험을 초래할 수 있습니다. 제3자 서비스와 공유되는 정보를 필요한 것으로 제한하고 민감한 데이터가 노출되지 않도록 해야 합니다.

제3자 서비스의 구현은 일반적으로 독립형 라이브러리 또는 완전한 SDK 형태로 제공됩니다. 이러한 서비스와 공유되는 모든 데이터는 익명화되어야 하며 개인 식별 정보(PII)의 노출을 방지해야 합니다.

애플리케이션이 사용하는 라이브러리를 식별하려면 otool 명령을 사용할 수 있습니다. 이 도구는 애플리케이션과 각 공유 라이브러리에 대해 실행되어 추가 라이브러리를 발견할 수 있어야 합니다.

otool -L <application_path>

참고 자료 및 추가 자원


Trickest를 사용하여 세계에서 가장 고급 커뮤니티 도구를 활용한 워크플로우를 쉽게 구축하고 자동화하세요.
오늘 바로 액세스하세요:

{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=ios-pentesting" %}

제로부터 AWS 해킹을 전문가로 배우세요 htARTE (HackTricks AWS Red Team Expert)와 함께!

HackTricks를 지원하는 다른 방법: