如何利用自定义URL Scheme远程突破Mac

一、前言

在最近几篇文章中,我们讨论了macOS中存在的一些漏洞或者缺陷,使得恶意代码能够执行各种恶意操作,比如绕过SIP、允许安装内核扩展、转储keychain数据以及其他操作。然而,这些漏洞利用技术都需要恶意代码已经(通过某种方式)获取目标系统上的初始代码执行权限。换句话说,这些技术都属于本地攻击范畴,通常会在攻击活动的第二阶段所使用。

今天我们将讨论恶意软件一直在使用的一种远程攻击技术,这种技术可以用来获取已打全补丁macOS系统的初始访问权限,属于第一阶段攻击技术。如果与之前介绍的各种第二阶段攻击技术结合起来,就可以通过优雅又有害的方法来攻击macOS系统。

注意:

虽然这种远程攻击方法仍需要一些用户交互操作,然而的确能够搞定具有安全意识的macOS目标用户。换句话说,大家需要小心这种攻击方法。

8月30日,来自DarkMatter LLC的Taha Karim在HITB会议上做了“The Trails of WINDSHIFT APT”主题演讲,他总结道:

WINDSHIFT APT是最近发现的一个隐蔽的网络间谍组织,专门攻击为政府工作的人员。这个攻击组织拥有专门的高级渔叉式钓鱼基础设施,可以为钓鱼邮件以及SMS攻击提供服务,在侦察阶段不间断地跟踪目标人员,也可以通过假冒全球及本地的服务商平台,在凭据收集阶段欺骗目标用户。

WINDSHIFT APT组织之所以与其他APT组织有所不同,原因在于他们会根据间谍和监控目的,只关注特定的个体,并且由于他们惯用的攻击手段,我们很难对其追踪溯源。WINDSHIFT APT组织很少使用恶意软件攻击目标,Dark Matter LLC发现了该攻击组织发起的几次攻击活动,并且分析了相关的macOS恶意软件。最后,WINDSHIFT APT有独特的macOS感染技巧,滥用macOS的原生功能自动将恶意软件投递到目标。

演讲中比较有趣的一个内容就是攻击者会滥用这种攻击方法,成功远程感染中东某政府的Mac系统。

注意:

本文的并不是简单地重述Taha的演讲内容,而是在此基础上进一步深入分析这款恶意软件的感染机制:

1、讨论macOS上的一些相关细节;

2、提供某些PoC代码片段;

3、讨论这种远程攻击方式的缓解措施。

 

二、Document Handler及URL Scheme

简而言之,WINDSHIFT APT组织滥用了自定义的URL Scheme来远程感染macOS目标。尽管该过程中需要用户交互,但成本很小,并且一定程度上可以受攻击者“控制”。此外,这种攻击方法已经有成功的攻击案例(攻击中东的政府目标),表明需要用户交互并不是一种无法突破的“屏障”。

在macOS上,应用程序可以“声明”自己能够支持(或者“处理”)各种文档类型以及/或者自定义的URL Scheme。想象一下,某个应用可能会说“如果有用户尝试打开foo文档类型或者bar这种URL Scheme,我可以处理这种场景”。大家肯定在macOS上碰到过这种场景。比如,当我们双击一个.pdf文档,Preview.app就会被启动来处理该文档。或者在浏览器中,我们点击了指向Mac App Store中的一个链接,App Store.app就会启动来处理这个请求。

不幸的是,Apple对Document Handler(文档处理程序)以及自定义URL Scheme的实现(或者“注册”)方法决定了攻击者可以滥用这种功能。

从操作系统的角度来看,尽管文档处理程序以及URL Scheme略有不同,但本质上是一样(因此实现方法也非常相似)。

首先我们来快速看一下Document Handler,前阶段我刚研究过这方面内容,写过一篇介绍性文章。

在之前的文章中,我分析了Mac File Opener这款广告软件(adware),该软件滥用了自定义的文档处理程序来实现隐蔽的持久化目标。简而言之,这款恶意软件“声明”自己能够支持超过200种类型的文件,一旦用户打开其中一种文件,恶意软件就会被操作系统自动启动来处理(理论上是显示)文档。非常耐心的持久化方法。

注意:如果已经有一个程序注册了一种文件类型(比如.pdf.html等),(据我所知)这种绑定关系无法被篡改。

当然这里第一个问题是,Mac File Opener广告软件(或者其他应用)如何“声明”自己能够支持哪些文件(因此在用户访问此类文件时会被调用)。第二个问题是,操作系统如何处理并注册这种信息?我推荐大家阅读这篇文章,其中详细回答了这两个问题,但是这里我们也会简单地做一下总结。

那么应用程序如何告诉操作系统自己能够处理哪类文件?答案就在于程序的Info.plist文件总。前面提到过,Mac File Opener支持超过200种文件类型,我们可以导出它的Info.plist文件:

在“原始的”plist中,这个信息存放在一个数组中(CFBundleDocumentTypes键)。根据Apple的说法:

CFBundleDocumentTypes(iOS及OS X上的数组)包含一个字典数组,将一个或多个文档类型与具体应用关联起来。每个字典都为类型定义(type-definition)字典,包含用来定义文档的具体键(key)。

举个例子,.7z(7Zip)文件类型的Mac File Opener详细信息如下所示,请注意其中的CFBundleTypeExtensions这个key,对应的值为该广告软件声明的可以处理的文件扩展名:

$ cat "Mac File Opener.app/Contents/Info.plist"
<?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">
<dict>
        <key>BuildMachineOSBuild</key>
        <string>14F27</string>
        <key>CFBundleDevelopmentRegion</key>
        <string>en</string>
        <key>CFBundleDocumentTypes</key>
        <array>
                <dict>
                        <key>CFBundleTypeExtensions</key>
                        <array>
                                <string>7z</string>
                        </array>
                        <key>CFBundleTypeName</key>
                        <string>DocumentType</string>
                        <key>CFBundleTypeOSTypes</key>
                        <array>
                                <string>????</string>
                        </array>
                        <key>CFBundleTypeRole</key>
                        <string>Viewer</string>
                        <key>LSHandlerRank</key>
                        <string>Alternate</string>
                        <key>NSDocumentClass</key>
                        <string>Document</string>
                </dict>

为了回答第二个问题,我们需要确定macOS如何处理这些文件的“注册”请求。在“Click File, App Opens”这篇文章中提到,这是一个自动化过程,一旦应用保存到本地磁盘上就会执行该操作。简单总结下,大致步骤如下:

1、应用(或者恶意软件)下载或者保存到本地文件系统中;

2、该过程会导致一个XPC消息发送到launch services daemon(lsd);

3、lsd守护进程解析该应用,将应用的“document handlers”信息提取并保存到一个数据库中。

# fs_usage -w -f filesystem | grep Info.plist
open  /Users/user/Desktop/Mac File Opener.app/Contents/Info.plist  lsd.16457
fstat64  F=4  lsd.16457
read  F=4  B=0x18a97  lsd.16457

# /usr/libexec/lsd
...

(lldb) po $rsi
<LSDatabase 0x7fe66183e600>{ path = '/var/folders/np/85lyz_4545d5lz8wvy04xvlm0000gn/0//com.apple.LaunchServices-134501.csstore' }

我们可以利用lsregister(具体路径为/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/)来转储lsd的数据库。当使用-dump标志调用时,lsregister可以显示指定了“document handler”的所有应用,lsd会自动注册这些“document handler”。比如,我们可以看到其中包含Mac File Opener及其注册的文档(文件类型,比如.7z等):

$ lsregister -dump
...
Container mount state: mounted
bundle id: 2592
Mach-O UUIDs: 88225C07-0FDC-3875-A3B4-C5328E509B9E, 20A99135-975D-3A7B-A8DD-B7DF2CE428D0
path: /Users/user/Downloads/Mac File Opener.app
name: Mac File Opener
identifier: com.pcvark.Mac-File-Opener (0x80025f61)
executable: Contents/MacOS/Mac File Opener
--------------------------------------------------------
claim id: 31508
  name: DocumentType
  rank: Alternate
  roles: Viewer
  flags: doc-type
  bindings: .7z
...

一旦应用(或者广告软件)自动注册了document handler,那么当用户尝试打开匹配的文档时,应用或广告软件就会被自动调用。

这个过程由launch services framework负责,更具体一些,是_LSBundleCopyOrCheckNode方法(以及_LSBundleCopyOrCheckNode_block_invoke)负责匹配过程(查找与文档类型匹配的已注册的应用)然后执行已注册的应用:

(lldb) b ___LSBundleCopyOrCheckNode_block_invoke
...
(lldb) x/gx $rdx
0x700000115c48: 0x00007fd3b4a9c520
(lldb) po 0x00007fd3b4a9c520
<FSNode 0x7fd3b4a9c520> { flags = 0x00000020, path = '/Users/user/Desktop/Mac File Opener.app' }

总结一下:

1、应用程序可以“声明”能够处理的各种文档或者文件类型;

2、一旦应用落盘,操作系统就会自动注册这些“document handler”;

3、文件打开时,系统会查询“launch services”数据库,确定该执行哪个应用。

以上就是“document handlers”的大概内容,接下来讨论一下自定义URL Scheme handler。从操作系统的角度来看,这种URL Scheme handler通常只是适用于url的document handler。

这对自定义URL Scheme handler来说意味着两点:

1、一旦(“声明”支持这些handler的)应用落盘,macOS会自动注册自定义的URL Scheme handler;

2、当自定义URL Scheme被调用时,就会触发(已自动注册的)handler应用。

由于这些操作都可以被网页触发,因此我们很容易就能猜到会出现什么后果。

之前我曾在Box 2017上讨论过自定义URL Scheme话题(“Oversight: Exposing Spies on macos”)。

然而当时并没有涉及到恶意软件或者恶意利用之类的内容。

由于我还没有接触WINDSHIFT恶意软件样本,我之前自己写了PoC示例,演示了攻击者如何滥用自定义URL Scheme handler来远程感染Mac主机(该过程涉及一些用户交互操作)。

我们先创建Xcode项目,使用Cocoa App模板:

应用本身的逻辑并不关键,但我们必须编辑应用的Info.plist文件,以便“声明”我们将支持一个自定义的URL Scheme。在Xcode中,我们添加了一个URL types数组,指定了Scheme的名称(windshift://)以及一个URL标识符:

观察原始的plist,我们可以看到这些信息对应其中的一些key,比如CFBundleURLTypes CFBundleURLSchemes以及CFBundleURLName

<key>CFBundleURLTypes</key>
<array>
  <dict>
        <key>CFBundleURLSchemes</key>
        <array>
                <string>windshift</string>
        </array>
        <key>CFBundleURLName</key>
        <string>com.foo.bar.WindShift</string>
        </dict>
</array>

一旦该应用编译(或下载)完毕,lsd就会解析应用的bundle数据(特别是Info.plist文件),检测是否存在自定义URL Scheme handler,如果有则进行注册。注意这些操作都会自动完成。

为了确认这一点,我们可以转储“launch services”数据库(通过lsregister -dump命令)。其中的确可以看到我们的PoC应用(WindShift.app),以及我们自定义的URL Scheme(CFBundleURLSchemes: (windshift)):

--------------------------------------------------------------------------------
BundleClass: kLSBundleClassApplication
Container mount state: mounted
bundle  id:            168204
 Mach-O UUIDs:  E2E77A08-F458-36C1-B7BD-99F409B4DEAC
 Device Familie
  Counterpart ID
  sequenceNum:   168204
 FamilyID:      0
  PurchaserID:   0
  DownloaderID:  0
  installType:   0
  appContainer:  #
  dataContainer: #
  path:          /Users/patrick/Projects/WindShift/DerivedData/WindShift/Build/Products/Debug/WindShift.app
 name:          WindShift
  ....
  executable:    Contents/MacOS/WindShift
 ....

  CFBundleURLTypes =     (
                {
            CFBundleURLName = "com.foo.bar.WindShift";
            CFBundleURLSchemes =             (
                windshift
            );
        }
    );
}


claim id:          386204
   name:          com.foo.bar.WindShift
    rank:          Default
    roles:         Viewer  
   flags:         url-type  
   icon:          
   bindings:      windshift:

如果我们现在使用浏览器(这里使用的是Safari),“浏览”我们的自定义URL Scheme(windshift://),我们可以确认自定义的URL Scheme已被自动注册:

如果我们点击“Allow”(这是个危险操作,后面我们会详细介绍),那么应用就会被启动:

 

三、远程利用

如果我们“不怀好意”,可能就会看到这种技术的利用方向。现在我们将介绍如何滥用自定义URL Scheme,远程定位(并在理想情况下感染)Mac用户的一种方法。

首先,目标必须浏览我们可控的一个网站。WINDSHIFT APT组织(成功使用了)钓鱼邮件这种途径。

一旦目标浏览我们的恶意网站,就会触发下载操作,下载包含恶意应用的一个归档(.zip)文件。如果Mac用户正在使用Safari,那么归档文件就会自动被解压,这是因为Apple认为自动打开“安全的”文件是一个比较明智的选择。这一点非常重要,这意味着恶意应用(而不是一个单纯的压缩zip文件)现在会存在于用户的文件系统上,这样就会自动触发自定义URL Scheme handler的注册过程,这一点的确应该好好谢谢Apple。

现在恶意应用的自定义URL Scheme已成功注册(在目标系统中),恶意网站中的代码就可以加载或者“浏览至”自定义的url地址,使用JavaScript可以轻松完成这个任务:

window.location.replace('windshift://');

macOS在后台会查找处理这个自定义URL Scheme的handler,最终就会找到我们的恶意应用(刚刚下载到目标系统中)。一旦查找完毕,操作系统将尝试启动恶意应用来处理所请求的URL!

(对Mac用户来说)幸运的是,较新版的Safari中会弹出一个警告信息:

然而引号中的字符其实可以被攻击者所控制,因为这些字符就是应用的名称。因此,我们很容易就可以让弹出的警告窗口看起来比较普通、无害甚至有趣:

注意:

通常情况下应用无法使用类似.txt或者.com之类的扩展名。

然而,由于应用名可以包含unicode字符,因此我们可以利用homograph这种攻击技巧。

这样我们就可以让恶意应用的名称变成类似Attachment.TXT之类的字符串(其中“X”其实是卡里安(Carian)字母X)。

虽然最新版的Safari会在启动已注册自定义URL Scheme的应用前提示用户,但老版本的Safari(比如默认安装在EI Capitan上的Safari)就不会执行这种操作。相反,这些版本的Safari并不会弹出任何警告信息,会盲目地启动(恶意)应用。

抛开Safari的版本,我们还有另一个障碍要绕过:文件隔离(File Quarantine)。

如果应用文件下载自互联网,那么当用户执行该应用时,文件隔离机制就会弹出警告窗口:

好消息是有些Mac用户会点击Cancel按钮,但仍有些Mac用户还是会点击Allow按钮(Taha已经确认了这一点,他在演讲中提到WINDSHIFT APT组织已经成功利用了这种攻击向量)。

此外,我们还可以控制应用的名称,因此可能会让更多用户点击Allow按钮,比如,我们可以添加个emoji表情试一下?

注意:

这里大家可能想知道为何Gatekeeper没有发挥作用?

在默认配置下,Gatekeeper只允许经过签名的应用。WINDSHIFT APT组织所使用的恶意软件都带有签名(现在大多数恶意软件都会使用这种方法),因此并没有轮到Gatekeeper上场。

在本文总结之前,我绘制如下一张图,介绍了这种“自定义URL Scheme handler”攻击的详细流程:

 

四、总结

我们并不是每天都能看到针对Mac用户的APT组织,更何况这类恶意软件使用了相当新颖的感染方式。然而,我们再也不能天真地认为Mac用户能够免受这类威胁的侵扰,WINDSHIFT APT组织已经给我们好好上了一课。

在本文中我们讨论了macOS的一些功能,比如document handler以及自定义URL Scheme handler,演示了这些功能如何被恶意软件主动利用。幸运的是,这类攻击方法(特别是在新版本的macOS上)需要一些用户交互操作。然而,这两种功能已经在实际攻击活动中被成功利用,因此如果大家正在寻找感染Mac用户的可靠方法,可以考虑使用这些技术。

如果你是Mac用户,并且比较注重安全,那么可以考虑使用Google Chrome浏览器:

如果你习惯使用Safari,至少需要关闭下载文件的自动解压功能,因为只有在应用被解压时才会触发(恶意)自定义URL Scheme handler的注册操作。

如果想关闭这个功能,请打开Safari的首选项,在General选项卡,勾掉Open "safe" files after downloading这个复选框:

此外,我们还可以将Gatekeeper设置成“仅允许来自Mac App Store的应用”(然后根据需求小心允许第三方应用),这一点并不会带来什么坏处。

(完)