0x00 漏洞描述
当Project Zero紧急发布CVE-2019-2215漏洞公告时,我决定将漏洞利用代码复制到本地设备上进行复现分析。我正好有一个存在漏洞的Pixel 2手机。我需要做的就是编译漏洞exp并通过ADB运行exp代码。我下载了最新的Android NDK并编译了PoC:[grant ~/Downloads/android-ndk-r20 >> ./toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android29-clang -o poc ../poc.c
[grant ~/Downloads/android-ndk-r20 >> adb push poc /data/local/tmp/poc
poc: 1 file pushed. 0.8 MB/s (22528 bytes in 0.026s)
我在设备上运行PoC后,发现了提权漏洞。
PoC代码提供了完整的内核读/写原语,最终可以获取root权限。这就提出了一个问题:“root”对于现代Android系统到底意味着什么?要回答这个问题,我们必须首先了解Android如何实施其安全策略的。
Android通过分层实施方法来防御恶意应用程序。以下是主要部分:
·任意访问控制(DAC) -UNIX权限(用户/组ID,R / W / X对象权限
·强制访问控制(MAC) -通过SELinux / SEAndroid强制执行类型(实际上是谁可以与谁以及如何进行对话的白名单)
·Linux功能(CAP) -将功能强大的root用户分成几个权限片(CAP_XYZ)
·SECCOMP-允许过滤/阻止系统调用,有效地限制了内核的攻击面
·Android的中间件 -限定如典型Android应用权限android_manifest.xml如android.permission.INTERNET(通常由执行system_server)
为了获得完整的root shell,我们需要绕过每个执行层(Android中间件除外,因为漏洞利用针对的是binder,它不需要任何中间件检查即可访问)。在现代Android系统上,这可以防范不会出现重大内核漏洞,但是,借助可访问应用程序的内核漏洞,我们可以相对轻松地绕过或禁用这些功能。对于系统上的每个任务,Linux内核都会在task_struct结构中跟踪其状态 。此状态碰巧包括与安全性相关的详细信息,例如所有用户ID,其SELinux上下文,其具有的功能,是否启用SECCOMP等等。如果我们能够针对特定目标task_struct使用我们的R / W原语,我们将能够将这些值更改为我们想要的值。例如,如果我们针对当前进程实现特权提升(EoP)。
0x01 提权到root权限
绕过DAC和CAP
有了指向当前task_struct的指针,我们所需的就是从开始到当前进程凭证的正确偏移量。然后,我们可以读取指针值,并在随后的调用中使用它来戳我们的凭据。
credLinux中的struct具有我们希望更改的所有优点,以升级我们的当前流程。这是源于最新版本Linux内核的源代码。struct cred {
atomic_t usage;
#ifdef CONFIG_DEBUG_CREDENTIALS
atomic_t subscribers; /* number of processes subscribed */
void *put_addr;
unsigned magic;
#define CRED_MAGIC 0x43736564
#define CRED_MAGIC_DEAD 0x44656144
#endif
kuid_t uid; /* real UID of the task */
kgid_t gid; /* real GID of the task */
kuid_t suid; /* saved UID of the task */
kgid_t sgid; /* saved GID of the task */
kuid_t euid; /* effective UID of the task */
kgid_t egid; /* effective GID of the task */
kuid_t fsuid; /* UID for VFS ops */
kgid_t fsgid; /* GID for VFS ops */
unsigned securebits; /* SUID-less security management */
kernel_cap_t cap_inheritable; /* caps our children can inherit */
kernel_cap_t cap_permitted; /* caps we're permitted */
kernel_cap_t cap_effective; /* caps we can actually use */
kernel_cap_t cap_bset; /* capability bounding set */
kernel_cap_t cap_ambient; /* Ambient capability set */
#ifdef CONFIG_KEYS
unsigned char jit_keyring; /* default keyring to attach requested
* keys to */
struct key *session_keyring; /* keyring inherited over fork */
struct key *process_keyring; /* keyring private to this process */
struct key *thread_keyring; /* keyring private to this thread */
struct key *request_key_auth; /* assumed request_key authority */
#endif
#ifdef CONFIG_SECURITY<