CVE-2020-0769逆向分析
受影响版本:
| 系统 | 版本 |
|---|---|
| Microsoft Windows 10 | |
| Windows 10 | 1607 |
| Windows 10 | 1709 |
| Windows 10 | 1803 |
| Windows 10 | 1809 |
| Windows 10 | 1903 |
| Windows 10 | 1909 |
| Windows 7 SP1 | |
| Windows 8.1 | |
| Windows RT 8.1 | |
| Windows Server | 2008 SP2 |
| Windows Server | 2008 R2 SP1 |
| Windows Server | 2012 |
| Windows Server | 2012 R2 |
| Windows Server 2016 | |
| Windows Server 2019 | |
| Windows Server | 1803 |
| Windows Server | 1903 |
| Windows Server | 1909 |
此漏洞只会影响SMB v3.1.1
客户端与服务端都存在此漏洞
服务端漏洞位于srv2.sys内核模块中,客户端漏洞位于mrxxmb.sys模块
漏洞描述
从win10 1903/win server 1903开始对SMB v3.1.1进行数据压缩的支持
包格式

翻译后内容


此次漏洞触发原因是因为客户端/服务端在进行数据解压是未对OriginalCompressedSegmentSize与Offset/Length 进行合理的长度检查造成的
先来大致梳理一下函数的调用关系:
DriverEntry=>Srv2DeviceControl=>Srv2ProcessFsctl=>Srv2StartDriver=>Srv2StartInstance=>Srv2ReceiveHandler
然后Srv2ReceiveHandler函数会将Srv2DecompressMessageAsync函数放入SLIST_ENTRY链表中进行回调异步调用

然后Srv2DecompressMessageAsync函数会调用去调用Srv2DecompressData函数

Srv2DecompressData函数会根据OriginalCompressedSegmentSize与Offset/Length进行内存分配

_mm_srli_si128函数是一个与XMM寄存器相关的函数,此函数让第一个参数v3逻辑运算向右移8个字节,要注意他的移动单位是字节不是位
此时Size指向ProtocolId,v4指向CompressionAlgorithm,Size偏移1个32位即4字节便是OriginalCompressedSegmentSize,v4偏移一个4字节便是Offset/Length
然后SrvNetAllocateBuffer函数申请内存空间其大小等于OriginalCompressedSegmentSize+Offset而这两个值都是可控的,然后进入SrvNetAllocateBuffer查看如何进行内存分配,要注意此函数与之后要看SmbCompressionDecompress的位于sysnet.sys模块中

进入SrvNetAllocateBuffe后他会先判断SrvDisableNetBufferLookAsideList是否为真,或者,参数1即要分配的内存大小是否大于0x100100
如果一方成立就进入if在判断参数1是否大于0x100100如果大于的话就返回失败,如果仅仅是SrvDisableNetBufferLookAsideList为真那就调用SrvNetAllocateBufferFromPool进行内存分配,再来看看SrvDisableNetBufferLookAsideList是如何初始化的

可以看出SrvDisableNetBufferLookAsideList是在函数SrvNetRefreshLanmanServerParameters中进行初始化的

可以看出SrvDisableNetBufferLookAsideList的值肯定为一个布尔值即真或假,SrvLibGetDWord函数会去调用ZwOpenKey打开注册表键值然后使用ZwQueryValueKey去读取注册表如果读取成功则返回一个指定值,如果读取失败则返回ZwQueryValueKey的返回值即失败原因,在我的系统里没有在注册表找到这个项,所以SrvDisableNetBufferLookAsideList的值默认为false,也就是说SrvNetAllocateBuffer的第一个if正常情况下不会去执行,顺着流程往下走可以看到

他会先判断参数1是否大于0x1100,然后求出到底用哪个值做SrvNetBufferLookasides的下标来获取内存,如果不大于0x1100则默认下标为0,再来看看SrvNetBufferLookasides是如何初始化的

进入SrvNetCreateBufferLookasides函数,一直追下去会发现PplCreateLookasideList内部其实还是调用ExInitializeLookasideListEx函数来进行LookasideList列表的初始化,我们直接进入SrvNetBufferLookasideAllocate查看分配了新的LookasideList列表的函数,这里(1<<(v3+12))+256是要分配内存的大小,根据计算此大小依次为[0x900,0x1100,0x2100,0x4100,0x8100,0x10100......0x80100]

SrvNetBufferLookasideAllocate在内部又调用了SrvNetAllocateBufferFromPool函数

在SrvNetAllocateBufferFromPool函数中调用了ExAllocatePoolWithTag函数来分配指定类型的内存

分配大小v7我重命名为size,然后会发现size=v6+v3=(2*(MmSizeOfMdl+8))+(lParam2 + 232)


最后要返回的数据我重命名为backdata,刚刚从ExAllocatePoolWithTag函数获取到的数据重命名为ExAllocData
可以看出backdata=&ExAllocData[lParam2+0x57]&0xFFFFFFFFFFFFFFF8ui64

假设lparam2为0x1100,那0x1100+0x57=0x1157,0x1157&0xFFFFFFFFFFFFFFF8ui64=0x1150,也就是说返回的数据是从ExAllocatePoolWithTag函数获取到的数据的0x1150偏移处开始的
根据上面可以总结出,SrvNetAllocateBuffer函数最后会创建一个‘结构体+数据’这种类型的一块内存,这块内存结构大致如下

回到srv2.sys中的Srv2DecompressData,在用SrvNetAllocateBuffer申请过内存后会调用SmbCompressionDecompress函数来解压缩数据,此函数也在srvnet.sys中,其本质上是调用RtlDecompressBufferEx2函数来进行数据解压缩的

这里解释一下几个重要参数,方便与Srv2DecompressData中的传入的参数一一对应
- CompressionFormat:解压缩算法,此参数不用过多关注,他对应SmbCompressionDecompress的第一个参数
- UncompressedBuffer:解压后数据存放的缓冲区地址,对应SmbCompressionDecompress的第四个参数
- UncompressedBufferSize:解压数据缓冲区大小,对应SmbCompressionDecompress的第五个参数
- CompressedBuffer:待解压数据,对应SmbCompressionDecompress的第二个参数
- CompressedBufferSize:待解压数据大小,对应SmbCompressionDecompress的第三个参数
返回值便是RtlDecompressBufferEx2函数的返回值
再回到Srv2DecompressData看看是如何调用SmbCompressionDecompress的

可以看出他会从*(_QWORD *)(*(_QWORD *)(v1 + 240) + 24i64) + Size.m128i_u32[3] + 16i64处获取压缩数据,经过解压放入Size.m128i_u32[3] + *(_QWORD *)(backdata + 24)backdata + 24指向刚刚SrvNetAllocateBuffer申请内存的起始位置,在这里也就是将解压后数据放入‘内存起始位置+SMB数据包offset/length’处,第六个参数v11用于接收解压后的数据大小,当SmbCompressionDecompress函数调用失败或者解压后的数据大小与SMB包中OriginalCompressedSegmentSize的值不一致时(不过如果RtlDecompressBufferEx2调用成功的话OriginalCompressedSegmentSize的值就会赋给v11),否则继续往后运行,接着往后看

这段代码可以解释为,如果offset/length不为0,则从(v1 + 240) + 24i64) + 16i64)处获取数据后放入(v8 + 24)指向的地址,根据分析上面SmbCompressionDecompress函数的调用可知(v1 + 240) + 24i64) + 16i64)大致指向压缩数据内存位置,(v8 + 24)指向内存起始的位置。
由于OriginalCompressedSegmentSize与Offset/Length长度我们可控,且SrvNetAllocateBuffer函数会根据他们俩来申请一块‘数据+结构体’形式的内存,我们可以申请一块较小的内存,将我们想要让重新赋值的某块内存的地址想办法构造payload填充到(v8 + 24)处,然后在momove函数执行时就会将我们想要写入的数据写入到(v8 + 24)处
CVE-2020-0769逆向分析的更多相关文章
- IM通信协议逆向分析、Wireshark自定义数据包格式解析插件编程学习
相关学习资料 http://hi.baidu.com/hucyuansheng/item/bf2bfddefd1ee70ad68ed04d http://en.wikipedia.org/wiki/I ...
- 技术分享:逆向分析ATM分离器
文章内容仅供技术交流,请勿模仿操作! 背景(作者) 每一次外出时, Elizabeth和我总是格外的小心,同时把我们身上的钱藏在特殊的皮带上面,这样还不够,我们还采取了“狡兔三窟”的方式来藏身上带的银 ...
- C++反汇编与逆向分析技术揭秘
C++反汇编-继承和多重继承 学无止尽,积土成山,积水成渊-<C++反汇编与逆向分析技术揭秘> 读书笔记 一.单类继承 在父类中声明为私有的成员,子类对象无法直接访问,但是在子类对象的 ...
- TI(德州仪器) TMS320C674x逆向分析之一
一.声明 作者并不懂嵌入式开发,整个逆向流程都是根据自身逆向经验,一步一步摸索出来,有什么错误请批评指正,或者有更好的方法请不吝赐教.个人写作水平有限,文中会尽量把过程写清楚,有问题或是写的不清楚的地 ...
- 一文了解安卓APP逆向分析与保护机制
"知物由学"是网易云易盾打造的一个品牌栏目,词语出自汉·王充<论衡·实知>.人,能力有高下之分,学习才知道事物的道理,而后才有智慧,不去求问就不会知道."知物 ...
- Android逆向分析(2) APK的打包与安装背后的故事
前言 上一次我们反编译了手Q,并遇到了Apktool反编译直接crash的问题,虽然笔者很想在这次解决这个问题,但在解决途中,发现该保护依赖于很多知识,所以本次先插入一下,正所谓知其然知其所以然,授之 ...
- 逆向分析一款国外Blackjack Card Counter软件并附上License生成脚本
没有学过逆向,一时兴起,搞了一下这个小软件,名为“逆向分析”,其实过程非常简单,难登大雅之堂,就当段子看吧.首先介绍一下背景吧.这是一款国外的Blackjack也就是21点算牌软件,我从来不玩牌的,机 ...
- 010 Editor v8.0.1(32 - bit) 算法逆向分析、注册机编写
010 Editor 的逆向分析整体算下来还是比较简单的,将程序拖入OD,通过字符串搜索定位到核心代码,经过分析,主要是如下图所示的两个关键函数,返回正确的值,才算是注册成功. 00409C9B 这个 ...
- [工控安全]西门子S7-400 PLC固件逆向分析(一)
不算前言的前言:拖了这么久,才发现这个专题没有想象中的简单,学习的路径大致是Step7->S7comm->MC7 code->firmware,我会用尽量简短的语言把前两部分讲清楚, ...
- 010 Editor 8.0.1 之 逆向分析及注册机编写
前言一.工具及软件介绍二.逆向分析2.1.找到提示错误注册弹窗2.2.分析跳转处代码2.3.=2D 函数分析2.3.1.获取注册码处分析2.3.2.3处分支分析2.3.2.1.9C情况2.3.2.2. ...
随机推荐
- git pull设置为无需密码
https方式每次都要输入密码,按照如下设置即可输入一次就不用再手输入密码的困扰而且又享受https带来的极速 设置记住密码(默认15分钟): git config --global credenti ...
- 增强for循环的用法
一.增强for循环 增强for循环的作用: 简化迭代器的书写格式.(注意:增强for循环的底层还是使用了迭代器遍历.)增强for循环的适用范围: 如果是实现了Iterable接口的对象或者是数组对象都 ...
- selenium原理学习笔记
一,selenium工作原理(参考文档:https://blog.csdn.net/dawei_yang000000/article/details/87639928) 自动化测试代码发送请求给到浏览 ...
- go panic
panic 抛出异常 通过recover捕获 类似 php python等语言的try catch package mainimport ( "fmt" "errors& ...
- linux(centos8):查看操作系统的当前版本(os/kernel/bash)
一,查看redhat系操作系统的版本: 适用于centos/fedora/rhel等 [root@centos8 ~]# cat /etc/redhat-release CentOS Linux re ...
- java Error opening registry key 'Software\JavaSoft\Java Runtime Environment'安装jdk1.7遇到的问题
最近开发项目要求jdk在1.7以上,我先卸载了jdk1.6,下载1.7下来安装好,配置下环境变量,可以是在输入java -version的时候发现: java Error opening regist ...
- 第二十一章 PHP编译安装(centos7)
一.环境准备 主机 IP 身份 web01 10.0.0.7 编译安装PHP 二.准备安装 1.新建目录 [root@jindada ~]# mkdir /php 2.上传源码包并解压 [root@j ...
- HTML <del> 标签
HTML <del> 标签 什么是<del> 标签? 定义文档中已被删除的文本. 实例 a month is <del>25</del> 30 day ...
- 【Azure 环境】连接到微软云Azure中国区 By VS 2019, VS Code, Powershell
问题情形 最近,在使用最新的VS Code插件连接到中国区的Azure时候,出现了依旧是global版的登录连接.这个问题是当前Azure Account插件最新版的问题,可以使用V0.8.11版本登 ...
- css和js实现硬件加速渲染自定义滚动条
听别人说用CSS的变换来实现渲染有硬件加速的效果,看到很多大网站都开始陆续使用上了,我也来说说怎么做,我这边实现的滚动条有自然滚动效果,看起来比较自然,说的再多不如直接写,让我们开始吧! 我们需要自己 ...