CVE-2022-32932 是我在 ANE 内核接口中发现的另一个漏洞;这是一个双重获取问题,导致了一个有趣的越界写入。
如果 model.hwx 具有可变的程序(mutable procedure)并且还包含 initInfo 节区,则会调用 H11ANEIn::patchMutableSurface()(可从 H11ANEIn::ANE_ProgramSendRequest_gated 到达)。我寻找过这样的模型,但一个也没找到,所以最终我修补了其中一个预编译模型,并使用 CVE-2022-32845 来加载它。请记住,从默认应用沙盒到达易受攻击的代码路径并不需要 CVE-2022-32845,只需编译一个自定义 mlmodel 即可达到相同效果。你可以在我的幻灯片中找到关于 CVE-2022-32845 的更多细节。
ZinComputeProgramUpdateMutables() 是另一个由 H11ANEIn::patchMutableSurface() 调用的函数,其函数原型如下:
ZinComputeProgramStatus __cdecl ZinComputeProgramUpdateMutables(
uint64_t procedureId,
const ZinComputeProgramInitInfo *init_info,
const ANECMutableProcedureInfo *mutable_procedure_info,
uint64_t mut_procedure_info_size,
void *MUTK_kernel_section,
uint64_t MUTK_kernel_section_size);
init_info: 是包含序列化输入的 initInfo 节区,你可以在 weightBufs 漏洞利用源码中找到序列化函数 serialize_initinfo_section()。mutable_procedure_info : 是由攻击者提供的共享 IOSurface 缓冲区,在 weightBufs 漏洞利用中也称为 weightsBuffer。mut_procedure_info_size: 表示 mutable_procedure_info 表面缓冲区的大小。MUTK_kernel_section:(或 MUTK)是 IOSurface 对象的映射缓冲区,由内核在程序加载阶段创建。MUTK_kernel_section_size: 是可变内核节区的大小。
第 88-92 行的循环计算 mutable_procedure_info 对象中 MutableWeight 对象的数量,然后在第 93 行计算 MutableWeight 数组的分配大小。之后,在第 100 行分配 ANECMutableWeight 对象数组,然后在第 111-127 行的循环中通过 ANECGetMutableWeight() 以相应的权重缓冲区/大小对填充该数组。
ANECGetMutableOperationInfo() 从我们的共享内存中返回一个 opsInfo 对象:
opsInfo *__fastcall ANECGetMutableOperationInfo(const ANECMutableProcedureInfo *MutableProcedureInfo, unsigned int id)
{
unsigned int weight_buffer_size; // w8
opsInfo *opInfo; // x0
weight_buffer_size = MutableProcedureInfo->header.weight_buffer_size;
if ( !weight_buffer_size )
return 0LL;
opInfo = (opsInfo *)((char *)MutableProcedureInfo + MutableProcedureInfo->wb_offsets[id]);
while ( opInfo->op_index != id )
{
if ( !--weight_buffer_size )
return 0LL;
}
return opInfo;
}
ANECGetMutableWeight 伪代码如下:
void __fastcall ANECGetMutableWeight(
const ANECMutableProcedureInfo *procedure_info,
weightInfo *a2,
ANECMutableWeight *a3)
{
uint64_t wi_size; // x9
wi_size = a2->wi_size;
a3->_weightBuf = (char *)procedure_info + a2->wi_off;
a3->_weightBufSize = wi_size;
}
ANECGetMutableWeightInfo 伪代码如下:
weightInfo *__fastcall ANECGetMutableWeightInfo(
const ANECMutableProcedureInfo *MutableProcedureInfo,
opsInfo *a2,
unsigned int a3)
{
if ( a2->op_count <= a3 )
return 0LL;
else
return (weightInfo *)((char *)MutableProcedureInfo + a2->op_offsets[a3]);
}
我已经在“Attacking Apple’s Neural Engine”幻灯片中描述了 ANECMutableProcedureInfo 的格式,如果你还没读过,请随意阅读。结构体定义可以在 weightBufs 漏洞利用的 'aneProgram.h' 中找到。
如果你已经注意到,ANECGetMutableOperationInfo()->op_count 会被获取两次:一次用于计算分配 ANECMutableWeight 数组所需的大小,另一次用于填充该数组。
由于 mutable_procedure_info 缓冲区是共享内存,攻击者可以使用单独的线程在第一次和第二次使用之间更改 opsInfo->op_count 的值,从而导致大小不匹配,并最终在 kalloc var 区域、kheap defaul 或内核映射中造成有趣的越界写入。
该漏洞可以以许多有趣的方式被利用。例如,攻击者可以在第 93 行将 total_count 设置为 0x1000,然后将 opsInfo->count 增大到更大的值,导致数据在 ANECGetMutableWeight() 中被越界复制。
如果越界写入到达了未映射的内存区域,内核将在下面所示的指令处 panic:
com.apple.driver.AppleH11ANEInterface:__text:FFFFFE0008913D08 EXPORT _ANECGetMutableWeight
com.apple.driver.AppleH11ANEInterface:__text:FFFFFE0008913D08 _ANECGetMutableWeight ; CODE XREF: _ZinComputeProgramUpdateMutables+270↓p
com.apple.driver.AppleH11ANEInterface:__text:FFFFFE0008913D08 LDP X8, X9, [X1,#8]
com.apple.driver.AppleH11ANEInterface:__text:FFFFFE0008913D0C ADD X8, X0, X8
com.apple.driver.AppleH11ANEInterface:__text:FFFFFE0008913D10 STP X8, X9, [X2] // <---- Kernel panic
com.apple.driver.AppleH11ANEInterface:__text:FFFFFE0008913D14 RET
这个漏洞提供了一个强大的原语,因为它写入两个 64 位值:一个指向我们用户共享缓冲区的内核地址,以及一个(半)任意的 64 位值。
概念验证留给读者作为练习。不过,weightBufs 漏洞利用包含了到达易受攻击代码路径所需的一切。祝你好运 :-)。