Áª·¢¿ÆоƬRootkit©¶´·ÖÎö£¨CVE-2020-0069£©

Ðû²¼Ê±¼ä 2020-06-24

Ò»¡¢Â©¶´Åä¾°


2020Äê3Ô£¬¹È¸èÐÞ²¹ÁËÒ»¸ö´æÔÚÓÚÁª·¢¿ÆоƬÖеÄÄþ¾²Â©¶´£¨CVE-2020-0069£©£¬Â©¶´Ó°Ïì20Óà¿îÁª·¢¿ÆоƬºÍÊý°ÙÍòAndroidÉ豸¡£¸Ã©¶´´æÔÚÓÚMediaTek Command QueueÇý¶¯£¨CMDQÃüÁîÐÐÁÐÇý¶¯£©£¬ÔÊÐíµ±µØ¹¥»÷ÕßʵÏÖ¶ÔÎïÀíÄÚ´æµØÖ·µÄÈÎÒâ¶Áд£¬´Ó¶øµ¼ÖÂȨÏÞÌáÉý¡£


¶þ¡¢ÊÜÓ°Ïì¹ú²úÊÖ»úÐͺÅ


Huawei GR3 TAG-L21

Huawei Y5II

Huawei Y6II MT6735 series

Lenovo A5

Lenovo C2 series

Lenovo Tab E7

Lenovo Tab E8

Lenovo Tab2 A10-70F

Meizu M5c

Meizu M6

Meizu Pro 7 Plus

Oppo A59 series

Oppo A5s

Oppo A7x -- up to Android 8.x

Oppo F5 series/A73 -- up to A.39

Oppo F7 series -- Android 8.x only

Oppo F9 series -- Android 8.x only

Oppo R9xm series

Xiaomi Redmi 6/6A series

ZTE Blade A530

ZTE Blade D6/V6

ZTE Quest 5 Z3351S


Èý¡¢CMDQÇý¶¯¼òÎö


DMA£¨Ö±½ÓÄÚ´æ·ÃÎÊ£©ÊÇÔÊÐíרÓÃÓ²¼þÖ±½Ó´ÓÖ÷´æ´¢Æ÷(RAM)·¢ËÍ»ò½ÓÊÕÊý¾ÝµÄÒ»ÖÖÌØÐÔ¡£ÆäÄ¿µÄÊÇͨ¹ýÔÊÐí´óÄÚ´æ·ÃÎʶø²»Íâ¶àÕ¼ÓÃCPUÀ´¼ÓËÙϵͳ¡£MediaTek Command QueueÇý¶¯(CMDQÃüÁîÐÐÁÐÇý¶¯)ÔÊÐí´ÓÓû§²ãÓëDMA¿ØÖÆÆ÷ͨÐÅ£¬ÒÔʵÏÖýÌå»òÏÔʾÏà¹ØµÄÈÎÎñ¡£


»ùÓÚRedmi 6/6A Ô´´úÂë·ÖÎö£¬ÔÚcmdq_driver.hÍ·ÎļþÖУ¬ÉùÃ÷cmdqÇý¶¯µÄIOCTLµ÷ÓÃÈçÏ£º


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


CMDQ_IOCTL_ALLOC_WRITE_ADDRESSÖ¸ÁîΪ·ÖÅäÒ»¸öDMA»º³åÇø¡£

CMDQ_IOCTL_FREE_WRITE_ADDRESSÖ¸ÁîΪÊÍ·ÅÒ»¸öDMA»º³åÇø¡£

CMDQ_IOCTL_READ_WRITE_ADDRESSÖ¸ÁîΪ¶ÁÈ¡Ò»¸öDMA»º³åÇøÖеÄÊý¾Ý¡£

CMDQ_IOCTL_EXEC_COMMANDÖ¸ÁîÔËÐз¢ËÍÆäËûÃüÁî¡£


1¡¢·ÖÅä¹ý³Ì


ͨ¹ýCMDQ_IOCTL_ALLOC_WRITE_ADDRESSµ÷ÓÃcmdqCoreAllocWriteAddress ()º¯Êý£¬·ÖÅäÒ»¸öDMA»º³åÇø£¬¸Ãº¯ÊýÒªº¦´úÂëʵÏÖÈçÏ£º


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


È»ºó£¬µ÷ÓÃcmdq_core_alloc_hw_buffer()º¯Êý·ÖÅäDMA»º³åÇø£¬pWriteAddr->vaÊÇÐéÄâµØÖ·£¬pWriteAddr->paΪÎïÀíµØÖ·£¬Á½ÕßÒ»Ò»¶ÔÓ¦¡£²¢ÇåÀí»º³åÇø¡£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


×îºó£¬½«ÎïÀíµØÖ·¸³Öµµ½*paStart£¬²¢½«pWriteAddr½á¹¹ÌåÌí¼Óµ½gCmdqContext.writeAddrListÁ´±íÖС£


2¡¢Ö´ÐÐÃüÁî¹ý³Ì


ÔÚCMDQ_IOCTL_EXEC_COMMANDµ÷ÓÃÖУ¬½ÓÄÉcmdqCommandStruct½á¹¹Ìå×÷Ϊ²ÎÊý£¬½á¹¹Ìå½ç˵ÈçÏ£º


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


pVABaseÖ¸ÏòÓû§²ã´æ·ÅÃüÁîµÄ»º³åÇø£¬»º³åÇø¾Þϸ·ÅÔÚblockSizeÖС£ÆäÖÐcmdqReadAddressStruct½á¹¹Ìå½ç˵ÈçÏ£º


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


DmaAddressesÊÇÒª¶ÁÈ¡µÄÎïÀíµØÖ·£¬¶ÁÈ¡µÄÖµ´æ·ÅÔÚvaluesÖС£ÔÚCMDQ_IOCTL_EXEC_COMMANDÃüÁîµÄÖ´Ðйý³Ì£¬ÊµÏÖ´úÂëÈçÏ£º


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


º¯Êýµ÷Ó÷¾¶ÈçÏ£º


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


Cmdq_core_acquire_task()º¯Êý»á½«command°ó¶¨µ½taskÖÐÖ´ÐС£¾ßÌåʵÏÖÈçÏ£º


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


µ÷ÓÃcmdq_core_find_free_task()º¯Êý»ñÈ¡Ò»¸ö¿ÕÏÐtask¡£Äõ½¿ÕÏÐtask²¢½øÐÐһЩ³õʼ»¯ÉèÖã¬È»ºó¿ªÊ¼µ÷ÓÃcmdq_core_insert_read_reg_command()º¯ÊýÖ´ÐÐÃüÁî¡£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


¸Ãº¯ÊýʵÏÖ·ÖÎö£¬ÏÈ¿½±´Óû§²ã´«ÈëµÄÃüÁîµ½DMA»º³åÇøÖС£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


pCommandDesc->pVABaseÊÇ´æ·ÅÃüÁîµÄÄÚ´æÆðʼµØÖ·¡£¿½±´ÍêÃüÁîºó£¬ºóÃæ·Ö¼¸ÖÖ·½Ê½½áβ¡£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾

ÕâÀï²»×öÉ£¬×îºó¿½±´EOCºÍJUMPÖ¸Áî½áβ¡£ÕâÀïÒ²Êǽ«Óû§²ã´«ÈëµÄÃüÁ±´¹ýÀ´¡£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


´Ócmdq_core_acquire_task()º¯ÊýÖзµ»Øºó£¬ÈçÏ£º


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


µ÷ÓÃcmdq_core_consume_waiting_list()º¯ÊýÖ´ÐÐtask¡£ÏÈ´ÓÆÚ´ýÐÐÁÐÖлñÈ¡task¡£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


È»ºó£¬»ñÈ¡¿ÕÏÐÄÚºËÏ̡߳£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


×îºó£¬½«task°ó¶¨µ½threadÖÐÈ¥Ö´ÐС£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


ËÄ¡¢¶ÁдÃüÁî·ÖÎö


ÒÔcmdq_test.c²âÊÔ´úÂëΪÀý£¬·ÖÎöÀí½âÒ»¸öÍêÕûµÄ¶ÁдÃüÁî½á¹¹¡£cmdqÇý¶¯Öнç˵ÁËÁ½Àà¼Ä´æÆ÷£¬Ò»ÀàÊǵØÖ·¼Ä´æÆ÷ÓÃÓÚ´æ·ÅµØÖ·£¬Ò»ÀàÊÇÊýÖµ¼Ä´æÆ÷ÓÃÓÚ´æ·Å¶ÁÈ¡»òдÈëµÄÊýÖµ¡£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


regResultsÊÇÐéÄâµØÖ·£¬µ÷ÓÃcmdq_core_alloc_hw_buffer()º¯Êý·ÖÅäÒ»¸ödmaµØÖ·£¬regResultsMVAÓëÖ®¶ÔÓ¦£¬È»ºóÉèÖÃregResultsÖеÄÊý¾Ý¡£¿ªÊ¼Æ´½Ó¶ÁÈ¡ºÍдÈëÃüÁ


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


½«regResults[0]µÄµØַдÈëCMDQ_DATA_REG_DEBUG_DSTÀàÐ͵ĵØÖ·¼Ä´æÆ÷ÖС£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


È»ºó£¬´ÓCMDQ_DATA_REG_DEBUG_DSTµØÖ·¼Ä´æÆ÷ÖжÁÈ¡Êý¾Ý²¢Ð´Èëµ½CMDQ_DATA_REG_DEBUGÊýÖµ¼Ä´æÆ÷ÖС£Õâʱºò£¬CMDQ_DATA_REG_DEBUGÊýÖµ¼Ä´æÆ÷ÖеÄÖµÓ¦¸ÃΪ0xdeaddead¡£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


½Ó×Å£¬½«regResults[1]µÄµØַת´æµ½CMDQ_DATA_REG_DEBUG_DSTµØÖ·¼Ä´æÆ÷ÖС£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


×îºó£¬½«CMDQ_DATA_REG_DEBUGÊýÖµ¼Ä´æÆ÷ÖеÄ0xdeaddeadдÈëµ½CMDQ_DATA_REG_DEBUG_DSTµØÖ·¼Ä´æÆ÷ÖÐÉú´æµÄregResults[1]µÄµØÖ·ÖУ¬¼´regResults[1]=0xdeaddead¡£ÅжÏregResults[0]ºÍregResults[1]ÊÇ·ñÏàµÈ¡£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


Èç¹ûÏàµÈ£¬ËµÃ÷¶ÁдÀֳɡ£


Îå¡¢PoC·ÖÎöÓë²âÊÔ


£¨1£©PoC´úÂëÖУ¬Ö´ÐÐд²Ù×÷µÄÒªº¦´úÂëÈçÏ£º


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


дÈë¹ý³ÌÖУ¬ÏȽ«value[count]Òƶ¯µ½CMDQ_DATA_REG_DEBUGÊýÖµ¼Ä´æÆ÷ÖУ¬È»ºó½«pa_address+offsetµØÖ·Òƶ¯µ½CMDQ_DATA_REG_DEBUG_DSTµØÖ·¼Ä´æÆ÷ÖУ¬×îºó½«CMDQ_DATA_REG_DEBUGÊýÖµ¼Ä´æÆ÷ÖеÄvalueдÈëµ½CMDQ_DATA_REG_DEBUG_DSTµØÖ·¼Ä´æÆ÷ÖÐÉú´æµÄpa_address+offsetµØÖ·ÖУ¬¼´*(pa_address+offset)= value[count]¡£


£¨2£©PoC´úÂëÖУ¬Ö´ÐжÁ²Ù×÷µÄÒªº¦´úÂëÈçÏ£º


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


¶ÁÈ¡¹ý³ÌÖУ¬µÚÒ»²½ÏȽ«pa_address+offsetµØÖ·Òƶ¯µ½CMDQ_DATA_REG_DEBUG_DSTµØÖ·¼Ä´æÆ÷ÖУ¬È»ºó´ÓCMDQ_DATA__REG_DEBUG_DSTµØÖ·¼Ä´æÆ÷Öд洢µÄµØÖ·pa_address+offsetÖжÁÈ¡Êý¾Ý·Åµ½CMDQ_DATA_REG_DEBUGÊý¾Ý¼Ä´æÆ÷ÖУ¬ÔÙ½«dma_address+offsetµØÖ·Òƶ¯µ½CMDQ_DATA_REG_DEBUG_DSTµØÖ·¼Ä´æÆ÷ÖУ¬×îºó½«CMDQ_DATA_REG_DEBUGÊýÖµ¼Ä´æÆ÷ÖÐÉú´æµÄÊý¾ÝдÈëµ½CMDQ_DATA_REG_DEBUG_DSTµØÖ·¼Ä´æÆ÷Öд洢µÄdma_address+offsetµØÖ·ÖУ¬¼´*(dma_address+ offset) = *(pa_address + offset)¡£


£¨3£©ÔÚReami6²âÊÔ»úÖУ¬Ö´ÐÐPoC²âÊÔ£¬Àֳɽ«LinuxÐ޸ijÉminix¡£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾


²Î¿¼Á´½Ó£º

[1]https://github.com/MiCode/Xiaomi_Kernel_OpenSource/tree/cactus-p-oss/drivers/misc/mediatek/cmdq

[2]https://github.com/quarkslab/CVE-2020-0069_poc/blob/master/jni/kernel_rw.c

[3]https://blog.quarkslab.com/cve-2020-0069-autopsy-of-the-most-stable-mediatek-rootkit.html

[4]https://forum.xda-developers.com/android/development/amazing-temp-root-mediatek-armv8-t3922213

[5]https://source.android.com/security/bulletin/2020-03-01



¶«É­Æ½Ì¨»ý¼«·ÀÓùʵÑéÊÒ£¨ADLab£©


ADLab½¨Á¢ÓÚ1999Ä꣬ÊÇÖйúÄþ¾²ÐÐÒµ×îÔ罨Á¢µÄ¹¥·À¼¼ÊõÑо¿ÊµÑéÊÒÖ®Ò»£¬Î¢ÈíMAPP¼Æ»®ºËÐijÉÔ±£¬¡°ºÚȸ¹¥»÷¡±¿´·¨Ê×ÍÆÕß¡£½ØֹĿǰ£¬ADLabÒÑͨ¹ýCVEÀÛ¼ÆÐû²¼Äþ¾²Â©¶´1000Óà¸ö£¬Í¨¹ý CNVD/CNNVDÀÛ¼ÆÐû²¼Äþ¾²Â©¶´800Óà¸ö£¬Á¬Ðø±£³Ö¹ú¼ÊÍøÂçÄþ¾²ÁìÓòÒ»Á÷Ë®×¼¡£ÊµÑéÊÒÑо¿Æ«Ïòº­¸Ç²Ù×÷ϵͳÓëÓ¦ÓÃϵͳÄþ¾²Ñо¿¡¢Òƶ¯ÖÇÄÜÖÕ¶ËÄþ¾²Ñо¿¡¢ÎïÁªÍøÖÇÄÜÉ豸Äþ¾²Ñо¿¡¢WebÄþ¾²Ñо¿¡¢¹¤¿ØϵͳÄþ¾²Ñо¿¡¢ÔÆÄþ¾²Ñо¿¡£Ñо¿½á¹ûÓ¦ÓÃÓÚ²úÎïºËÐļ¼ÊõÑо¿¡¢¹ú¼ÒÖصã¿Æ¼¼ÏîÄ¿¹¥¹Ø¡¢×¨ÒµÄþ¾²·þÎñµÈ¡£


¶«É­¡¤(ÖйúÇø)¹Ù·½ÍøÕ¾