百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

IE浏览器缓解技术逆向初探(ie浏览器出现问题怎么办)

mhr18 2024-10-03 22:52 21 浏览 0 评论

作者:dwfault@野火研习社

预估稿费:400RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿

前言

浏览器中的UAF类漏洞触发时,通常用“exploit-friendly”对象占位之前释放的内存空间,通过数组下标索引即可读写此内存区域的对象,控制内存中的对象虚函数调用以执行流程劫持。虚函数调用本质上是通过函数指针进行的,往往形如“call register”或“call [register + offset]”,因此也被称为间接调用。

2014年6月,微软在浏览器产品Internet Explorer中应用堆隔离技术(Isolated Heap),把漏洞多发的对象与“exploit-friendly”对象分配在不同的堆空间;2014年7月微软在IE浏览器中加入延迟释放技术(Delayed Free),其主要流程如下:对象释放时不立即释放堆块,而是加入等待列表中;当内存分配有压力时,从栈中检查是否存在对内存空间的引用,不存在时将堆块释放;针对劫持间接调用的攻击技术,微软在Windows 10上实现了粗粒度的控制流保护技术(Control Flow Guard, CFG)。堆隔离、延迟释放、控制流保护技术使得传统的基于占位的利用技术发生变化,本文就来对这些缓解技术进行逆向初探,分析环境为Windows 10 14393 32bit IE 11,主要分析对象涉及mshtml.dll、msvcrt.dll、ntdll.dll等。

一、堆隔离技术

在mshtml!DllMainStartup函数中,有:

call ds: __imp__GetProcessHeap@0mov ecx, eax
mov _g_hProcessHeap, ecx
call ?RegisterHeap@MemoryProtection@@YGXPAX@Z ;mov _g_hIsolatedHeap, ecx

当mshtml.dll被加载进入浏览器内存时,DllMainStartup函数首先被调用,初始化全局变量_g_hProcessHeap、_g_hIsolatedHeap,全部赋值为GetProcessHeap API的返回值,即首先将隔离堆的句柄初始化为进程默认堆。

mshtml!DllProcessAttach函数中有:

push ebx
push ebx ; dwInitialSizepush ebx ; flOptionscall ds:__imp__HeapCreate@12 ;mov _g_hIsolatedHeap, eax

这段代码创建了新的堆,随后为全局变量_g_hIsolatedHeap重新赋值。从这里开始隔离堆被创建。之后在隔离堆上分配对象时,设置HeapAlloc的参数为_g_hIsolatedHeap。下面代码已经简化:

mov ecx, _g_hIsolatedHeap…call ds:__imp__HeapAlloc@12

按照同样的方法对jscript9.dll中的内存分配进行逆向分析。分析发现,一部分对象分配在系统堆上;大多数对象使用jscript9!HeapAllocator::Alloc分配,该函数实际是对malloc函数的封装,malloc函数位于msvcrt.dll中,跟踪进入该模块,发现这些对象分配在__crtheap中。

查看全局变量_g_hIsolatedHeap的交叉引用,可得到分配在隔离堆的对象类型,其中包括DOM元素(CElement及其派生类)、DOM树节点(CTreeNode)、DOM树节点标记(CTreePos)、结构化标记(CMarkup)等。堆隔离技术使可用于内存占位的对象种类减少,因此占位难度增加,漏洞利用的难度增加。

二、延迟释放技术

mshtml.dll模块下的MemoryProtection命名空间实现了多个延迟释放技术相关的类,因此延迟释放技术也被称为MemoryProtection。CMemoryProtector是命名空间中的核心类,浏览器进程的每个线程维护一个该类的实例,该实例的索引存储在线程局部存储TLS中,总大小为0x1020字节,其结构如下:

class CMemoryProtector+00 void * SBlockDescriptorArray+04 DWORD TotalSize+08 DWORD NumberOfUsed+0c DWORD NumberOfTotal+10 BOOL IsSorted+14 BOOL IsForceMarkAndReclaim+18 DWORD StackHighAddress+1c DWORD StackMarkerAddress+20 DWORD SAddressFilter[512]

其中的SAddressFilter是一个bitmap,用来指示SBlockDescriptorArray中的堆块是否存在引用。SBlockDescriptor是SBlockDescriptorArray中的元素,大小为8字节,用以存储堆块的地址和大小。其结构如下:

struct SBlockDescriptor
+00 void *pAddress
+04 DWORD nSize

SBlockDescriptorArray表示等待列表,对象释放后堆块添加进该列表,以后再释放堆块。等待列表在初次分配时大小为0x8000字节,可以存放0x1000个SBlockDescriptor,NumberOfTotal表示等待列表的总容量,初始值为0x1000;NumberOfUsed表示已存储的堆块个数,初始值为0。当有新的堆块添加到SBlockDescriptorArray时,NumberOfUsed增加;当NumberOfUsed与NumberOfTotal相等时,说明SBlockDescriptorArray已满,此时调用HeapReAlloc重新分配SBlockDescriptorArray,大小翻倍。

图1 延迟释放技术相关函数调用关系

被保护的对象在释放时,不直接调用Windows API HeapFree,而是调用MemoryProtection::HeapFree。该函数检查进程保护策略,包括是否启用延迟释放技术的保护等,若保护未开启,调用Windows API HeapFree直接释放堆块;否则调用CMemoryProtector::ProtectedFree。

CMemoryProtector::ProtectedFree函数调用的核心函数是ReclaimMemory,此外调用有SBlockDescriptorArray::AddBlockDescriptor、SAddressFilter::AddBlock、memset。

ReclaimMemory用于检查等待列表中的堆块。首先检查CMemoryProtector的TotalSize域,该值表示已经添加进等待列表的堆块总大小,当TotalSize小于等于0x186a0(100000)字节时不做处理,否则调用MarkBlock、ReclaimUnmarkedBlocks函数,这两个函数实现了标记清除式垃圾回收算法。算法首先从栈内存中查找堆块的引用,标记存在引用的堆块;然后释放未标记的堆块,为已标记的堆块去除标记以供下次检查。最后调用memset把堆块内容覆写为0。

SBlockDescriptorArray::AddBlockDescriptor用于在等待列表中增加堆块;SAddressFilter::AddBlock用于进行bitmap的更新。

图2展示了延迟释放技术相关代码的整体流程图:

图2 延迟释放技术相关代码流程图

可将延迟释放技术总结如下:对象释放时不立即释放堆块,而是加入等待列表中,同时将堆块内存覆写为0;当列表标示的堆块总大小达到100000字节时,从栈中检查是否存在堆块的引用,若不存在引用则将堆块释放。

延迟释放技术对基于占位的UAF漏洞利用具有有效的遏制作用。但由于IE浏览器采用保守垃圾回收算法,延迟释放机制存在严重缺陷:

保守垃圾回收算法无法区分指针和数据,攻击者可以用Array等数据结构在栈中伪造堆块的指针,使伪造指针所指向的堆块不能被释放;以侧信道攻击配合,攻击者迭代地把指针置零可将MemoryProtection用作Oracle,询问进程内存空间是否可用;用这种方法将动态库模块加载到一个确定的地址,该地址就是本次置零的指针值。如图3所示,研究者利用延迟释放技术将Windows.data.pdff.dll加载到确定的地址:

图3 利用延迟释放技术绕过ASLR技术示意图

三、控制流保护技术

Visual Studio 2015及之后的版本支持CFG,相关编译参数为“/guard:cf”。编译时,编译器扫描所有的间接调用,在调用之前插入语句调用检查函数;且将潜在的间接调用的目的函数地址对齐到0x10字节,即函数地址值可整除16。

链接过程中,模块的PE文件节区结构体IMAGE_LOAD_CONFIG_DIRECTORY末尾添加有GuardFlags和GuardCFFunctionTable、GuardCFFunctionCount等项。其中GuardCFFunctionTable是一个表,反汇编时该函数被识别为___guard_fids_table,表中以RVA形式存放函数指针,用1字节存放SuppressedFlag,每个表项5字节,GuardCFFunctionCount表明该表的容量。

例如,某dll模块定义导出函数normal_function、sensitive_function,假设要求sensitive_function不能被间接调用,可在函数声明时添加“guard(suppress)”关键字。编译完成后,节区包含GuardCFFunctionTable如下:

10001040 _sensitive_function0110001070 _normal_function00100010C0 @__security_check_cookie@400100013F0 __DllMainCRTStartup@1200

对于_sensitive_function,SuppressedFlag值为1,标示为禁止间接调用;其他函数对应的SuppressedFlag值为0,标示为允许间接调用。该模块被加载进入进程内存空间后,进程bitmap添加对应的DWORD值来标示其中函数是否被允许间接调用。

程序执行过程中,exe和dll模块中的代码在执行间接调用前会先调用函数__gurad_check_icall,其中EDI寄存器存放实际调用的函数,调用之前拷贝到ECX寄存器传入__gurad_check_icall函数进行检查:

mov ecx, edicall _guad_check_icallcall edi

另外,有些函数中的间接调用会检查栈顶在调用前后是否发生变化:

mov ebx, esp
mov ecx, edicall _guad_check_icallcall edi
cmp ebx, esp
jz loc_continue:
mov ecx, 4int 29h

静态分析时,函数_guad_check_icall在文件中指向无意义的函数,只包含RETN指令以兼容老版本的操作系统;在被加载进入进程时该函数被动态插装,指向的汇编代码横跨连续的三个函数:

ntdll!LdrpValidateUserCallTarget:mov edx,dword ptr [ntdll!LdrSystemDllInitBlock+0x60]
mov eax,ecx
shr eax,8ntdll!LdrpValidateUserCallTargetBitMapCheck:mov edx,dword ptr [edx+eax*4]
mov eax,ecx
shr eax,3
test cl,0Fh
jne ntdll!LdrpValidateUserCallTargetBitMapRet+0x1
bt edx,eax
jae ntdll!LdrpValidateUserCallTargetBitMapRet+0xantdll!LdrpValidateUserCallTargetBitMapRet:ret
or eax,1
bt edx,eax
jae ntdll!LdrpValidateUserCallTargetBitMapRet+0xa
ret
…
ntdll!LdrpValidateUserCallTargetBitMapRet+0xa
call ntdll!RtlpHandleInvalidUserCallTarget

本段代码中ntdll!LdrSystemDllInitBlock+0x60存放bitmap基地址的指针,该bitmap在大多数情况下是只读的。bitmap中的每个DWORD标示0x00-0xff范围内256个地址的合法性。例如,对于10001070处的_normal_function函数,地址的LSB为0x70,bitmap有对应10001000~100010FF范围的DWORD,该DWORD第14位为1,标示该函数是合法的。

对于每个DWORD,偶数位可以为0或1,标示地址LSB为00、10、20、30、40、50、60、70、80、90、A0、B0、C0、D0、E0、F0处函数的合法性;每个DWORD的奇数位与地址LSB的其他值构成一对多的关系,一般均为0,表示这些地址全部非法。下表举例展示内存地址地址LSB与bitmap比特位的对应关系:

表1 内存地址LSB与bitmap比特位的对应关系示例

浏览器进程中间接调用的黑白名单由加载到进程的不同模块确定;在进程中也可以直接调用SetProcessValidCallTargets来修改黑白名单;进程代码如果调用Window API GetProcAddress,该API也会修改bitmap以标示对应函数为合法。

CFG技术通过bitmap维护各模块中间接调用地址的黑白名单。由于进程bitmap不存在0x0c0c0c00~0x0c0c0cff所对应的DWORD值,CFG技术使堆喷射技术常用的0x0c0c0c0c等地址为非法地址;间接调用的目标为函数内部的情况也不合法,因为该地址不在bitmap标识的白名单之内。

CFG技术主要保护间接调用。它不是为控制流完整性而设计,也不能保证控制流完整性。通过上述分析可知该技术有如下缺陷:

不保护栈上的返回地址和其他函数指针(如SEH)。

不保护call [data]类型的函数调用。

CFG只提供粗粒度的保护。进程中的所有线程、模块查询同一个bitmap,因此共享相同的保护策略。由于兼容性原因,当不同模块的黑白名单冲突时只能将引起冲突的函数加入白名单。进程保护策略不好协调、不易确定,粗粒度的保护使CFG技术难以确保安全。

进程中,如果某dll模块未开启CFG,则该模块内的间接调用均不受保护;如果exe主模块未开启CFG,则保护完全失效。

CFG技术对于不改变程序执行流程的漏洞利用无保护作用。

目前CFG技术最严重的缺陷在于它提供保护的粗粒度。根据前述CFG的流程可以实现一个调试插件以枚举CFG检查为合法的目标函数【3】,发现IE 11浏览器进程中的合法目标函数不乏LoadLibrary、VirtualProtect、ProtectVirtualMemory等敏感API;另一方面存在2700个以上的DWORD的值为0xffffffff,意味着较老的模块中的任意地址均为合法地址;更重要的是,合法目标函数的总数在270000以上,理论上攻击者可以借鉴ROP技术实施代码重用攻击,将多个合法目标函数作为CFG gadget进行组合以绕过该技术的保护。

四、小结

新型缓解技术在UAF漏洞利用过程的各个阶段进行拦截,迫使高级漏洞利用技术也有所演进。

五、参考资料

Abusing Silent mitigations. Abdul-Aziz Hariri, Simon Zuckerbraum, Brian Gorenc

Cross The Wall-Bypass All Modern Mitigations of Microsoft Edge. Henry Li

https://github.com/dwfault/CFGValidEnum

相关推荐

SpringBoot 各种分页查询方式详解(全网最全)

一、分页查询基础概念与原理1.1什么是分页查询分页查询是指将大量数据分割成多个小块(页)进行展示的技术,它是现代Web应用中必不可少的功能。想象一下你去图书馆找书,如果所有书都堆在一张桌子上,你很难...

《战场兄弟》全事件攻略 一般事件合同事件红装及隐藏职业攻略

《战场兄弟》全事件攻略,一般事件合同事件红装及隐藏职业攻略。《战场兄弟》事件奖励,事件条件。《战场兄弟》是OverhypeStudios制作发行的一款由xcom和桌游为灵感来源,以中世纪、低魔奇幻为...

LoadRunner(loadrunner录制不到脚本)

一、核心组件与工作流程LoadRunner性能测试工具-并发测试-正版软件下载-使用教程-价格-官方代理商的架构围绕三大核心组件构建,形成完整测试闭环:VirtualUserGenerator(...

Redis数据类型介绍(redis 数据类型)

介绍Redis支持五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及Zset(sortedset:有序集合)。1、字符串类型概述1.1、数据类型Redis支持...

RMAN备份监控及优化总结(rman备份原理)

今天主要介绍一下如何对RMAN备份监控及优化,这里就不讲rman备份的一些原理了,仅供参考。一、监控RMAN备份1、确定备份源与备份设备的最大速度从磁盘读的速度和磁带写的带度、备份的速度不可能超出这两...

备份软件调用rman接口备份报错RMAN-06820 ORA-17629 ORA-17627

一、报错描述:备份归档报错无法连接主库进行归档,监听问题12541RMAN-06820:WARNING:failedtoarchivecurrentlogatprimarydatab...

增量备份修复物理备库gap(增量备份恢复数据库步骤)

适用场景:主备不同步,主库归档日志已删除且无备份.解决方案:主库增量备份修复dg备库中的gap.具体步骤:1、停止同步>alterdatabaserecovermanagedstand...

一分钟看懂,如何白嫖sql工具(白嫖数据库)

如何白嫖sql工具?1分钟看懂。今天分享一个免费的sql工具,毕竟现在比较火的NavicatDbeaverDatagrip都需要付费才能使用完整功能。幸亏今天有了这款SQLynx,它不仅支持国内外...

「开源资讯」数据管理与可视化分析平台,DataGear 1.6.1 发布

前言数据齿轮(DataGear)是一款数据库管理系统,使用Java语言开发,采用浏览器/服务器架构,以数据管理为核心功能,支持多种数据库。它的数据模型并不是原始的数据库表,而是融合了数据库表及表间关系...

您还在手工打造增删改查代码么,该神器带你脱离苦海

作为Java开发程序,日常开发中,都会使用Spring框架,完成日常的功能开发;在相关业务系统中,难免存在各种增删改查的接口需求开发。通常来说,实现增删改查有如下几个方式:纯手工打造,编写各种Cont...

Linux基础知识(linux基础知识点及答案)

系统目录结构/bin:命令和应用程序。/boot:这里存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件。/dev:dev是Device(设备)的缩写,该目录...

PL/SQL 杂谈(二)(pl/sql developer使用)

承接(一)部分。我们从结构和功能这两个方面展示PL/SQL的关键要素。可以看看PL/SQL的优雅的代码。写出一个好的代码,就和文科生写出一篇优秀的作文一样,那么赏心悦目。1、与SQL的集成PL/S...

电商ERP系统哪个好用?(电商erp哪个好一点)

电商ERP系统哪个好用?做电商的,谁还没被ERP折腾过?有老板说:“我们早就上了ERP,订单、库存、财务全搞定,系统用得飞起。”也有运营吐槽:“系统是上了,可库存老不准,订单漏单错单天天有,财务对账还...

汽车检测线系统实例,看集中控制与PLC分布控制

PLC可编程控制器,上个世纪70年代初,为取代早期继电器控制线路,开始采取存储指令方式,完成顺序控制而设计的。开始仅有逻辑运算、计时、计数等简单功能。随着微处理的发展,PLC可编程能力日益提高,已经能...

苹果五件套成公司年会奖品主角,几大小技巧教你玩转苹果新品

钱江晚报·小时新闻记者张云山随着春节的临近,各家大公司的年会又将陆续上演。上周,各大游戏公司的年会大奖,苹果五件套又成了标配。在上海的游戏公司中,莉莉丝奖品列表拉得相当长,从特等奖到九等奖还包含了特...

取消回复欢迎 发表评论: