受影响版本:

系统 版本
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逆向分析的更多相关文章

  1. IM通信协议逆向分析、Wireshark自定义数据包格式解析插件编程学习

    相关学习资料 http://hi.baidu.com/hucyuansheng/item/bf2bfddefd1ee70ad68ed04d http://en.wikipedia.org/wiki/I ...

  2. 技术分享:逆向分析ATM分离器

    文章内容仅供技术交流,请勿模仿操作! 背景(作者) 每一次外出时, Elizabeth和我总是格外的小心,同时把我们身上的钱藏在特殊的皮带上面,这样还不够,我们还采取了“狡兔三窟”的方式来藏身上带的银 ...

  3. C++反汇编与逆向分析技术揭秘

    C++反汇编-继承和多重继承   学无止尽,积土成山,积水成渊-<C++反汇编与逆向分析技术揭秘> 读书笔记 一.单类继承 在父类中声明为私有的成员,子类对象无法直接访问,但是在子类对象的 ...

  4. TI(德州仪器) TMS320C674x逆向分析之一

    一.声明 作者并不懂嵌入式开发,整个逆向流程都是根据自身逆向经验,一步一步摸索出来,有什么错误请批评指正,或者有更好的方法请不吝赐教.个人写作水平有限,文中会尽量把过程写清楚,有问题或是写的不清楚的地 ...

  5. 一文了解安卓APP逆向分析与保护机制

    "知物由学"是网易云易盾打造的一个品牌栏目,词语出自汉·王充<论衡·实知>.人,能力有高下之分,学习才知道事物的道理,而后才有智慧,不去求问就不会知道."知物 ...

  6. Android逆向分析(2) APK的打包与安装背后的故事

    前言 上一次我们反编译了手Q,并遇到了Apktool反编译直接crash的问题,虽然笔者很想在这次解决这个问题,但在解决途中,发现该保护依赖于很多知识,所以本次先插入一下,正所谓知其然知其所以然,授之 ...

  7. 逆向分析一款国外Blackjack Card Counter软件并附上License生成脚本

    没有学过逆向,一时兴起,搞了一下这个小软件,名为“逆向分析”,其实过程非常简单,难登大雅之堂,就当段子看吧.首先介绍一下背景吧.这是一款国外的Blackjack也就是21点算牌软件,我从来不玩牌的,机 ...

  8. 010 Editor v8.0.1(32 - bit) 算法逆向分析、注册机编写

    010 Editor 的逆向分析整体算下来还是比较简单的,将程序拖入OD,通过字符串搜索定位到核心代码,经过分析,主要是如下图所示的两个关键函数,返回正确的值,才算是注册成功. 00409C9B 这个 ...

  9. [工控安全]西门子S7-400 PLC固件逆向分析(一)

    不算前言的前言:拖了这么久,才发现这个专题没有想象中的简单,学习的路径大致是Step7->S7comm->MC7 code->firmware,我会用尽量简短的语言把前两部分讲清楚, ...

  10. 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. ...

随机推荐

  1. Termux基础教程(二):软件包安装

    Termux基础教程(二):软件包安装 Termux是一个在安卓手机上模拟Linux系统的高级终端,这个终端十分强大,实用. Termux可以安装Liunx的各种软件包,这就是Termux的灵魂所在. ...

  2. ScanTailor-ScanTailor 自动矫正图像歪斜

    ScanTailor 自动矫正图像歪斜   下面操作某一步可能会卡住,别担心情等待它处理完毕.   New Project ... Input Directory "Browse" ...

  3. vim插件配置

    OS:kali linux tool:vim 上图: 0x00 需要用到的插件及其下载地址 左边的一栏显示文件目录结构的用到的插件为 NERDTree 下载地址:https://github.com/ ...

  4. Gitlab 11.9.1 高可用教程

    Gitlab 11.9.1 高可用教程 一. PostgreSQL数据迁移 由于默认Gitlab的安装会内置Postgres数据库,并且没有对外,所以我们需要通过设置对应的Gitlab的配置将其中的数 ...

  5. poj3178 Roping the Field (计算几何 + dp)

    Roping the Field Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 858   Accepted: 250 De ...

  6. liunx 免密登录远程主机

    #!/bin/bash #Program: # no password login in hosts #History: # hbl 2017/12/9 1.0.0v function auto-lo ...

  7. NET CORE WebAPI 搭建--基础搭建

    之前我们写了一个系统架构,是用.NET CORE 3.1.2 版本写的,没有使用前后端分离,说话老实话,本屌前端不是非常牛逼,太多的样式需要写,而且还要兼容响应式页面,一个人确实忙不过来,所以就想搞一 ...

  8. 基于Python与命令行人脸识别项目(系列一)

    Face Recognition 人脸识别 摘要:本项目face_recognition是一个强大.简单.易上手的人脸识别开源项目,并且配备了完整的开发文档和应用案例,方便大家使用.对于本项目可以使用 ...

  9. [String] intern()方法

    intern()方法设计的初衷,就是重用String对象,以节省内存消耗. JDK1.6以及以前版本中,常量池是放在 Perm 区(属于方法区)中的,熟悉JVM的话应该知道这是和堆区完全分开的. 使用 ...

  10. E. Almost Regular Bracket Sequence 解析(思維)

    Codeforce 1095 E. Almost Regular Bracket Sequence 解析(思維) 今天我們來看看CF1095E 題目連結 題目 給你一個括號序列,求有幾個字元改括號方向 ...