热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【漏洞分析】MS17017Windows内核提权漏洞Exploit分析

作者:playb0y23333预估稿费:1000RMB(本篇文章享受双倍稿费 活动链接请点击此处)投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿一、简介此次分析的内核提权漏洞为S

https://img.php1.cn/3cd4a/1eebe/cd5/7d7ef3f69d479716.webp

作者:playb0y23333

预估稿费:1000RMB

(本篇文章享受双倍稿费 活动链接请点击此处

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

一、简介

此次分析的内核提权漏洞为SENSEPOST的Saif El-Sherei在分析微软MS17-017补丁的时候发现的,该漏洞类型为win32k.sys驱动程序中处理GDI对象的函数EngRealizeBrush内发生的整型溢出,利用方式也比较经典,Saif El-Sherei在今年的Defcon会议上发布了一款针对Win7 Sp1 x86平台的Exploit,我就主要针对该Exploit进行了下简单的分析,如果分析过程存在问题,欢迎联系我交流指正。


二、成因分析

Saif是通过补丁比对分析的漏洞成因,为了便于分析漏洞成因,我们先把漏洞POC代码中的喷射及后续的利用代码去掉,只留能够触发蓝屏的代码(见附件中的poc.exe),运行poc程序触发蓝屏,通过分析蓝屏信息再一步步的定位漏洞触发成因(注意:poc.exe中设置了一个调试断点,在Windbg中触发之后设置了一个虚拟机快照,以后每次重新调试恢复快照重新连接Windbg即可,这样可以尽量使每次调试时的内存布局尽量稳定):

 https://img.php1.cn/3cd4a/1eebe/cd5/60405fda58cd0acd.webp

查看栈回溯信息也可以看到是在ExFreePoolWithTag函数释放Pool时的故障:

 https://img.php1.cn/3cd4a/1eebe/cd5/eec57030b649a106.webp

查看0xfdec3168处的Pool信息:

 https://img.php1.cn/3cd4a/1eebe/cd5/433ea70d6ea577b1.jpeg

根据Pooltag标识Gebr搜索到该Pool是在EngRealizeBrush函数中申请的:

 https://img.php1.cn/3cd4a/1eebe/cd5/2fdc212433a29829.png

其实根据这里的内存申请代码已经能够看出此处存在问题,PALLOCMEM函数参数中申请的空间大小为ebx+0x40h,即下图中反编译的代码中的v12+0x40,v12本身为无符号整型,所以申请的空间大小至少为0x40:

 https://img.php1.cn/3cd4a/1eebe/cd5/60405fda58cd0acd.webp

但是在之前查看0xfdec3168处的Pool信息中显示的Size为0x18(包含Pool 头部8字节,实际申请空间大小应为0x10)。可以证明此处申请内存时发生了整形溢出:

 https://img.php1.cn/3cd4a/94ce/a6e/865776f6fe3d5f59.jpeg

下面再啰嗦下查看蓝屏的成因,在PALLOCMEM函数返回处下断查看申请的Pool内存地址:

 https://img.php1.cn/3cd4a/1eebe/cd5/7d7ef3f69d479716.webp

此处注意对比蓝屏时查看的0xfdec3168处Pool信息,可以发现蓝屏状态时0xfdec3178处显示的POOL_HEADER被破坏,在释放其链表的下一项0xfdec3160时导致其操作失败,下面再看下0xfdec3178地址处存放的数据是如何被覆盖的,触发写断点:

 https://img.php1.cn/3cd4a/1eebe/cd5/1e3db12dd78db092.webp

0xfdec3160处Pool大小为0x18字节,除去8字节的POOL_HEADER大小,实际的缓冲区只有0xfdec3168-0xfdec3178这0x10字节,但是明显可以看到此处被越界覆写,也就验证了EngRealizeBrush函数调用PALLOCMEM申请内存时申请空间过小,导致后续操作该处内存空间时发生了越界。

下面来分析一下为什么PALLOCMEM函数会只申请0x10字节的内存,再来深入探究下其参数的来源:

 https://img.php1.cn/3cd4a/1eebe/cd5/99b88427bc9ce0dc.webp

来看下运行时的计算过程,下图中的乘法运算即v60*v68,最终结果还需要加上0x44(68),调用PALLOCMEM函数时再加上0x40:

 https://img.php1.cn/3cd4a/1eebe/cd5/72fd2c126203a875.webp

此时edi寄存器的值以及ebp-18h的值均来自poc代码中CreateBitmap函数参数(HBITMAP bitmap = CreateBitmap(0x23, 0x1d41d41, 1, 1, NULL))。最终的计算结果为0x23*0x20/(2^3)* 0x1d41d41=0xFFFFFF8C,在调用PALLOCMEM函数时又分别加上了0x44、0x40字节,0xFFFFFF8C+0x44+0x40= 0x100000010,正是在此整形溢出导致的实际申请内存时只申请了0x10字节,在EngRealizeBrush后续对申请的内存赋值时导致破坏了紧邻的Pool结构,最终触发蓝屏。


三、漏洞利用

该漏洞的利用过程还是比较精彩的,上文的poc中原作者已经构造好参数,控制最终申请0x10+0x8字节内存,能够越界覆写临近的Pool结构,为了完成提权过程可以使用多种利用方式,作者发布的Exploit使用的是混合利用Bitmap和Palette对象完成,首先控制在发生越界的SURFOBJ对象后面喷射两个相邻的Bitmap对象和Palette对象,利用越界覆写第一个Bitmap对象结构的sizlBitmap成员,获取相对地址读写权限,再利用被修改的Bitmap对象修改相邻的Palette对象的cEntries成员,继而控制这个Palette对象修改第二个Palette对象的pFirstColor成员,完成任意地址读写,替换当前进程的Token为SYSTEM进程的Token,整个利用过程也就完成了。

3.1喷射

因为产生越界读写的SURFOBJ对象是在Paged Session Pool中分配的,对应的也需要利用它的特性完成喷射,第一次申请内存将首先占据内存页(0x1000字节大小)的开始部分,后续申请的内存则会从内存页的末尾开始向前排列(盗用Saif文章原图如下):

 https://img.php1.cn/3cd4a/1eebe/cd5/780a3060eeed6a4e.webp

具体做法如下:

a)首先申请2000个0xFE8字节大小的空间,用于清理内存空间,内存页末尾留出0x18字节。

b)利用创建Windows窗体类时成员lpszMenuName,控制申请0x18字节内存占用上一步空出的0x18字节。虽然窗体类tagCLS是在Desktop Heap中分配内存,但是lpszMenuName却是在内核池中分配的。

c)释放第一步申请的0xFE8大小的空间,便于下一步布置相邻的Bitmap以及Palette对象。

d)依次申请0x7F8字节大小的Bitmap对象以及0x7E8字节大小的Palette对象,使相邻的这两个对象占据上一步释放的空间,关于如何确定内核中Bitmap对象申请的空间大小跟CreateBitmap函数的参数之间没有确定的公式,只能不断尝试,不过CreatePalette函数参数与对应的内核中申请空间的大小已经有公开的资料了。

e)释放第二步申请的窗体类,这样最后0x18字节内存就变成为了Free状态,在漏洞触发时申请的0x18内存就落入了这些内存空洞之间。

下面将exploit代码中喷射的代码和利用的代码注释回来,重新开始调试exploit从堆喷到执行Shellcode的步骤,同时继续在PALLOCMEM运行完毕后下断,查看发生越界的SURFOBJ对象所在的内存地址以及喷射之后越界对象地址附近的内存布局:

 https://img.php1.cn/3cd4a/1eebe/cd5/d34245582687a4e6.webp

可以看到发生越界的SURFOBJ对象0xfd4a8ff0相邻的两个对象就是我们布局的一个Bitmap对象(0xfd4a9000)以及Palette对象(0xfd4a97f8),利用喷射完成内存地址的稳定布局之后就可以触发漏洞了。

3.2相对地址读写

实现相对地址读写的目的主要是能够利用只触发漏洞一次,完成从受限的越界写入转化成可以多次覆写其它更多地址的功能,注意漏洞触发时并非只有我们在分析漏洞成因的时候发现的越界覆写Pool Header,同时覆盖的还有相邻内存池的其它数据结构:

 https://img.php1.cn/3cd4a/9b0d/ae9/2d998ad7838fbf16.jpeg

在写exploit中我们主要关注*(_DWORD *)(v16 + 0x3C) = a3这段代码,除去发生越界的SURFOBJ对象缓冲区0x10字节以及相邻的Bitmap对象的Pool header0x8字节、_BASE_OBJECT 0x10字节,实际还会覆盖相邻的Bitmap对象的sizlBitmap结构的cy成员(0x3C-0x10-0x10-0x8=0x14):

 https://img.php1.cn/3cd4a/1e618/cd5/af17da15769ccb2e.jpeg

下面继续运行exploit覆盖该地址的数据,也可以使用windbg的gdiobjdump插件更方便的查看覆盖的数据格式,这里不再介绍了:

 https://img.php1.cn/3cd4a/1eebe/cd5/857a46d091981bac.webp

因为修改了Bitmap对象的sizlBitmap结构,现在就能利用Bitmap对象的GetBitmapBits、SetBitmapBits函数完成功能更容易操作的越界读写操作,因此也就拥有了喷射在与Bitmap对象紧邻的Palette对象数据结构的数据的操作能力,具体需要读写那些Palette对象成员可以研究下Palette对象的结构:

 https://img.php1.cn/3cd4a/1eebe/cd5/02c379d60086f382.webp

其中cEntries代表结构体末尾的 PALETTEENTRY数组的成员个数,pFirstColor指针则指向PALETTEENTRY数组的第一个成员的地址。下面通过利用上一步的Bitmap对象修改相邻Palette对象的cEntries为0xFFFFFFFF,就相当于是扩展了Palette对象操作的内存空间是pFirstColor指针指向的内存空间之后的任意地址。这部分流程也比较简单,首先从喷射的Bitmap对象中找到被漏洞触发越界覆写sizlBitmap结构的那个Bitmap对象,调用GetBitmapBits函数看看那个能越界就行,不再赘述。第二步根据喷射时Bitmap与Palette对象的位置关系,调用GetBitmapBits获取Bitmap对象的数据,定位到其中包含的Palette对象的cEntries成员,修改后调用SetBitmapBits函数重新写入,下图即为被修改前后的cEntries:

 https://img.php1.cn/3cd4a/1eebe/cd5/bdd1ca32a69bc8b2.webp

至此就被覆写cEntries的Palette对象就拥有相对地址读写的能力了。

3.3任意地址读写

虽然已经能够完成相对地址读写的能力,但是还是局限在特定的内存空间内,所以还需要再做一点手脚完成对任意地址内存空间的操纵能力,最终完成替换Token的操作。具体做法其实类似上一步骤覆写cEntries,这里只需要覆写pFirstColor指针即可,需要修改什么地址的内存将pFirstColor指针指向该地址就行了,首先也是先寻找到被修改cEntries结构的Palette对象,不再赘述。根据喷射的特点,每隔0x1000就存在一个喷射的Palette对象,直接调用SetPaletteEntries函数对下一个内存页的Palette对象pFirstColor成员进行修改即可:

 https://img.php1.cn/3cd4a/18ace/696/1d8e759bd3e6bbec.jpeg

注意此处pFirstColor的值被修改为了0xfd4a8000,这个地址是第一步喷射时和发生越界的SURFOBJ对象在同一个内存页的Bitmap对象。设置成这个地址的目的是利用该地址处Bitmap对象的tag值Gh15做标示,再遍历所有喷射的Palette对象这个pFirstColor值被修改的Palette。

 https://img.php1.cn/3cd4a/1eebe/cd5/67cc2e96eddffff8.png

到此就已经具备任意地址读写的能力了,需要修改任意地址的内存只需利用被修改cEntries的Palette去再次修改第二个Palette的pFirstColor,再对其调用SetPaletteEntries、GetPaletteEntries函数读取或修改内存数据。

3.4Shellcode

进行到这里就可以松口气了,内核提权Shellcode目前一般都采用替换当前进程的Token为SYSTEM进程的Token,这里没有什么需要特别说的,首先获取当前进程和SYSTEM进程的EPROCESS结构地址,利用任意地址读写将SYSTEM进程的Token写入到当前进程的Token位置就完事了。提权成功:

https://img.php1.cn/3cd4a/1eebe/cd5/ed19db63ee478b98.png

 

四、总结

微软最后在PALLOCMEM函数申请内存之前添加了ULongLongToULong函数做检测,如果发生了整形溢出不会跳转到申请内存的代码,已经被Patch的代码:

 https://img.php1.cn/3cd4a/1eebe/cd5/d67981797265d9c7.webp

除了exp所使用的这种漏洞利用方式以外,Saif也提到了其它两种方式,一种是利用两个相邻的Bitmap对象完成,由一个Bitmap对象去覆写另一个Bitmap的pvScan0来完成任意地址读写,另一种方式是利用一个Bitmap直接去修改一个Palette对象的pFirstColor指针,有兴趣的湿敷可以尝试下。

附件链接:

https://share.weiyun.com/d1ed23e7750d6a37e3db268ac9ad84ef 


参考资料:

Saif El-Sherei的代码及文章:

https://github.com/sensepost/gdi-palettes-exp 


推荐阅读
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 深度学习中的Vision Transformer (ViT)详解
    本文详细介绍了深度学习中的Vision Transformer (ViT)方法。首先介绍了相关工作和ViT的基本原理,包括图像块嵌入、可学习的嵌入、位置嵌入和Transformer编码器等。接着讨论了ViT的张量维度变化、归纳偏置与混合架构、微调及更高分辨率等方面。最后给出了实验结果和相关代码的链接。本文的研究表明,对于CV任务,直接应用纯Transformer架构于图像块序列是可行的,无需依赖于卷积网络。 ... [详细]
  • 导出功能protectedvoidbtnExport(objectsender,EventArgse){用来打开下载窗口stringfileName中 ... [详细]
  • ScrollView嵌套Collectionview无痕衔接四向滚动,支持自定义TitleView
    本文介绍了如何实现ScrollView嵌套Collectionview无痕衔接四向滚动,并支持自定义TitleView。通过使用MainScrollView作为最底层,headView作为上部分,TitleView作为中间部分,Collectionview作为下面部分,实现了滚动效果。同时还介绍了使用runtime拦截_notifyDidScroll方法来实现滚动代理的方法。具体实现代码可以在github地址中找到。 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • Android实战——jsoup实现网络爬虫,糗事百科项目的起步
    本文介绍了Android实战中使用jsoup实现网络爬虫的方法,以糗事百科项目为例。对于初学者来说,数据源的缺乏是做项目的最大烦恼之一。本文讲述了如何使用网络爬虫获取数据,并以糗事百科作为练手项目。同时,提到了使用jsoup需要结合前端基础知识,以及如果学过JS的话可以更轻松地使用该框架。 ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 如何在php文件中添加图片?
    本文详细解答了如何在php文件中添加图片的问题,包括插入图片的代码、使用PHPword在载入模板中插入图片的方法,以及使用gd库生成不同类型的图像文件的示例。同时还介绍了如何生成一个正方形文件的步骤。希望对大家有所帮助。 ... [详细]
  • 如何利用 Myflash 解析 binlog ?
    本文主要介绍了对Myflash的测试,从准备测试环境到利用Myflash解析binl ... [详细]
  • .NetCoreWebApi生成Swagger接口文档的使用方法
    本文介绍了使用.NetCoreWebApi生成Swagger接口文档的方法,并详细说明了Swagger的定义和功能。通过使用Swagger,可以实现接口和服务的可视化,方便测试人员进行接口测试。同时,还提供了Github链接和具体的步骤,包括创建WebApi工程、引入swagger的包、配置XML文档文件和跨域处理。通过本文,读者可以了解到如何使用Swagger生成接口文档,并加深对Swagger的理解。 ... [详细]
author-avatar
hy11011_847
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有