导语:在上一篇文章​中,我详细介绍了macOS的用户交互安全屏障的过程,今天我就接着介绍这种防护措施是如何失效的?

上一篇文章中,我详细介绍了macOS的用户交互安全屏障的过程,今天我就接着介绍这种防护措施是如何失效的?

macOS的用户交互安全是如何被绕过的?

在经过一番探索之后,我发现了一个叫做"Mouse Keys"的功能特性。"Mouse Keys"是macOS的一项文档记录功能,正如它的介绍那样,该功能允许用户把键盘当作鼠标用。启用"Mouse Keys"后,如果要将鼠标往右移动,你只需按下O或键盘上的数字6即可。接着按下I或键盘上的数字5,就会确认单击动作完成了。

12.png

这就引发了一些列安全问题,比如:

1.可以通过程序化方式启用"Mouse Keys"吗?

2.可以通过组合这些键盘事件,生成可信的鼠标点击过程吗?

对于这两个问题,我的答案是肯定的!

首先,我可以使用AppleScript以程序化方式打开“系统偏好设置”应用程序的窗口,该窗口具有用于启用"Mouse Keys"的复选框,然后使用CoreGraphics发送鼠标检查命令 "synthetic"以启用模拟过程。

mouseKeys.gif

由于Apple仅保护某些UI组件(比如安全警报)不受"synthetic"命令的影响,因此攻击过程很容易完成。

//click via mouse key
void clickAllow(float X, float Y)
{
   //move mouse
   CGEventPost(kCGHIDEventTap, CGEventCreateMouseEvent(nil, kCGEventMouseMoved,
               CGPointMake(X, Y), kCGMouseButtonLeft));

   //apple script
   NSAppleScript* script = [[NSAppleScript alloc] initWithSource:
                            @"tell application \"System Events\" to key code 87\n"];

   //exec
   [script executeAndReturnError:nil];
}

要生成程序化的鼠标单击事件,在启用"Mouse Keys"后,首先要移动鼠标,然后通过AppleScript发送所需的键盘事件。比如下面这个例子,我就合成了87键盘事件。

# ./sniffMK

event: key down
keycode: 0x57/87/5

event: key up
keycode: 0x57/87/5

event: left mouse down
(x: 146.207031, y: 49.777344)

event: left mouse up
(x: 146.207031, y: 49.777344)

当启用"Mouse Keys"时,当键盘代码87(代表键盘上的数字5)被描述成单击事件时,系统将其转换为一次真正的鼠标单击过程。这可以通过使用我的开源鼠标和键盘嗅探器SniffMK可以观察到整个过程,过程如下所示。

具体步骤如下:首先操作系统会将键盘代码转换为鼠标事件,然后再转换为一次真正的鼠标单击过程,即使受保护的UI组件也会接受并处理这样的事件!一般来说,当攻击目标是操作系统本身时,这种受保护的组件就会默认信任这些模拟事件。

那么我们可以用这种模拟事件做些什么呢?比如进行转储并使用他们的私钥和未加密的密码来泄露用户的钥匙串。

具体视频,请点此

目前,我已经向苹果公司报告了这个漏洞,他们也在High Sierra补充更新中将其修补为CVE-2017-7150:

18.png

但是,类似的模拟用户行为的恶意事件仍然很多!

首先,我注意到各种与隐私相关的警报会盲目接受程序化的鼠标操作事件,即使是在完全修补的macOS 10.13上,情况也如此。例如,在最新版本的macOS上,macOS会在代码试图访问以下信息时显示警告:

1.系统的地理位置信息;

2.用户的联系信息;

3.用户的日历事件;

……

由于这些警报会对以上所说的那些模拟事件轻而易举的绕过,因此恶意软件可以通过程序化方式简单的解除这些警报。

//given some point {x, y}
// generate synthetic event...
CGPostMouseEvent(point, true, 1, true);
CGPostMouseEvent(point, true, 1, false);

privacy.png

以上是一个攻击演示,演示了攻击者如何通过模拟事件解除操作系统的访问警报,从而来确定用户的地理位置。

20.gif

也许你可能会提出这样的疑问“如果恶意软件可以如此轻而易举的绕过这些防护措施,那为什么系统还会发出警报呢,干脆让它们直接跳过不得了?”对于这个问题,我也不无法回答你。

事实证明,目前macOS甚至存在着比以上所述的模拟事件操作是更糟糕的问题,比如允许无用户操作权限的恶意软件或攻击者与受保护的UI组件交互的问题,例如High Sierra的“用户辅助内核加载”界面。虽然,它们也在macOS 10.6中被修复,但现实的情况却不是想得那么简单。于是我试图测试苹果发布的CVE-2017-7150补丁,并有意错误的剪切和粘贴了一些代码。结果,漏洞发生了!

上面我讲过,可以通过CoreGraphics框架发送模拟的鼠标事件。对于这样的鼠标点击事件,通常是由两个事件合成的:鼠标按下事件+鼠标松开事件。

//given some point {x, y}
// generate synthetic event...

//final param: true => mouse down
CGPostMouseEvent(point, true, 1, true);

//final param: false => mouse up
CGPostMouseEvent(point, true, 1, false);

但是,如果复制并粘贴代码段的CGPostMouseEvent(point, true, 1, true);时,忘记将最终参数从true更改为false(以指示鼠标松开),那这将生成两个鼠标按下事件。

理论上这种低级的失误应该被忽略才是,但事实证明并非如此!同理,即通过SniffMK,我们也可以观察到系统生成两个鼠标松开事件。

# ./sniffMK

event: left mouse down
event source pid 951
event state 0 (synthetic)
(x: 1100.000000, y: 511.000000)

event: left mouse up
event source pid 0
event state 0 (synthetic)
(x: 1100.000000, y: 511.000000)

而第二次鼠标按下事件被转换为鼠标松开的事件,则是由操作系统完成的,这意味着事件的源进程ID为0(即 OS/system)。如前所述,一般来说,UI(包括安全提示和其他受保护的组件)允许来自系统的这些合成事件(pid 0)。例如,将典型的鼠标向下/向上合成事件发送到“用户辅助内核加载”界面的“允许”按钮,它将被忽略,并显示以下错误。

$ log stream | grep mouse
Dropping mouse down event because sender's PID (899) isn't 0 or self (828)

但如果pid为0,会是什么情况呢?如上所述,“允许”按钮就会发生!

24.png

假如你是攻击者,现在就可以以程序化方式批准内核扩展的加载,即使是在完全修补的High Sierra系统上也是如此。

在OSX/macOS上,只有得到root的用户,才能加载这样的扩展。那么这种袭击会给我们带来的启发是什么?或者更确切的说,“用户辅助内核加载”的防护作用是什么?

在最新版本的macOS上,加载kext时不仅需要是root权限,还需要对kext进行签名,而从macOS中获得内核代码签名证书几乎是不可能的。

但是,具有root权限的攻击者可不会坐以待毙,他们可以利用root权限做什么呢?看看这篇文章,你就知道了,比如:

1.加载一个已经公开的易受攻击的第三方驱动程序,前提是该程序已经有了合法签名;

2.利用已知漏洞在内核的上下文中获取任意代码执行权限;

苹果公司对此攻击的回应就是利用“用户辅助内核加载”,它可以通过要求用户必须手动批准任何kext的加载,来增加额外的安全防护。遗憾的是,我刚刚通过CVE-2017-7150展示了这个安全机制的漏洞,而且非常容易。那到头来,这个“用户辅助内核加载”只能增加第三方开发者的开发成本和难度。

模拟鼠标的攻击事件能被发现吗?

利用模拟鼠标的攻击事件发起攻击的一个明显缺点是,它们的攻击过程是可见的。想象一下,你正坐在办公桌前的Mac上工作,这时突然出现一个警报时,而此时你并未移动鼠标,可是鼠标似乎会自动移动到警报那里并进行点击,此时你会清楚的知道你被黑了!

不过,攻击者倒是想到了一个简单的解决方案,就是调暗屏幕。

25.png

当屏幕亮度变暗到0.0时,此时UI对用户来说,和关闭状态没有什么两样。此时不管界面发生什么活动,用户都是看不见的。

因此,作为攻击者,执行此类攻击的办法之一,就是要确保你在适当的时候调暗屏幕。例如:

1.在用户不使用电脑一段时间后,再进行此操作;(注意:使用CGEventSourceSecondsSinceLastEventType API)

2.显示器即将进入休眠状态的时候;

在第二种情况下,代码是可以检测显示器会在何时进入休眠状态,通过kIOMessageCanDevicePowerOff通知既可以获得此信息。此时,攻击者可以快速将屏幕亮度调为0.0,然后在显示器休眠之前执行任何模拟攻击。

26.png

总结

通过利用鼠标点击过程中的合成事件,恶意软件或攻击者可以绕过无数的macOS内置安全机制。

27.png

虽然苹果公司已经知道这个攻击方法的存在,并试图保护与操作系统的安全和隐私相关的UI组件,但很明显,防护还是失败了。即使在完全修补的High Sierra系统上,也很容易发生模拟攻击事件,从而绕过这些UI组件的安全设置。

就像macOS Mojave(10.14)一样,对Mac用户来说,好消息是,这些对合成事件做手脚的模拟事件目前很可能会被操作系统全部忽略,除非用户明确的给应用程序提供用户交互的权限。虽然从安全的角度来看,这可能会破坏目前许多合法的应用程序的使用,但这显然是正确的安全防护方法!

源链接

Hacking more

...