首页
社区
课程
招聘
[原创][原创]SMB RCE CVE-2022-35804 分析
发表于: 2022-8-11 14:42 10097

[原创][原创]SMB RCE CVE-2022-35804 分析

2022-8-11 14:42
10097

2022年8月更新中出现了SMB的RCE, 微软介绍说对于server端是认证后的, 所以应该不会是历史漏洞重新出现的问题, 毕竟曾经也分析过一阵子SMB, 出现了新鲜漏洞还是需要分析分析的, 以下是一个简单的分析介绍

Bug

首先官方介绍是压缩相关的bug, 对比srv2.sys和srvnet.sys后, 发现srvnet.sys的SmbCompressionDecompress有改动, 所以大概率是它了.

 

以下是相关改动:
图片描述

 

从图中看到, 改动其实很小, 就改了个传入参数.

 

查看MSDN对于该函数的说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
NT_RTL_COMPRESS_API NTSTATUS RtlDecompressBufferEx2(
  [in]           USHORT CompressionFormat,
  [out]          PUCHAR UncompressedBuffer,
  [in]           ULONG  UncompressedBufferSize,
  [in]           PUCHAR CompressedBuffer,
  [in]           ULONG  CompressedBufferSize,
  [in]           ULONG  UncompressedChunkSize,
  [out]          PULONG FinalUncompressedSize,
  [in, optional] PVOID  WorkSpace
);
 
[in, optional] WorkSpace
 
A pointer to a caller-allocated work space buffer used by the RtlDecompressBufferEx2 function during decompression. Use the RtlGetCompressionWorkSpaceSize function to determine the correct work space buffer size.

所以可以了解到, workspace理应是caller申请的一块内存. 一般来说, 应该是如下的形式调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
if(NT_SUCCESS(RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, &CompressBufferWorkSpaceSize, &CompressFragmentWorkSpaceSize)))
{
    if(WorkSpace = LocalAlloc(LPTR, CompressBufferWorkSpaceSize))
    {
        if((*compressedData) = LocalAlloc(LPTR, size))
        {
            status = NT_SUCCESS(RtlCompressBuffer(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, (PUCHAR) data, size, (PUCHAR) (*compressedData), size, 4096, compressedSize, WorkSpace));
            if(!status)
                LocalFree(*compressedData);
        }
        LocalFree(WorkSpace);
    }
}

接下来, 我们看看P到底是个什么东西.
在SmbCompressionInitialize函数内, 它初始化了全局变量P:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
CompressionWorkSpaceSize = RtlGetCompressionWorkSpaceSize(
                             2u,
                             &CompressBufferWorkSpaceSize,
                             &CompressFragmentWorkSpaceSize);
if ( CompressionWorkSpaceSize < 0 )
  goto LABEL_12;
v1 = 0;
if ( CompressBufferWorkSpaceSize )
  v1 = CompressBufferWorkSpaceSize;
CompressionWorkSpaceSize = RtlGetCompressionWorkSpaceSize(
                             3u,
                             &CompressBufferWorkSpaceSize,
                             &CompressFragmentWorkSpaceSize);
if ( CompressionWorkSpaceSize < 0 )
  goto LABEL_12;
if ( CompressBufferWorkSpaceSize > v1 )
  v1 = CompressBufferWorkSpaceSize;
CompressionWorkSpaceSize = RtlGetCompressionWorkSpaceSize(
                             4u,
                             &CompressBufferWorkSpaceSize,
                             &CompressFragmentWorkSpaceSize);
if ( CompressionWorkSpaceSize < 0 )
  goto LABEL_12;
if ( CompressBufferWorkSpaceSize > v1 )
  v1 = CompressBufferWorkSpaceSize;
P = (PVOID)PplCreateLookasideList(0, 0, v1, 0x2532534Cu, v3, 0x2532534Cu);

可以看到, v1最后的值应该是3种压缩类型所需要的size中最大的那一个, P是LOOKASIDE_LIST 相关的结构体. 这样在需要的时候, 比如第一个图更新后的58行, 使用P的申请函数去申请相应size的内存作为workspace.

 

然而, 由于程序员错误的使用, 不小心传入了P, 导致了类型混淆, 从而造成了对P的写入问题.

History

在windows 10 1909的代码中, SmbCompressionDecompress是这样实现的:

1
2
3
4
5
6
if ( RtlGetCompressionWorkSpaceSize(v13, &CompressBufferWorkSpaceSize, (PULONG)CompressFragmentWorkSpaceSize) < 0
  || (PoolWithTag = ExAllocatePoolWithTag((POOL_TYPE)512, CompressBufferWorkSpaceSize, 0x2532534Cu)) != 0i64 )
{
  v10 = RtlDecompressBufferEx2(v13, a4, (unsigned int)a5, a2, a3, 0, a6, PoolWithTag);
#   if ( PoolWithTag )
    ExFreePoolWithTag(PoolWithTag, 0x2532534Cu);

可见没有任何问题, 在windows 10 2004里, 开始变了模样, 但是参数传递是修补后的样子. 之前保存过windows 20211(发布于2020年9月)的srvnet.sys文件, 发现它是传递了P, 所以可以看到, 这个bug应该某个开发版引入的, 一直延续到了windows 11.

 

有意思的是, 它的变量类型是PVOID, 而P也是PVOID, 所以编译器不会有任何警告. 理论上只要有任何测试触发这个位置, 这块代码都有可能会崩溃, 但是直到如今, 才被爆出来, 也是出人意料的, 可见微软内部的安全审计依然不到位(也许就没有)

我想微软之所以那么改, 可能是为了提高内存利用效率, 避免频繁的申请内存吧, 没想到搞出这等幺蛾子, 哈哈哈

影响

好在, 自从windows 爆出过压缩部分的bug后, 它已经要求server端先验证, 后压缩, 使得bug只能是认证后才能触发. 但是Client端还是会受影响的, 毕竟client主动连的server, 也就不存在认证限制了.


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2022-9-7 11:30 被音货得福编辑 ,原因: 优化说明
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//