译者说明:由于该研究是在一年前完成的,所以截止本文发布时,华为不仅解决了本文提到的漏洞(CVE-2021-22337),而且现在已经将他们的许多设备从 Android 升级到了鸿蒙操作系统。因此,不要期望在你最新的华为设备上找到完全相同的漏洞利用细节。

在审核某个供应商的文件系统节点访问权限时,我们发现了一个 SELinux 权限错误配置漏洞,起初看起来有些无害,因为所有不受信任的应用程序都可以访问基于 sysfs 的触屏事件统计日志文件。然而,在对这些日志的格式进行逆向工程并应用一些简单的机器学习技巧之后,我们设法从不受信任的应用程序上下文中偷偷地提取了精确的触屏事件模式。为此,我们创建了概念验证,发现通过此漏洞,恶意应用程序可以通过在后台持续侦听触屏事件并从观察到的事件推断用户输入来窃取敏感的用户数据。调查表明,可以提取的信息量足以在很大程度上重构输入密码的键盘(pin-pad)甚至模拟屏幕键盘上的用户输入。

 华为Android设备上的触摸屏事件可以被记录

华为智能手机的触屏是通过 tpkit 模块处理的,该模块可以在已发布的内核源代码中的drivers/devkit/tpkit/ 中找到。为不同的触屏供应商实现了多个底层驱动程序,但:

Nova 5T(YAL)、Mate 30 Pro(LIO)和P40 Pro (ELS)上的高级驱动程序都使用了 hostprocessing/huawei_thp* 文件中定义的驱动程序.

这个huawei_thp驱动会在/sys/devices/platform/huawei_thp/路径下创建一些虚拟控制文件。以下是包含详细权限和 SELinux 部分标签文件列表:

现在让我们看一下 roi_data_internal 节点,它由 root 用户拥有,但对其他用户来说仍然是可读的。正如我们所看到的,huawei_thp内核模块的大多数其他节点对“other”角色没有文件权限,所以不管SELinux是什么,自由访问控制(传统的Unix权限系统)都会阻止访问。但是roi_data_internal是一个例外。我们有必要弄清它来自哪里。sysfs 文件权限以编程方式分配。下面是drivers/devkit/tpkit/hostprocessing/huawei_thp_attr.c文件的相关部分:

正如我们在上面看到的,roi_data_internal 设备属性是用 S_IRUGO 定义的。这是漏洞利用的代码行。

然而,如果不考虑强制访问控制,这幅图就是不完整的。由于华为智能手机使用 SELinux,因此检查 SELinux 策略数据库中的 sysfs_touchscreen 文件标签很重要,该数据库位于 /vendor/etc/selinux/precompiled_sepolicy。下载数据库并查询允许对 sysfs_touchscreen 目标上下文执行读取操作的每个规则会产生超过一千条输出行。在结果中,我们可以找到允许untrusted_app上下文规则。

这意味着任何应用程序都可以在没有任何权限的情况下访问roi_data_internal节点。该访问适用于未经修改的、开箱即用的电话,无需任何类型的本地权限提升。虽然访问控制绕过漏洞本身很明显,但我们必须弄清楚从该节点提取触屏使用信息的精确度,以确定此漏洞对安全性的影响。

 roi_data_internal 矩阵的含义

该节点的内容由huawei_thp_core.c文件中的thp_roi_data_debug_show函数提供,其中ROI_DATA_LENGTH == 49。

thp_get_core_data()函数调用返回g_thp_core指针,在这个指针中,触屏控制器以中断驱动的方式更新底层数据。由于该节点对触屏内核驱动程序使用的原始数据进行操作,因此只需在紧密循环中监视 roi_data_internal 并寻找变化,就可以实现非常高的计时精度。

下面是节点在简单触摸屏幕后的输出示例,屏幕以原始文本格式和图形形式表示。可以看出,最大值在矩阵([3,3])的中心,这是设计的,因为该点应该是估计的接触点的中心。

指尖触摸的 roi_data_internal 输出示例

为了验证这个7 × 7矩阵确实代表触屏区域的周边区域(而矩阵的中心代表触屏的中心,但事实并非如此),我们制作了一个超级复杂的验证工具:一个由铝箔覆盖的不对称 L 形钢回形针,铝箔很重要,因为现代触屏使用电容传感,主要是检测由导电触摸事件引起的表面电子亏损。

L形回形针实验

由于 roi_data_internal 的图形明显类似于回形针的 L 形,我们可以通过捕获触摸位置的大约 3 cm周边区域得出结论,返回的矩阵与物理现实有紧密的联系。

 roi_data_internal 数据与tapping位置的关系

人们可能会假设,如果每个触摸事件都具有完全相同的物理特性,那么就不可能从触屏数据中推断出位置。事实上,情况并非如此。当 ROI 矩阵超出屏幕的物理尺寸时,触摸屏驱动程序将用常量零填充缺失的数据点。这使得仅根据ROI数据来区分触屏特定边缘的触摸与其他位置的触摸非常方便。

当然,人类的触摸不会像理论上的高精度机器人手指那样具有恒定的特性,它具有均匀的表面、固定的触摸角度和力度,以及无论位置如何,每次触摸之间的时间间隔都是恒定的。与单独的内核驱动程序的“用零填充缺失数据”行为相比,有两个主要因素可以促进更高精度的推断。

首先是时机。由于各种原因,在许多场景中,触摸之间的时间间隔将与实际的按键序列相关联。我们注意到学术界在这个研究领域的现有技术。例如,在“沙盒JavaScript中的实际按键计时攻击”中,Lipp等人认为,即使在浏览器内的沙盒JavaScript运行时限制更大的环境中,按键计时差异也可以用来恢复实际类型化的短语。在一个更接近我们的场景中,在“对PIN输入设备的计时攻击”中,Kune等人使用按键间隔计时(在他们的例子中,这是从音频获得的,不如我们在这里所依赖的时间戳精确)来更好地推断PIN pad上的按键命中情况。最近,在“键盘记录侧通道”中,Monaco基于许多数据集构建了键间时间延迟的语言模型。有趣的是,他们发现单词越长(就字符数而言),恢复的机会就越高,因为延迟模式变得非常独特。

第二个因素是手指运动和定位的差异。我们在生活中可以观察到,大多数人都是将自己的手机拿在手里,同时用拇指来访问触摸屏。这意味着手通常处于相对固定的位置,而只有拇指在屏幕上移动。拇指触摸屏幕的部分在屏幕上有一个不对称的印记,更重要的是,当我们旋转、弯曲或伸展我们的拇指以到达屏幕的特定区域时,这个印记也会发生变化。这个简单的观察提供了一种直觉,即所记录的矩阵数据值的差异实际上与所触摸的位置相关。

不同位置的不同印记

我们做了一个非常简单的实验来还原了这个过程,在屏幕中间留下一个触摸事件的指纹,在右下角留下一个,同时右手拿着手机,用 4 个手指支撑,用拇指触碰。正如我们在可视化中看到的,有一个明显的区别!出于隐私原因,屏幕上的指纹是模糊的,但为了更好的可见性而突出显示。用于从数据集生成可视化的数学变换将在下一节中进行更详细的描述。

 触摸事件目标:PIN 和按键

在尝试创建基于统计或神经网络的模型之前,我们首先必须为我们的推理实验选择目标。首先,我们研究了数字输入的默认虚拟键盘和PIN pad。

屏幕上的键盘

Android上的虚拟屏幕键盘基本上是唯一的文本输入法,所以它不可避免地会在系统范围内使用。屏幕键盘的按键布局是固定的,这就有可能发生类似的攻击。

SwiftKey输入法,华为智能手机的默认屏幕键盘

很明显,由于间隔和可能性的数量,仅从指纹数据对键盘进行精确推断比对PIN pad更具挑战性。虽然我们对此的研究结果是比较初步的,但它们仍显示了该方法在基本层面上的可行性。

PIN Pad

华为智能手机中使用数字输入法的例子有很多,例如解锁屏幕或电话拨号器。正如下面的屏幕截图所示,密码键盘使用常见的 3×4 网格。可能是出于人体工程学和可用性的原因,这些网格是均匀分布的,几乎跨越了整个手机的宽度,并占据了高度的很大一部分。

华为智能手机PIN pad示例

在所有测试设备(即YAL、LIO和ELS)上,1,4,7,3,6,9和0的数字都位于距离屏幕边缘1.5厘米的位置。在前几节中,我们根据经验估计了LIO上ROI矩阵的边长为3厘米。正如我们上面所提到的,当ROI矩阵超出屏幕的物理尺寸时,触屏驱动程序将用常量零填充缺失的数据点。这使得仅基于ROI数据就可以非常方便地检测边缘周围的触摸。

最近智能手机的大屏幕尺寸确保了手指触摸的远距离差异,例如右手拿着电话时的数字 1 与 9(或类似的左手拿着电话时的数字 3 和 7)。这些距离需要大量的拇指移动、旋转和拉伸,这将导致手指印记变形。

因此,从经验上来说,我们可以合理地假设,这些差异会让触摸值变得可区分。接下来,我们将ROI数据分两个阶段进行数字识别分析。首先,我们使用统计分析。其次,我们使用神经网络。

 统计分析

我们有两个主要目标:首先证明多次触摸某个数字会导致相似的 ROI 数据,其次验证不同数字的 ROI 数据收到不同的均值。

屏幕上的键盘

对于 Swiftkey 键盘,我们首先尝试对边缘的几个键进行统计分析:左侧的 A 和 Q 以及右侧的 0 和 P。数据标准化与密码键盘数据相同(见下文)。下图显示了数字平均值与全局平均值的差异。

SwiftKey 上选定键的全局平均值和 ROI 数据的差异

ROI 差异非常明显,这意味着,通过进一步建模,触屏键应该通过其相应的 ROI 数据即可复原。

PIN Pad

对于PIN Pad,首先我们收集了一个小数据集(每个数字100个触摸事件),这些ROI数据由实际触摸的数字标记。然后将原始样本(ROI矩阵)按其能量(平方和的平方根)归一化,并按标签平均,以得到每个数字的平均基线。这些基线进一步平均,从而形成一个统一的全局基线。

为了验证第一个目标,通过从归一化数据集中随机选择不同数量的样本并绘制与全局平均值的差异来证明每位数的 ROI 数据的收敛性。下图显示了列中的数字,向下有更多的样本用于平均计算。它清楚地表明数据收敛到平均值。当前的方法是比较经验的,但通过这种方式在视觉上更容易掌握联系。这告诉我们触摸数字会提供可重复的 ROI 数据。

归一化样本和基线与样本大小的差异

要验证第二个目标,就需要用数字标出平均值,并将它们相互比较。下个图显示了数字和全局基线的差异。很容易看出,数字之间的差异是非常明显的。即使通过肉眼,也很容易看出 1-4-7、2-5-8、3-6-9 和 0 这四个数字组具有非常容易区分的模式。当然,数据处理可以更好地区分它们。为了使精度更加明显,我们采用了神经网络处理。

平均ROI数据和按数字分组的全局基线的差异

 神经网络模型

为了提供进一步的证明,我们还对非常简单的神经网络模型进行了实验,结果很好,因此我们认为通过收集更多的数据和应用更先进的数据清理方法,神经网络可以很好地实现 ROI 之间的映射函数数据和实际数字。

与统计分析一样,整个神经网络计算都是在 tensorflow 中实现的。

我们的神经网络模型在输入层接收ROI数据的49个像素点,最后有10个输出节点。在两个全连接层之间只使用了 512 个节点并使用 ReLU 激活函数。我们的 1000 个元素数据集在 ML 领域被认为很小,并且小的输入案例往往会过度拟合,因此我们还包含了“dropout”层来抵消这种影响。对于我们模型的损失函数,我们选择优化交叉熵,因为我们期望在输出层上进行一次性编码,即对于输入 ROI,只有 10 个输出神经元中的一个应该被触发。在训练期间,五分之一的输入数据被保留用于验证目的。以下是部分tensorflow 代码:

令人惊讶的是,这样一个简单的模型已经表现得相当好:我们已经实现了大约 90% 的准确率,而无需微调网络结构或输入数据。另请注意,当前模型仅依赖于 ROI 数据,并未考虑时间信息。具有记忆功能的循环神经网络也能够计算触摸间延迟,进一步提高准确度。

神经网络训练历史

最后,构建一个预测器来对 PIN pad触摸进行分类并在手机上实时播放会产生预期的积极结果:

神经网络分类结果

总之,我们的经验表明,ROI数据可以明确地映射到PIN pad数字上。

 实验结果的实践应用

诚然,这些结果是实验性的。但经过大量的改进,很快就能被用于实践。从 roi_data_internal 获取的侧信道信息取决于用户特征:ROI 数据会随着手的大小、惯用手和手机使用习惯而变化。变化也可以基于地理或基于语言的特征。尽管开发适用于每个受害者的通用算法似乎很困难,但并非绝对有必要有效利用此漏洞。一个关键原因是攻击者(恶意应用程序)还可以对其决策算法应用高精度的设备端训练。这是因为应用程序可以很容易地设计为在使用应用程序本身时从用户那里绘制触摸事件,通过持续监控 ROI 数据,同时通过合法输入字段了解真实情况,应用程序可以有效地“学习”其用户的手势。此外,这种行为很难被任何监控检测到,因为读取 roi_data_internal 不会生成任何内核日志消息。

可用于改进精度的另一个参数是时间,我们还没有进一步试验用于推断键盘按键的时间信息,但除了指尖的印记之外,roi_data_internal 还提供了非常精确的时间信息。由于键盘的几何形状,当手指移动更远的距离以到达更远的按键时,计时信息也带有信息值,这会转化为按键之间的延迟增加。

参考及来源:

https://labs.taszk.io/articles/post/ouchscreen/