记录下firefox下RCE的一些操作
前言
跟着https://doar-e.github.io/blog/2019/06/17/a-journey-into-ionmonkey-root-causing-cve-2019-9810/ 这篇文章复现cve-2019-9810后,因为Firefox不像Chrome那样有WebAssembly好用的操作,所以在获取任意地址读写和addrof原语后还需要一些步骤才能最终执行我们的shellcode
RCE
以下都是已经有了任意地址读写和addrof原语下的操作
泄露xul.dll基址
xul.dll是firefox的最主要的dll,除了内存分配相关的函数不在这个dll里,其它的函数几乎都在这个dll中,泄露的方式为利用addrof原语获得一个非array对象的地址,接着泄露利用任意地址读它的elements,非Array对象的elements会指向xul.dll中的某个地方,接着靠向前一页一页的寻找(为了避免写死特定的偏移),利用PE文件格式特有的’MZ’和’PE’来定位:
1 | function FindModuleBase(Mem,ModuleAddr){ |
寻找virtualProtect函数地址
有了xul.dll地址,我们继续寻找我们需要的API的地址,也就是virtualProtect,原理就是解析xul.dll,找到IAT在依次遍历:
1 | function FindImportDescriptor(Mem,ModuleBase,DllName2Find){ |
jit gadget
firefox会将被jit函数中的常量放到一个可读可执行的段中,这意味着我们可以将gadget用常量的形式来构建(避免在dll中寻找,节约时间):
1 | function get_rwx_helper() { |
Magic常量是为了在内存中更好的定位到这些gadget
转换用到的util.js:
1 | var buf = new ArrayBuffer(0x10); |
劫持jit指针
找到我们的gadget后,只需将jit指针劫持到这些gadget即可:
1 | var jitfuncAddr = mem.Addrof(get_rwx_helper); |
可以看到在最后调用jit函数的时候是传入了参数的,这是为了方便,我们直接把shellcode的地址和virtualProtect函数的地址直接作为参数传入,这样我们劫持程序执行流到我们布置好的gadget的时候,r8寄存器会指向这些参数(对应gadget中的mov r/a/b/cx, [r8 + offset]
)
gadget的效果就是将shellcode所在的段的权限用virtualProtect改为可执行,最后在跳转过去执行真正的shellcode
参考链接
https://doar-e.github.io/blog/2019/06/17/a-journey-into-ionmonkey-root-causing-cve-2019-9810/
https://www.sentinelone.com/labs/firefox-jit-use-after-frees-exploiting-cve-2020-26950/