首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >[ Windows 10 x64中的RFG(Return Flow Guard)技术研究 ]7

[ Windows 10 x64中的RFG(Return Flow Guard)技术研究 ]7

作者头像
franket
发布2022-06-29 16:51:31
发布2022-06-29 16:51:31
4070
举报
文章被收录于专栏:技术杂记技术杂记
代码语言:javascript
复制
 我们可以看到,整个“影子栈”区域是一个以0x00007A00~00000000开始的reserved区域。想来这里面应该有一些trick影藏在其中,
因为NtQueryVirtualMemory/VirtualQueryEx通过解析vadroot来获得当前进程的内存分配情况,如果vad里面存储的“影子栈”就是一个512G的
整体区域,那么在内核中针对每一个线程为什么能区分出这些“影子栈”的边界。显然上述API获得的信息是不全面的。通过调试我们来探测出这个整
体影子栈的内存布局情况。我们可以在nt!PspAllocateProcess中获得刚刚创建的Edge进程,然后在MmSwapThreadControlStack获得相应的“影子栈”地址
和真实线程栈地址,测试出的信息如下:

	shadowstackbase:00007adcbab00000 - threadstack:0000009547800000 = userfs:00007a4773300000
	shadowstackbase:00007adcbac00000 - threadstack:0000009547900000 = userfs:00007a4773300000
	shadowstackbase:00007adcbad00000 - threadstack:0000009547a00000 = userfs:00007a4773300000
	shadowstackbase:00007adcbae00000 - threadstack:0000009547b00000 = userfs:00007a4773300000
	shadowstackbase:00007adcbaf00000 - threadstack:0000009547c00000 = userfs:00007a4773300000
	shadowstackbase:00007adcbb000000 - threadstack:0000009547d00000 = userfs:00007a4773300000
	shadowstackbase:00007adcbb100000 - threadstack:0000009547e00000 = userfs:00007a4773300000
	shadowstackbase:00007adcbb200000 - threadstack:0000009547f00000 = userfs:00007a4773300000
	shadowstackbase:00007adcbb300000 - threadstack:0000009548000000 = userfs:00007a4773300000
	shadowstackbase:00007adcbb400000 - threadstack:0000009548100000 = userfs:00007a4773300000 
	shadowstackbase:00007adcbb500000 - threadstack:0000009548200000 = userfs:00007a4773300000
	shadowstackbase:00007adcbb600000 - threadstack:0000009548300000 = userfs:00007a4773300000

	shadowstackbase:00007adcbb700000 - threadstack:0000009548400000 = userfs:00007a4773300000
	shadowstackbase:00007adcbb800000 - threadstack:0000009548500000 = userfs:00007a4773300000
	shadowstackbase:00007adcbb900000 - threadstack:0000009548600000 = userfs:00007a4773300000
	shadowstackbase:00007adcbba00000 - threadstack:0000009548700000 = userfs:00007a4773300000
	shadowstackbase:00007adcbbb00000 - threadstack:0000009548800000 = userfs:00007a4773300000
	shadowstackbase:00007adcbbc00000 - threadstack:0000009548900000 = userfs:00007a4773300000

    由上面的信息可以得知,在15002开始以后的版本“影子栈”的布局变成了以100000为边界的内存区域。但哪部分才是可写的内容,可以通过当前
线程的userfs + rsp的值来计算出。

[0x03] 突破RFG的可能性

    首先我们回顾一下,RFG防护的主要目的是防止恶意的对用户栈的篡改。通过分配一段512G空间的区域将各个线程的“影子栈”放入其中。
在一个被保护函数结束前进行栈数据的比对。RFG的强度在于,

1) 用户态无法控制fs段寄存器指向,这是由内核态来决定的
2) 攻击者很难猜测出“影子栈”所在的内存位置

对于情况1,用户态我们很难做到修改,对于情况2我谈谈曾经考虑过的一些攻击方式。

    在应对14986的版本时,考虑的优化后的搜索“影子栈”是有可能的情况。继而我们需要寻找利用的任意地址读写功能。在Edge中首先需要考虑如何任意
内存地址读写,通常的内存层面暴力搜索是存在的问题的,因为“影子栈”之间插入的reversed的内存,读指令会引发程序异常。这里有个利用技巧就是在该
版本中lstrcpyA函数是未被CFG的,我们可以利用该函数来测试一个指定的内存区域是否可读、写。而且该函数仅需要2个参数,利用漏洞较容易控制其利用,
在读到一个reversed空间内存时该函数不会触发异常。

LPTSTR WINAPI lstrcpy(
  _Out_ LPTSTR lpString1,
  _In_  LPTSTR lpString2
);

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档