- 55
- 61
Сегодня я вам поведаю об очень интересной уязвимости, которая эксплуатировалось шпионским ПО Pegasus, стало скучно, почему бы и в оффтоп не написать что-то... В ней есть одна деталь, которая реализована невероятно здорово... У нее была очень красивая реализация. Для тех времен это было невероятно сладко. Там была уязвимость целочисленного переполнения.
Фреймворк для 2D-рендеринга в iOS.
Для 2D-рендеринга в iOS используется фреймворк CoreGraphics, Собственно внутри себя данная библиотека еще и тащит код открытого проекта xPdf, древнего опенсорсного парсера документов ,из которого инженеры Apple аккуратно вырезали синтаксический анализатор и парсер шрифтов. Вместо того чтобы по-человечески развивать PDF-движок или вкладываться в опенсорс, Apple просто форкнула старый Си-шный код начала нулевых, намертво зашила его в закрытый фреймворк. Главная уязвимость скрывалась именно в части этого самого xPdf, заключалась она, как я упомянул выше - в целочисленном переполнении -
Objective-C:
Guint numSyms; // (1)
numSyms = 0;
for (i = 0; i < nRefSegs; ++i) {
if ((seg = findSegment(refSegs[i]))) {
if (seg->getType() == jbig2SegSymbolDict) {
numSyms += ((JBIG2SymbolDict *)seg)->getSize(); // (2)
} else if (seg->getType() == jbig2SegCodeTable) {
codeTables->append(seg);
}
} else {
error(errSyntaxError, getPos(),
"Invalid segment reference in JBIG2 text region");
delete codeTables;
return;
}
}
...
// get the symbol bitmaps
syms = (JBIG2Bitmap **)gmallocn(numSyms, sizeof(JBIG2Bitmap *)); // (3)
kk = 0;
for (i = 0; i < nRefSegs; ++i) {
if ((seg = findSegment(refSegs[i]))) {
if (seg->getType() == jbig2SegSymbolDict) {
symbolDict = (JBIG2SymbolDict *)seg;
for (k = 0; k < symbolDict->getSize(); ++k) {
syms[kk++] = symbolDict->getBitmap(k); // (4)
}
}
}
}
MAIN
В общем. В версии iOS 14 была уязвимость, а конкретно внутри метода [IMGIFUtils copyGifFromPath:toDestinationPath:error], который крутился в процессе IMTranscoderAgent ( в iMessage есть нативная поддержка GIF-анимации. Присланная в чат гифка воспроизводится в цикле бесконечно. Как только iMessage получает сообщение, еще до его вывода на экран вызывается метод в процессе ).
Собственно, в этом методе случился один косяк с логикой. По идее функция должна была просто взять и скопировать файл гифки с одного места в другое, но вместо обычного копирования байтов этот метод под капотом запускал полноценный рендеринг через определенные системные библиотеки. Система забивала на то, что у файла расширение .gif, и лезла проверять его реальный формат. А те, кто эксплуатировал это - подсовывали туда PDF, внутри которого был зашит поток JBIG2 - мега-древний кодек из 90-х для сжатия чёрно-белых факсов. Сам же транскодер занимается тем, что перекодирует файлы и оптимизирует их размер, чтобы айфон не умер от нехватки памяти, когда в чат отправляется пачка тяжелых картинок или видео. Т.е взять медиафайл , сжать его, подогнать под нужный формат экрана и сделать так, чтобы всё это красиво отображалось в интерфейсе.
Транскодер запускал парсер для этого мамонта, и там был баг целочисленного переполнения. Выше упомянул.
А теперь касаемо гениальной идеи. Сам же кодек JBIG2 умеет сжимать картинки без потерь, применять к пикселям логические операторы ( XOR, AND, XNOR ). Авторы атаки поступили по-настоящему имхо изысканно. Они отправили 70 000 мелких команд рендеринга. Каждая из них не рисовала картинку, а выполняла математическую операцию над битами в памяти. И из этих 70 тысяч логических вентилей они, прямо внутри парсера, собрали полноценный виртуальный ПК с собственными регистрами и 64-битным сумматором... А дальше уже выход из песочницы и загрузка основного модуля.
JBIG2
Текстовый документ, особенно написанный на языках с небольшими алфавитами (английский или, к примеру, русский), состоит из множества часто встречающихся символов. Вместе буквы, диакритику, знаки препинания и прочие загогулины называют глифами. JBIG2 пытается сегментировать каждую страницу на глифы, а затем использует простое сопоставление с образцом, чтобы выделить глифы, которые выглядят одинаково -
Все. Пока.