导语:为了显示图形,图形加速器需要将OpenGL脚本处理成实际的图形。该过程被称为“着色器编译”(Shader Compilation)。在Intel图形加速器中,这一过程是由igdusc64动态链接库(DLL)来完成的,而这一位置存在漏洞。
一、概述
为了显示图形,图形加速器需要将OpenGL脚本处理成实际的图形。该过程被称为“着色器编译”(Shader Compilation)。在Intel图形加速器中,这一过程是由igdusc64动态链接库(DLL)来完成的,而这一位置存在漏洞。
二、指针损坏漏洞(CVE-2018-12152)
2.1 概述
在适用于Intel图形加速器(10.18.14.4889版本)的Intel Unified Shader编译器存在一个可以利用的指针损坏漏洞。特定的像素着色器(Pixel Shader)可能会导致指针损坏,一旦攻击者成功利用此漏洞,将会导致代码执行漏洞。攻击者可以通过提供二进制或文本形式的特制着色器文件来触发此漏洞。该漏洞可以通过VMWare Guest虚拟机来触发。在特定情况下,WebGL也可能会作为攻击媒介。
2.2 测试环境
· Windows 8.1 x64 操作系统
· VMWare Workstation 14(14.0.0 build-6661328)
· Intel igdusc64.dll 10.18.14.4889(x64)
· 其中Guest VM操作系统为Windows 8.1 x64
2.3 漏洞详情
攻击者可以通过向Intel igdusc64.dll驱动程序提供格式错误的像素着色器(文本或二进制形式)来触发此漏洞。该攻击可以从本地计算机(用户模式)、VMWare Guest用户模式(导致VMWare主机发生内存损坏)触发。理论上,也可以通过WEBGL(远程网页)触发,前提是浏览器不会使用ANGLE,并且以某种方式向Intel驱动程序提供格式错误的着色器。
特定的Shader文件会导致igdusc64.dll驱动程序执行从已损坏或无效指针获取的内存位置的内容:
17a0.13ec): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. igdusc64!USC::SetClientCallbacks+0x360024: 00007ffe`8b9daf84 ff90e0000000 call qword ptr [rax+0E0h] ds:00007ffe`00000160=????????????????
更多反编译后代码如下:
.text:000000000045AF40 loc_45AF40: ; CODE XREF: sub_45AEB0+112°j .text:000000000045AF40 mov rax, [r14+20h] .text:000000000045AF44 mov ecx, [rsi+rax] ; rsi = 0/8; rax = mem .text:000000000045AF47 mov rax, [r15+18h] .text:000000000045AF4B cmp ecx, [rax+30h] .text:000000000045AF4E jnb short loc_45AFBB .text:000000000045AF50 mov rdi, [rax+28h] .text:000000000045AF54 test rdi, rdi .text:000000000045AF57 jz short loc_45AF64 .text:000000000045AF59 cmp ecx, [rax+30h] .text:000000000045AF5C jnb short loc_45AF64 .text:000000000045AF5E mov rdi, [rdi+rcx*8] ; rdi = mem with call pointer (v-table), rcx = index ... .text:000000000045AF7E mov rax, [rdi] .text:000000000045AF81 mov rcx, rdi .text:000000000045AF84 call qword ptr [rax+0E0h]
攻击者可以影响用于计算最终指针的索引值(0x45AF5E),但这不是漏洞的根本原因。实际的指针损坏早于sub_142B0发生。该函数负责将一个新指针写入[mem-4]区域,在其后的[mem]区域会被函数使用,作为调用指令目的地的“来源”。这意味着,最终的指针将会由两个不同的指针计算而得。
addr_45AF44: rsi=0x0000000000000008 rax=0x0000008029c2eae4 [rsi+rax]=0x0100e400000002a6 addr_45AF4B: ecx = 0x000002a6 must be < [@rax+0x30]=0x0000032e addr_45AF5E: rdi_calced=0x0000008029505a78 rdi=0x00000080297b3000 rcx=0x00000000000002a6 0:000> ? @rax Evaluate expression: 140728898420864 = 00007ffe`00000080 0:000> dd poi(poi(0x80297b3000+(0x2a6*8))) 00007ffe`00000080 ???????? ???????? ???????? ???????? 0:000> dd (poi(0x80297b3000+(0x2a6*8))) 00000080`29505a78 00000080 00007ffe 00000000 c0c0c0c0 but 4 bytes before we have a valid pointer: 0:000> dd (poi(0x80297b3000+(0x2a6*8)))-4 00000080`29505a74 29505a08 00000080 00007ffe 00000000 00000080`29505a84 c0c0c0c0 2966cec0 00000080 0000006f 0:000> ? poi(00000080`29505a74) Evaluate expression: 550448945672 = 00000080`29505a08 0:000> db poi(00000080`29505a74) 00000080`29505a08 18 0f ae 29 80 00 00 00-fe 7f 00 00 00 00 00 00 ...)............ 00000080`29505a18 c0 c0 c0 c0 c0 ce 66 29-80 00 00 00 00 00 00 00 ......f)........
在此示例中,包含调用目标的内存地址为0x0000008029505a78,但是sub_142B0写入了指向0x0000008029505a74的指针,二者相差了4个字节。
# writing to mem rbx=0x0000008029505a74 [rbx]=0x8bad6200abcd0068 [rbx+4]=0x00007ffe8bad6200 value=0x0000008029505a08
v-table的其余部分似乎没有损坏,所有其他的条目都有效:
... [index 0x29f] dump: addr=0x0000008022d822ce value=0x00007ffe8bad1400 [index 0x2a0] dump: addr=0x0000008022d8214a value=0x00007ffe8bad1400 [index 0x2a1] dump: addr=0x0000008022d8220c value=0x00007ffe8bad1400 [index 0x2a2] dump: addr=0x0000008022d81fc6 value=0x00007ffe8bad1400 [index 0x2a3] dump: addr=0x0000008022d82088 value=0x00007ffe8bad1400 [index 0x2a4] dump: addr=0x0000008022d82390 value=0x00007ffe8bad1400 [index 0x2a5] dump: addr=0x0000008022d81f04 value=0x00007ffe8bad1400 [index 0x2a6] dump: addr=0x0000008029505a78 value=0x00007ffe00000080 *BAD*
并且所有条目似乎都指向正确的函数位置:
0:000> u poi(0x00007ffe8bad1400) igdusc64!USC::CShaderInputDecl::GetVertexIDRegisterNum+0x29f0: 00007ffe`8b5948b0 48895c2408 mov qword ptr [rsp+8],rbx 00007ffe`8b5948b5 57 push rdi 00007ffe`8b5948b6 4883ec20 sub rsp,20h
堆内存自身似乎也没有损坏。我们目前暂不清楚攻击者这种“有限的”控制是否足以利用这一漏洞完全实现代码执行,但不能排除这一可能性。
三、远程拒绝服务漏洞(CVE-2018-12153)
3.1 概述
在适用于Intel图形加速器(10.18.14.4889版本)的Intel Unified Shader编译器存在一个可以利用的拒绝服务漏洞。特定的着色器文件(二进制或文本形式)可能会触发此漏洞。攻击者可以从VMWare Guest虚拟机触发这一漏洞,同时主机上的vmware-vmx.exe进程将会崩溃。
3.2 测试环境
· Windows 8.1 x64 操作系统
· VMWare Workstation 14(14.0.0 build-6661328)
· Intel igdusc64.dll 10.18.14.4889(x64)
· 其中Guest VM操作系统为Windows 8.1 x64
3.3 漏洞详情
攻击者可以通过向Intel igdusc64.dll驱动程序提供格式错误的像素着色器(文本或二进制形式)来触发此漏洞。该攻击可以从本地计算机(用户模式)、VMWare Guest用户模式(导致VMWare主机发生内存损坏)触发。理论上,也可以通过WEBGL(远程网页)触发,前提是浏览器不会使用ANGLE,并且以某种方式向Intel驱动程序提供格式错误的着色器。
在提供特制的着色器文件之后,攻击者可以强制igdusc64.dll使用能够触发异常的参数执行“memcpy_s”函数。在触发异常后,将会强行终止程序,以防止内存损坏。
造成这一问题的最根本原因是没有正确验证sub483870提供的返回值。该值随后会在sub34BC30中的一个while循环条件里使用。一旦提供了格式错误的着色器,攻击者就可以强制该值为0xFFFFFFFF(-1),从而导致sub34BC30中while的无限循环,每一次循环都将调用一次sub0x1E9A0,其代码片段如下:
.text:000000000001E9E7 lea eax, ds:0[rbx*4] [1] .text:000000000001E9EE mov ecx, eax ; Size (32bit value) .text:000000000001E9F0 mov r14d, eax .text:000000000001E9F3 call malloc .text:000000000001E9F8 mov rbp, rax .text:000000000001E9FB test rax, rax .text:000000000001E9FE jz short loc_1EA3B .text:000000000001EA00 mov r8d, r14d ; Size .text:000000000001EA03 xor edx, edx ; Val .text:000000000001EA05 mov rcx, rax ; Dst .text:000000000001EA08 call memset .text:000000000001EA0D mov r8, [rsi+18h] ; Src .text:000000000001EA11 test r8, r8 .text:000000000001EA14 jz short loc_1EA31 .text:000000000001EA16 mov r9d, [rsi+20h] ; src size (count) 32-bit value .text:000000000001EA1A mov edx, r14d ; DstSize .text:000000000001EA1D mov rcx, rbp ; Dst .text:000000000001EA20 shl r9, 2 ; src size << 2 -> extended to 64-bits [2] .text:000000000001EA24 call memcpy_s ; memcpy_s( .text:000000000001EA24 ; void *dest, .text:000000000001EA24 ; size_t destSize, .text:000000000001EA24 ; const void *src, .text:000000000001EA24 ; size_t count .text:000000000001EA24 ; ) .text:000000000001EA24 ; .text:000000000001EA24 ; .text:000000000001EA24 ; rcx - dest .text:000000000001EA24 ; rdx - dest size .text:000000000001EA24 ; r8 - src .text:000000000001EA24 ; r9 - src size (count)
请注意,在[1]的位置,LEA指令用于计算malloc调用的最终大小。这一过程是通过将RBX寄存器乘以4,后将结果截取前32位值(随后存储在ECX / R14D中)来完成的。如我们所见,0x1EA20处的指令负责计算memcpy_s函数的源大小(计数)参数。初始的32位值取自[rsi+0x20]存储器,然后在[2]的位置进行了左移,进行这一操作后所得的结果就不再是32位值,而是上升到了64位,该值存储在R9寄存器中。
通过提供格式错误的像素着色器,攻击者可以强制Intel igdusc64.dll驱动程序分配大小为0的内存。由于32位长度的限制,传递给malloc的参数将为0。但是,传递到memcpy_s函数的src大小(计数)参数与之相比要大得多(0x0000000080000000)。一旦使用了正常的memcpy函数,就会导致内存损坏。在使用memcpy函数之后,错误的参数将被删除,并且会抛出异常,最终导致应用程序终止。
... before memcpy_s: [i=33] rcx(dest)=0x0000001ddcea7040 rdx(dest_size)=0x10000000 r8(src)=0x0000001dd4e95040 r9(count)=0x0000000008000000 [rsi+20h]=0x02000000 after memcpy_s: returned 0x00000000 przed memcpy_s: rbx=0x0000000008000000 eax=rbx*4=0x20000000 before memcpy_s: [i=34] rcx(dest)=0x0000001d8000c040 rdx(dest_size)=0x20000000 r8(src)=0x0000001ddcea7040 r9(count)=0x0000000010000000 [rsi+20h]=0x04000000 after memcpy_s: returned 0x00000000 przed memcpy_s: rbx=0x0000000010000000 eax=rbx*4=0x40000000 before memcpy_s: [i=35] rcx(dest)=0x0000001dccf1d040 rdx(dest_size)=0x40000000 r8(src)=0x0000001d8000c040 r9(count)=0x0000000020000000 [rsi+20h]=0x08000000 after memcpy_s: returned 0x00000000 przed memcpy_s: rbx=0x0000000020000000 eax=rbx*4=0x80000000 before memcpy_s: [i=36] rcx(dest)=0x0000001e0cf2a040 rdx(dest_size)=0x80000000 r8(src)=0x0000001dccf1d040 r9(count)=0x0000000040000000 [rsi+20h]=0x10000000 after memcpy_s: returned 0x00000000 przed memcpy_s: rbx=0x0000000040000000 eax=rbx*4=0x00000000 before memcpy_s: [i=37] rcx(dest)=0x0000001dccad8af0 rdx(dest_size)=0x00000000 r8(src)=0x0000001e0cf2a040 r9(count)=0x0000000080000000 [rsi+20h]=0x20000000 0:000> g (41c8.26d0): Security check failure or stack buffer overrun - code c0000409 (!!! second chance !!!) igdusc64!USC::DeleteCompilerOutputPixelShaderOpenGL_impl<USC::SCompilerOutputPixelShaderOpenGL_Gen9>+0x2323: 00007ffc`013697c3 cd29 int 29h
四、远程拒绝服务漏洞(CVE-2018-12154)
4.1 概述
在适用于Intel图形加速器(10.18.14.4889版本)的Intel Unified Shader编译器存在一个可以利用的指针损坏漏洞。特定的像素着色器可能会产生死循环,从而导致拒绝服务。攻击者可以从VMWare Guest虚拟机触发此漏洞,该虚拟机可以影响VMWare主机从而导致vmware-vmx.exe大量消耗CPU资源,造成系统无响应。
4.2 测试环境
· Windows 8.1 x64 操作系统
· VMWare Workstation 14(14.0.0 build-6661328)
· Intel igdusc64.dll 10.18.14.4889(x64)
· 其中Guest VM操作系统为Windows 8.1 x64
4.3 漏洞详情
攻击者可以通过向Intel igdusc64.dll驱动程序提供格式错误的像素着色器(文本或二进制形式)来触发此漏洞。该攻击可以从本地计算机(用户模式)、VMWare Guest用户模式(导致VMWare主机发生内存损坏)触发。理论上,也可以通过WEBGL(远程网页)触发,前提是浏览器不会使用ANGLE,并且以某种方式向Intel驱动程序提供格式错误的着色器。
在一般情况下,即使着色器中包含死循环,它的执行也应该由Watchdog驱动程序终止。针对于没有使用嵌套循环的着色器来说,这一机制是有效的。因此,像下面例子中这样的像素着色器,尽管理论上for循环会一直持续,但实际上并不会在Intel igdusc64.dll驱动程序中引发任何问题。
void main( void ) { float val; for(float i=0.0; i!=0.1; i+=0.0) val = val+0.000001; gl_FragColor += val; }
然而,当使用由嵌套循环(其中一个是无限循环)组成的着色器时,情况就变得不一样了:
void main( void ) { for(int i = 0; i < 1; i++) { for(int j = 0; j < 1; j += 0) { gl_FragColor += float(i); } } }
由于这一过程中永远不会遇到第二个循环条件,因此该循环将会一直运行,导致igdusc64.dll驱动程序无限次数的执行以下代码:
.text:00000000004FC850 loc_4FC850: ; CODE XREF: forever_loop_x+FB°j .text:00000000004FC850 mov rdx, [rdx+2E8h] ; forever loop .text:00000000004FC857 cmp [rdx+18h], r8d ; [rdx+0x18] -> always -1, != r8d .text:00000000004FC85B ja short loc_4FC850 ; always taken
这将导致主机上CPU资源消耗过多,并且基本上会使得进程无响应。因此,如果使用的是虚拟机,那么整个虚拟机都将没有响应。
五、总结
这些可能会导致虚拟机直接实现宿主机逃逸的漏洞非常隐蔽,其危害也不仅仅在于暴露目标系统。通过WebGL的远程攻击方法进一步增加了漏洞所带来的风险,并且为攻击者提供了更多样的攻击方式。