我们可以控制参数2指向待测试的内存,让其拷贝到我们分配的一段内存空间,即参数1,如果成功说明待测试内存可读。否则说明不可读。当然这里
面有一个风险,待测试的目标内存如果刚好是很长的一个串结尾。而参数1不够长则会出现问题。
同样,我们也可以是GlobalLock函数来达到一样的目的。这个函数也是可以bypass CFG保护的,而且只需要一个参数更方便控制。
LPVOID WINAPI GlobalLock(
_In_ HGLOBAL hMem
);
还有就是我们如果可以在Edge中分配出512G的内存空间,那么这个新分配出的空间将靠近在“影子栈”区域,这会方便我们搜索时尽量减少预测的数
据长度。
但不够幸运的是,在15016版本的时候Edge已经把这些函数都加入到CFG防护的列表当中了。也就是说这一类的函数都不能进行读内存的利用了。同样
的原因NtQueryVirtualMemory/VirtualQueryEx 也都很早的被加入了CFG的sensitive API列表里面,这似乎也可以说明不存在更上一层的调用路
径回去调用这2个API去获得内存块的具体信息。所以脚本层面的利用已经非常困难的了。
另外,就是可以考虑可以修改RFG的异常时的跳转问题。在RFG比较失败的情况下会跳向对应_guard_ss_verify_failure:
00007ff7`58e526e2 644c8b1c24 mov r11,qword ptr fs:[rsp]
00007ff7`58e526e7 4c3b1c24 cmp r11,qword ptr [rsp]
00007ff7`58e526eb 0f85ef350100 jne MicrosoftEdgeCP!_guard_ss_verify_failure (00007ff7`58e65ce0)
00007ff7`58e526f1 c3 ret
//跳向这里
MicrosoftEdgeCP!_guard_ss_verify_failure:
00007ffb`c52b0580 4d33db xor r11,r11
00007ffb`c52b0583 ff25e7f33800 jmp qword ptr [chakra!_guard_ss_verify_failure_fptr (00007ffb`c563f970)]
00007ffb`c52b0589 cc int 3
//我们查看这里的信息
0:011> x chakra!_guard_ss_verify_failure_fptr
00007ffa`0495f970 chakra!_guard_ss_verify_failure_fptr = <no type information>
//替换
0:011> dqs chakra!_guard_ss_verify_failure_fptr
00007ffa`0495f970 00007ffa`238fe8c0 ntdll!LdrpHandleInvalidReturnAddress//替换这里的指针
00007ffa`0495f978 00007ffa`238fe910 ntdll!RtlGuardVerifyReachableStackPointer
00007ffa`0495f980 00000000`00000000
00007ffa`0495f988 00007ffa`04323a60 chakra!jscriptinfo_IID_Lookup+0x2a60
00007ffa`0495f990 00007ffa`04323a70 chakra!jscriptinfo_IID_Lookup+0x2a70
chakra!_guard_ss_verify_failure_fptr 所在内存区域的属性
Usage: Image
Base Address: 00007ffa`04904000
End Address: 00007ffa`04a9e000
Region Size: 00000000`0019a000 ( 1.602 MB)
State: 00001000 MEM_COMMIT
Protect: 00000002 PAGE_READONLY
Type: 01000000 MEM_IMAGE
Allocation Base: 00007ffa`04320000
Allocation Protect: 00000080 PAGE_EXECUTE_WRITECOPY
如果有办法修改 chakra!_guard_ss_verify_failure_fptr的内存属性为可写,将其LdrpHandleInvalidReturnAddress指针替换为我们的一个控制的
函数,这样也可以绕过RFG。
总之,在详细分析过后,就是RFG的整体防护情况来看是具有很高的强度防御来应对ROP/控制流劫持等攻击。但其实我们都知道,CFG的弱点是可以通过直接的修改函数栈
上的return地址来绕开,避免寻找直接的方法绕过。RFG的开启,CFG才形成了真正意义上的完整性防护。单纯的内存破坏层面的利用在DEP+ASLR+CFG+RFG的配合下必
将变得越来越难突破。
[0x04].致谢
最后,非常感谢我的同事Sun Bing在RFG研究方面给予的非常重要的提示和帮助,一同调试研究了非常多的技术细节,才得以使得本篇文章得到了整理和汇总。
注意:
微软已经从漏洞悬赏计划里面撤掉了RFG防护,仅作为一个Research Project。说明RFG设计本身存在一个很大的问题。接下来会发生什么谁也不知道了。我们已经知道几个点上可能被
绕过的情况,但不确定是否是微软撤掉RFG的根本原因。
正文完