今日分享 – [ Windows 10 x64中的RFG(Return Flow Guard)技术研究 ]8

 我们可以控制参数2指向待测试的内存,让其拷贝到我们分配的一段内存空间,即参数1,如果成功说明待测试内存可读。否则说明不可读。当然这里
面有一个风险,待测试的目标内存如果刚好是很长的一个串结尾。而参数1不够长则会出现问题。

   同样,我们也可以是GlobalLock函数来达到一样的目的。这个函数也是可以bypass CFG保护的,而且只需要一个参数更方便控制。

LPVOID WINAPI GlobalLock(
  _In_ HGLOBAL hMem
);


   还有就是我们如果可以在Edge中分配出512G的内存空间,那么这个新分配出的空间将靠近在“影子栈”区域,这会方便我们搜索时尽量减少预测的数
据长度。

  但不够幸运的是,在15016版本的时候Edge已经把这些函数都加入到CFG防护的列表当中了。也就是说这一类的函数都不能进行读内存的利用了。同样
的原因NtQueryVirtualMemory/VirtualQueryEx 也都很早的被加入了CFG的sensitive API列表里面,这似乎也可以说明不存在更上一层的调用路
径回去调用这2API去获得内存块的具体信息。所以脚本层面的利用已经非常困难的了。


   另外,就是可以考虑可以修改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的根本原因。

正文完