xlab · 2016/04/07 10:11

Author:[email protected]

0x00 简介


内存的读、写、执行属性是系统安全最重要的机制之一。通常,如果要改写内存中的数据,必须先确保这块内存具有可写属性,如果要执行一块内存中的代码,必须先确保这块内存具有可执行属性,否则就会引发异常。然而,Windows系统的异常处理流程中存在一些小小的特例,借助这些特例,就可以知其不可写而写,知其不可执行而执行。

0x01 直接改写只读内存


我在CanSecWest 2014的演讲《ROPs are for the 99%》中介绍了一种有趣的IE浏览器漏洞利用技术:通过修改JavaScript对象中的某些标志,从而关闭安全模式,让IE可以加载类似WScript.Shell这样的危险对象,从而执行任意代码而完全无需考虑DEP。

不过,修改SafeMode标志并非是让IE可以加载危险对象的唯一方法。

IE浏览器的某些界面实际上是用HTML实现的,这些HTML通常存储在ieframe.dll的资源中,例如:打印预览是res://ieframe.dll/preview.dlg,整理收藏夹是res://ieframe.dll/orgfav.dlg,页面属性则是res://ieframe.dll/docppg.ppg

IE浏览器会为这些HTML创建独立的渲染实例,以及独立的JavaScript引擎实例。而为这些HTML创建的JavaScript引擎实例中,SafeMode本身就是关闭的。

所以,只需将JavaScript代码插入到ieframe.dll的资源中,然后触发IE的相应功能,被插入的代码就会被当作IE自身的功能代码在SafeMode关闭的JavaScript实例下执行。

不过,PE的资源节是只读的,如果试图用某个能对任意地址进行写入的漏洞直接改写ieframe.dll的资源,会触发写访问违例:

#!bash
eax=00000041 ebx=1e2e31b0 ecx=00000000 edx=00000083 esi=1e2e31b0 edi=68b77fe5
eip=69c6585f esp=0363ac00 ebp=0363ac84 iopl=0         nv up ei pl nz na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010207
jscript9!Js::JavascriptOperators::OP_SetElementI+0x117:
69c6585f 88040f          mov     byte ptr [edi+ecx],al      ds:002b:68b77fe5=76
0:008> !exchain
0363b0f0: jscript9!DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+1570 (69b421d1)
0363b648: jscript9!DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+1570 (69b421d1)
0363bab8: jscript9!DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+1570 (69b421d1)
0363bb78: jscript9!DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+28c0 (69c71564)
0363bbc0: jscript9!DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+2898 (69c7150f)
0363bc44: jscript9!DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+276a (69d0dedd)
0363c588: MSHTML!_except_handler4+0 (66495fa4)CRT scope  0, filter: MSHTML! ... Omitted... (6652bbe8) func:   MSHTML!... Omitted... (6652bbf1)
0363c62c: user32!_except_handler4+0 (7569a61e)CRT scope  0, func:   user32!UserCallWinProcCheckWow+123 (75664456)
0363c68c: user32!_except_handler4+0 (7569a61e)CRT scope  0, filter: user32!DispatchMessageWorker+15e (756659b7)func:   user32!DispatchMessageWorker+171 (756659ca)
0363f9a8: ntdll!_except_handler4+0 (776a71f5)CRT scope  0, filter: ntdll!__RtlUserThreadStart+2e (776a74d0)func:   ntdll!__RtlUserThreadStart+63 (776a90eb)
0363f9c8: ntdll!FinalExceptionHandler+0 (776f7428)
复制代码

在上面的异常处理链中,mshtml.dll中的异常处理函数最终会调用kernel32!RaiseFailFastException()。如果g_fFailFastHandlerDisabled标志是false,就会终止当前进程:

#!cpp
int __thiscall RaiseFailFastExceptionFilter(int this) {signed int **v1; // [email protected]CONTEXT *v2; // [email protected]signed int v3; // [email protected]UINT v4; // [email protected]HANDLE v5; // [email protected]v1 = (signed int **)this;if ( !g_fFailFastHandlerDisabled ){v2 = *(CONTEXT **)(this + 4);g_fFailFastHandlerDisabled = 1;RaiseFailFastException(*(PEXCEPTION_RECORD *)this, v2, 2u);v3 = 1653;if ( *v1 )v3 = **v1;v4 = v3;v5 = GetCurrentProcess();TerminateProcess(v5, v4);}return 0;
}
复制代码

但是,如果g_fFailFastHandlerDisabled标志为true,异常处理链就会执行到kernel32!UnhandledExceptionFilter(),并最终执行kernel32!CheckForReadOnlyResourceFilter():

#!cpp
int __stdcall CheckForReadOnlyResourceFilter(int a1) {int result; // [email protected]if ( BasepAllowResourceConversion )result = CheckForReadOnlyResource(a1, 0);elseresult = 0;return result;
}
复制代码

如果BasepAllowResourceConversion 也为true,CheckForReadOnlyResource()函数就会将试图写入的那个内存分页的属性设为可写,然后正常返回。

也就是说,如果先将g_fFailFastHandlerDisabled和BasepAllowResourceConversion这两个标志改写为true,之后就可以直接修改ieframe.dll的资源,而不必担心其只读属性的问题,操作系统会处理好一切。

另外还有个小问题。如果像上面所说的那样触发了一次CheckForReadOnlyResource()中的修改内存属性的操作,内存属性的RegionSize也会变成一个内存分页的大小,通常是0x1000。而IE在以ieframe.dll中的HTML资源创建渲染实例前,mshtml!GetResource()函数会检查资源所在内存的RegionSize属性,如果该属性小于资源的大小,就会返回失败。然而,只需将要改写的资源从头到尾全部改写一遍, RegionSize就会相应变大,从而绕过这个检查。

这样,利用Windows写访问异常对PE文件资源节开的绿灯,就可以写出非常奇妙的漏洞利用代码。

0x02 直接执行不可执行内存


我在VARA 2009的演讲《漏洞挖掘中的时间维度》中介绍了一种较为少见的模块地址释放后重用漏洞。比如一个程序中线程A调用了模块X的函数,模块X又调用了模块Y的函数。模块Y的函数由于某种原因,耗时比较长才能返回。在它返回前,如能让线程B将模块X释放,那么模块Y的函数返回时,返回地址将是无效的。当时发现在Opera浏览器中可以利用Flash模块触发这种漏洞,一款国产下载工具也有类似问题。

另外还有不少其它类型的漏洞,最终表现也和上述问题一样,可以执行某个固定的指针,但无法控制该指针的值。在无DEP环境下,这些漏洞并不难利用,只要喷射代码到会被执行的地址即可。而在DEP环境下,这些漏洞通常都被认为是不可能利用的。

但如果在预期会被执行到的地址喷射下面这样的数据:

#!cpp
typedef struct _THUNK3 {UCHAR MovEdx;       // 0xba         mov edx, imm32LONG EdxImmediate; UCHAR MovEcx;       // 0xb9         mov ecx, imm32LONG EcxImmediate; // <- put your Stack Pivot hereUSHORT JmpEcx;      // 0xe1ff       jmp ecx
} Thunk3;
复制代码

即使在DEP环境下,尽管堆喷射的内存区域确定无疑不可执行,但你会惊奇地发现系统似乎还是执行了这些指令,跳到ecx所设定的地址去了。只要把ecx设为合适的值,就可以跳往任何地址,继而执行ROP链。

这是因为Windows系统为了兼容某些老版本程序,实现了一套叫ATL thunk emulation的机制。系统内核在处理执行访问异常时,会检查异常地址处的代码是否符合ATL thunk特征。对符合ATL thunk特征的代码,内核会用KiEmulateAtlThunk()函数去模拟执行它们。

ATL thunk emulation机制会检查要跳往的地址是否位于PE文件中,在支持CFG的系统上还会确认要跳往的地址能否通过CFG检查。同时,在Vista之后的Windows默认 DEP policy 下,ATL thunk emulation机制仅对没有设置 IMAGE_DLLCHARACTERISTICS_NX_COMPAT的程序生效。如果程序编译时指定了/NXCOMPAT参数,就不再兼容ATL thunk emulation了。不过还是有很多程序支持ATL thunk emulation,例如很多第三方应用程序,以及32 位的 iexplore.exe。所以,类似Hacking Team泄露邮件中的CVE-2015-2425,如能用某种堆喷成功抢占内存,也可借此技巧实现漏洞利用。

这样,利用系统异常处理流程中的ATL thunk emulation能直接执行不可执行内存的特性,就可以让一些通常认为无法利用的漏洞起死回生。

(本文大部分内容完成于2014年10月,涉及的模块地址、符号信息等基于Windows Technical Preview 6.4.9841 x64 with Internet Explorer 11。)

0x03 参考


  1. ROPs are for the 99%, CanSecWest 2014
  2. Bypassing Browser Memory Protections
  3. (CVE-2015-2425) “Gifts” From Hacking Team Continue, IE Zero-Day Added to Mix
  4. 《漏洞挖掘中的时间维度》,VARA 2009

异常中的异常——借助系统异常处理特例实现匪夷所思的漏洞利用相关推荐

  1. Java异常中受检异常非受检异常与RuntimeException异常关系

    Error 和 Exception: 所有异常都是 Throwable 的子类,分为 Error 和 Exception.Error 是 Java 运行时系统的内部错误和资 源耗尽错误,例如 Stac ...

  2. java中抛出异常快捷键_idea中处理异常的快捷键

    建议68:从System.Exception或其他常见的基本异常中派生异常 微软建议:从System.Exception或其他常见基本异常之一派生异常.在Visual Studio中输入Excepti ...

  3. [系统安全] 十.Windows漏洞利用之SMBv3服务远程代码执行漏洞(CVE-2020-0796)及防御详解

    您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列.因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全.逆向分 ...

  4. java 异常处理发生异常_处理Java中的异常

    java 异常处理发生异常 每个程序员都希望编写一个完美的程序. 也就是说,程序运行时没有任何障碍. 好吧,如果希望是马,乞g就会骑. 除了程序员的所有愿望之外,有时还会发生无法预料的情况. 在Jav ...

  5. java 异常的分类并举例_Java异常处理中的一些特殊情况举例

    只使用try和finally不使用catch的原因和场景JDK并发工具包中,很多异常处理都使用了如下的结构,如AbstractExecutorService,即只有try和finally没有catch ...

  6. kotlin中的异常处理_如何使用assertFailsWith在Kotlin中测试异常

    kotlin中的异常处理 by Daniel Newton 丹尼尔·牛顿 如何使用assertFailsWith在Kotlin中测试异常 (How to test exceptions in Kotl ...

  7. python自定义全局异常_flask中主动抛出异常及统一异常处理代码示例

    本文主要介绍的是flask中主动抛出异常及统一异常处理的相关内容,具体如下. 在开发时,后台出现异常 ,但不想把异常显示给用户或者要统一处理异常时,可以使用abort主动抛出异常,再捕获异常返回美化后 ...

  8. junit 5测试异常处理_在JUnit中处理异常的3种方式。 选择哪一个?

    junit 5测试异常处理 在JUnit中,有3种流行的方式来处理测试代码中的异常: 试捕习语 使用JUnit规则 带注解 我们应该使用哪一个?何时使用? 试捕习语 这个习语是最受欢迎的习语之一,因为 ...

  9. 我们的系统检测到您的计算机网络中存在异常流量_如何建立我们的网络防线?入侵检测,确保我们的网络安全...

    目前我们的网络安全趋势日益严峻,那么如何利用入侵检测系统确保我的网络安全呢?入侵检测又是什么呢? 网络安全 入侵检测技术是为保证计算机系统的安全,而设计与配置的一种能够及时发现并报告系统中未授权或异常 ...

最新文章

  1. Linux下redis的安装
  2. android OkHttp form 上传图片和参数
  3. 中国石油大学(华东)暑期集训--二进制(BZOJ5294)【线段树】
  4. MySQL数据库的回滚失败(JAVA)
  5. 反编译后怎么修改服务器地址,反编译后怎么修改服务器地址
  6. 【课堂教学/课堂复习/课堂竞赛手段探析】给广大教师推荐一个期末课堂复习的最好办法
  7. 怎么判断二阶导数是否异号_「高等数学」给出函数的二阶导函数图形,求该曲线图形拐点的个数...
  8. C语言一个数组中随机抽取5个数字
  9. 【C语言】常见面笔试题(10道)
  10. 计算机中硬盘容量的单位,硬盘容量的单位和计算单位是什么?
  11. Python学习_100Days
  12. Android桌面小插件——Widget
  13. 计算机画分段函数,《几何画板》:绘制分段函数的图像 -电脑资料
  14. NR PRACH(三)时域位置
  15. python彩色七段数码管绘制
  16. 【健康专栏】170条生理常识,好好养生啊
  17. 如何从零开始训练BERT模型
  18. 如何使用BSA方法进行遗传定位(水稻篇)
  19. Tableau图表 • 桑基图
  20. 【01.23】大数据 -- JAVA基础 P15-P24

热门文章

  1. 08-Hadoop之Zookeeper详解
  2. 仿牛客网项目第二章:开发社区登录模块(详细步骤和思路)
  3. 如何实现超大文件上传?
  4. Java -- SQL注入
  5. ES面试问题和入门资料
  6. 2023最新SSM计算机毕业设计选题大全(附源码+LW)之java疫情下校园食品安全信息管理系统4r61l
  7. 004-hive基本操作
  8. 《程序员十二时辰》,居然是这样的!内容过于真实 ...
  9. 吉利汽车科创板上市终止:2019年利润腰斩,还存在两大风险问题
  10. OpenStreetMap数据Qt5分析实战(基于2020数据)