欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

通过IndexedDB条件竞争实现Chrome沙箱逃逸(下)

来源:本站整理 作者:佚名 时间:2019-08-13 TAG: 我要投稿


 
接着上文,我们开始讲这个漏洞的利用。
 
Exploitation
一旦我们通过竞争条件触发了UAF(free-after-free)场景,则可以绕过时间的限制,我们可以完美控制使用已释放对象的时间。
在下面部分中,我们要分享漏洞利用的目标是在Android上运行的64位版本的Chrome。 但只需稍加修改,该漏洞即可在Linux或Windows上利用。
构造信息泄漏
首先我们要做的事是把bug转为信息泄漏漏洞,为此我们需要将Chrome的基地址泄漏到渲染器中。 有几种方法可以完成,但我们决定使用IndexedDB mojo接口及其回调来实现。
我们没有找到直接泄漏Chrome基地址的方法,因此我们需要触发bug两次。
泄漏堆指针
我们通过分别使用两次连接(版本0,2),实现两次Open调用从而触发bug,然后调用Close和AbortTransactionsForDatabase方法来触发竞争条件并最终释放IndexedDBDatabase对象。
然后,我们可以调用CreateObjectStore方法,使用相应的对象库创建的元数据的IDB keypath字符串,重新分配释放的IndexedDBDatabase对象。
我们可以完全控制字符串keypath的内容,并用于构造假的IndexedDBDatabase对象,同时将pending_requests_.buffer和pending_requests_.capacity字段设置为0。
如果现在我们调用Open方法,获取指向已释放的IndexedDBDatabase对象的mojo接口指针,即可对伪对象做一些操作。 调用Open只会向pending_requests_ queue(队列)添加一个新的OpenRequest。 因为我们将buffer(缓冲区)和capacity(容量)设置为0,所以将重新分配缓冲区,并将伪对象的pending_requests_.buffer设置为新的堆指针,而且该指针实际上存储在keypath字符串中。
通过调用Commit(数据库事务)方法,可以将对象存储库的元数据泄漏到渲染器中。因此,我们可以轻松泄漏出指向渲染器的指针。
在这之前,我们继续在已释放的IndexedDBDatabase上调用Open方法,这可以为pending_requests_队列添加更多的OpenRequest指针,从而增加底层的后备缓冲区。 通过控制对Open的调用次数,我们还可以控制分配的后备缓冲区的大小。
最后我们可以通过调用Commit方法,从返回的元数据中提取出堆指针,最终泄漏出指向后备缓冲区的指针。
使用对象替换堆指针内存
一旦我们获取指向pending_requests_的后备缓冲区的指针,我们将在释放的IndexedDBDatabase对象上继续调用几次Open方法,之后将再次重新分配后备缓冲区并且增长。 这将导致我们泄漏的堆指针被释放。
为了防止其他代码占用已泄漏指针指向的内存,需要再次调用CreateObjectStore方法,以便使用新对象库的keypath重新分配释放的后备缓冲区。 通过这点我们可以控制何时再次释放内存。
现在,我们已将一个堆指针泄漏到渲染器中,指向对象存储库的元数据中已分配的keypath字符串。
泄漏Vtable指针
为了泄漏vtable指针,我们需要再次触发漏洞。 首先我们要再次使用正常的IndexedDBDatabase对象,重新分配之前释放的IndexedDBDatabase对象,以便在第二次触发时不引发程序崩溃。 因为调用AbortTransactionsForDatabase方法会遍历database_map_并接触所有引用的对象。
在第二次触发错误之后,我们要再次使用CreateObjectStore方法,通过新制作的假对象重新分配已释放的IndexedDBDatabase对象。
在精心设计的假对象中,需要将pending_requests_.buffer设置为先前泄漏的堆指针(指向先前创建的对象存储库的元数据中的keypath字符串),并pending_requests_.capacity设置为1。
现在,我们在已释放的IndexedDBDatabase上调用Open方法一次,这将会把新的OpenRequest附加到伪对象的pending_requests_队列中。 由于容量设置为1,因此代码会尝试重新分配后备缓冲区,并释放pending_requests_.buffer指向的内存,并将其替换为更大的缓冲区。
这将会释放泄漏的堆指针指向的内存,然后我们可以通过更改数据库名称重复调用Open方法,以便重新分配有效的IndexedDBDatabase对象。
这里我们会用到一个小trick,我们把创建的数据库名称设置为一个非常大的0x4000字节的字符串。 稍后,我们将泄漏其中一个创建的IndexedDBDatabase对象的内容。该过程不仅会泄漏出vtable指针,还会泄漏指向数据库的名称字符串的指针,然后它将返回我们一个指向巨大的slcak space(松弛空间)的堆指针,我们可以利用它来存储ROP链和shellcode。
但现在我们只读取先前创建的对象存储库的元数据,该对象存储将接收其中一个IndexedDBDatabase对象的内容。
然后,我们可以使用来自已泄漏的IndexedDBDatabase对象的vtable指针以及指向对象的名称字符串的指针,从而泄漏出一个指向大内存的指针,以便我们存储ROP链和shellcode。
 
远程代码执行
只要我们泄漏出指向松弛内存和Chrome基地址的指针,我们就可以在松弛内存中放置一个伪OpenRequest对象,然后使用它的虚拟化Perform方法来获取远程代码执行并启用ROP链。
然后,我们将精心构造的伪对象放入已释放的IndexedDBDatabase的内存中,并将processing_pending_requests_设置为0,将pending_requests_.buffer设置为我们放置伪OpenRequest指针的内存。 因为processing_pending_requests 为0,对已释放的IndexedDBDatabase调用Open方法,将会对存储在`pending_requests`中的请求调用Perform方法,从而启用我们的伪对象并且获取代码执行。
ROP链
通过调用IndexedDBDatabase::ProcessRequestQueue方法,我们可以控制程序的counter(计数)。
void IndexedDBDatabase::ProcessRequestQueue() {
  // Don't run re-entrantly to avoid exploding call stacks for requests that
  // complete synchronously. The loop below will process requests until one is
  // blocked.
  if (processing_pending_requests_)
    return;
  DCHECK(!active_request_);

[1] [2] [3]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载