Microsoft Hyper-V虚拟TPM设备漏洞分析

写在前面

2023年10月微软发布的安全更新中,修复了2个由笔者报送的Hyper-V虚拟TPM设备漏洞。


本次修复的Hyper-V虚拟TPM组件的漏洞可以通过远程访问虚拟机的方式触发漏洞,造成宿主机拒绝服务或者远程代码执行,对宿主机上的其他虚拟机或业务造成损失。


01
背景介绍

Hyper-V的虚拟TPM组件旨在为虚拟机提供模拟的TPM设备,虚拟TPM设备可以为依赖TPM设备的服务或者操作系统(例如Windows 11)提供支持。


漏洞位于vmsp.exe进程中的TpmEngUM.dll二进制文件中,本次介绍的两个虚拟TPM组件的漏洞就是位于TpmEngUM.dll这个二进制文件中。


vmsp.exe进程与vmwp.exe进程相似,都是一个虚拟机实例启动一个进程。但是不同的是vmsp.exe进程是隔离用户模式(IUM)进程,也就是说vmsp.exe进程无法在windows用户态下被正常attach。所以在调试上,针对vmsp.exe进程的调试就需要额外的“手脚”,这里我们引用Quarkslab博客的文章《Debugging Windows Isolated User Mode (IUM) Processes》,感兴趣的读者可以去了解并实践下,这里不做讨论。


02
环境搭建

虚拟TPM组件漏洞的触发需要在Hyper-V虚拟机设置中的“安全”设置中,勾选“启用受信任的平台模块”。


Microsoft Hyper-V虚拟TPM设备漏洞分析


03

漏洞分析CVE-2023-36717

该漏洞是一个拒绝服务漏洞,当这个漏洞被触发时会导致宿主机vmsp.exe进程进入死循环,并占用大量CPU计算资源。由于vmsp.exe进程是IUM进程,所以当漏洞被触发后,管理员无法从用户态结束掉这个进程,这种情况下除非重启宿主机操作系统否则计算资源一直无法被释放。

这个漏洞位于TpmEngUM!TPM2_ECDH_KeyGen函数中。

__int64 __fastcall TPM2_ECDH_KeyGen(unsigned int *a1, __int64 a2){  OBJECT *v3; // rax  OBJECT *v4; // rsi  unsigned int v5; // eax  unsigned int v6; // ebx  unsigned __int16 v8[28]; // [rsp+20h] [rbp-58h] BYREF
v3 = ObjectGet(*a1); v4 = v3; if ( v3->public_type != 0x23 || (v3->public_objectAttributes & 0x10000) != 0 || (v3->public_objectAttributes & 0x20000) == 0 ) { return 0x19Ci64; } while ( !(unsigned __int16)cpri__GetEphemeralEcc( (unsigned __int16 *)(a2 + 104), v8, v4->public_parameters_Detail_keyBits) ) { *(_WORD *)(a2 + 0x66) = TPMS_ECC_POINT_Marshal((_BYTE *)(a2 + 104), 0i64, 0i64); v5 = CryptEccPointMultiply( (_WORD *)(a2 + 2), v4->public_parameters_Detail_keyBits, v8, (__int64)&v4->public_unique_ecc_x); v6 = v5; if ( v5 == 0xA7 ) break; if ( v5 != 0x154 ) goto LABEL_9; } v6 = 156;LABEL_9: if ( !v6 ) *(_WORD *)a2 = TPMS_ECC_POINT_Marshal((_BYTE *)(a2 + 2), 0i64, 0i64); return v6;}

TpmEngUM!TPM2_ECDH_KeyGen函数中v4->public_unique_ecc_x成员可以从Guest中被控制,如果v4->public_unique_ecc_x成员是一个NULL ECC Point的情况下TPM2B_ECC_PARAMETER.size为0x00,并且TPM2B_ECC_PARAMETER.buffer数组被0填充),TpmEngUM!CryptEccPointMultiply会一直返回错误码0x154,并不停的循环调用TpmEngUM!CryptEccPointMultiply函数,最终造成vmsp.exe进程死循环,导致宿主机拒绝服务。


04

漏洞分析CVE-2023-36718

该漏洞是远程代码执行漏洞,当这个漏洞被触发时会使用未初始化的栈空间变量。这个漏洞位于TpmEngUM!CryptSecretEncrypt函数中。

__int64 __fastcall CryptSecretEncrypt(unsigned int a1, _BYTE *a2_plabel, __int64 a3, __int16 *a4){  unsigned int v7; // ebx  OBJECT *v8_obj; // rax  OBJECT *v9_obj; // rdi  unsigned __int16 DigestSize; // ax  unsigned __int16 public_parameters_Detail_keyBits; // cx  __int16 public_nameAlg; // cx  void *v14; // [rsp+40h] [rbp-C0h] BYREF  __int16 v15[28]; // [rsp+48h] [rbp-B8h] BYREF  __int16 v16[56]; // [rsp+80h] [rbp-80h] BYREF  __int16 v17_Z_eccpointaftermul[56]; // [rsp+F0h] [rbp-10h] BYREF
v7 = 0; v8_obj = ObjectGet(a1); v9_obj = v8_obj;
......
DigestSize = cpri__GetDigestSize(v8_obj->public_nameAlg); *(_WORD *)a3 = DigestSize; ......
if ( v9_obj->public_type == 1 ) { ......
} else { if ( v9_obj->public_type != 0x23 ) {
......
} public_parameters_Detail_keyBits = v9_obj->public_parameters_Detail_keyBits; v14 = a4 + 1; if ( (unsigned int)cpri__EccIsPointOnCurve( public_parameters_Detail_keyBits, (__int64)&v9_obj->public_unique_ecc_x) ) { cpri__GetEphemeralEcc((unsigned __int16 *)v16, (unsigned __int16 *)v15, v9_obj->public_parameters_Detail_keyBits); *a4 = TPMS_ECC_POINT_Marshal(v16, &v14, 0i64); if ( (unsigned int)CryptEccPointMultiply( v17_Z_eccpointaftermul, v9_obj->public_parameters_Detail_keyBits, (unsigned __int16 *)v15, (__int64)&v9_obj->public_unique_ecc_x) ) { v7 = 0x9C; } else if ( BitIsSet((unsigned __int16)v9_obj->public_nameAlg, (__int64)&g_toTest, 9u) ) { public_nameAlg = v9_obj->public_nameAlg; if ( public_nameAlg != 0x10 ) TestAlgorithm(public_nameAlg, 0i64); } cpri__KDFe( v9_obj->public_nameAlg, (unsigned __int16 *)v17_Z_eccpointaftermul, a2_plabel, (unsigned __int16 *)v16, (unsigned __int16 *)&v9_obj->public_unique_ecc_x, 8 * *(unsigned __int16 *)a3, (_BYTE *)(a3 + 2)); } else { return 0x9C; } } return v7;}


上面代码中的v17_Z_eccpointaftermul是一个栈上的数组(也可能是个结构体),v17_Z_eccpointaftermul的大小是0x70字节。代码中的v9_obj->public_unique_ecc_x成员可以从Guest中被控制,当v9_obj->public_unique_ecc_x成员是一个NULL ECC Point的情况下(TPM2B_ECC_PARAMETER.size为0x00,并且TPM2B_ECC_PARAMETER.buffer数组被0填充),TpmEngUM!CryptEccPointMultiply函数会返回一个错误码并将v7设置为0x9C。


设置完v7的值之后,程序继续走到要调用TpmEngUM!cpri__KDFe函数这里,此时v17_Z_eccpointaftermul是一个栈上未初始化的数组,并作为TpmEngUM!cpri__KDFe函数的第二参数进入到之后的TpmEngUM!cpri__KDFe函数的代码流程里。


TpmEngUM!cpri__KDFe函数后续的代码流程中,使用了未初始化的栈上的数据,导致越界读或者内存损坏。下面是崩溃时的现场:

(4afc.2f4c): Access violation - code c0000005 (first chance)First chance exceptions are reported before any exception handling.This exception may be expected and handled.TpmEngUM!SymCryptSha512AppendBlocks_ull+0xa7:00007ffb`38d9a42f 4d8b41f0        mov     r8,qword ptr [r9-10h] ds:00000000`00153ffe=????????????????0:000> k # Child-SP          RetAddr           Call Site00 00000000`0014ec80 00007ffb`38d99e01 TpmEngUM!SymCryptSha512AppendBlocks_ull+0xa701 00000000`0014eed0 00007ffb`38d99e59 TpmEngUM!SymCryptSha512Append+0x9502 00000000`0014ef10 00007ffb`38d87724 TpmEngUM!SymCryptSha384Append+0x903 00000000`0014ef40 00007ffb`38d66cd7 TpmEngUM!cpri__KDFe+0x1a404 00000000`0014f110 00007ffb`38d7c7cd TpmEngUM!CryptSecretEncrypt+0x14305 00000000`0014f2c0 00007ffb`38d70a54 TpmEngUM!TPM2_MakeCredential+0x7d06 00000000`0014f340 00007ffb`38d61c54 TpmEngUM!CommandDispatcher+0xa7807 00000000`0014f420 00007ffb`38d61313 TpmEngUM!ExecuteCommand+0x46008 00000000`0014f530 00000001`400c3862 TpmEngUM!VTpmExecuteCommand+0x73


05

总 结

借助此文简单的介绍了下Hyper-V虚拟TPM组件的两个漏洞,可以发现这两个漏洞都是Hyper-V虚拟TPM组件在处理Guest数据时发生了错误导致宿主机进程受到了影响。通过本文帮助读者更好地理解虚拟TPM组件漏洞的成因,以及希望能够在TPM组件的漏洞挖掘工作中帮到大家。







【版权说明】

本作品著作权归HongZhenhao所有

未经作者同意,不得转载。

Microsoft Hyper-V虚拟TPM设备漏洞分析
HongZhenhao

天工实验室安全研究员

专注于Windows、云、虚拟化领域漏洞挖掘。

曾多次获得微软 MSRC 最高漏洞赏金,荣登2019,2020,2022 微软MSRC全球最具价值安全精英榜。连续两年BlackHat USA世界黑帽大会Speaker。


Microsoft Hyper-V虚拟TPM设备漏洞分析
点击下方的卡片关注我们吧!

原文始发于微信公众号(破壳平台):Microsoft Hyper-V虚拟TPM设备漏洞分析

版权声明:admin 发表于 2023年10月25日 上午10:00。
转载请注明:Microsoft Hyper-V虚拟TPM设备漏洞分析 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...