• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Глубокое погружение в эксплойт iMessage от NSO: удаленное выполнение кода

yashechka

Генератор контента.Фанат Ильфака и Рикардо Нарвахи
Эксперт
Регистрация
24.11.2012
Сообщения
2 344
Реакции
3 563
Авторы: Ян Бир и Сэмюэл Гросс из Google Project Zero

Мы хотим поблагодарить Citizen Lab за то, что они поделились с нами образцом эксплойта FORCEDENTRY, и группу разработки и архитектуры безопасности Apple (SEAR) за сотрудничество с нами в техническом анализе. Приведенные ниже редакционные мнения принадлежат исключительно Project Zero и не обязательно отражают точку зрения организаций, с которыми мы сотрудничали в ходе этого исследования.

Ранее в этом году Citizen Lab удалось зафиксировать эксплойт NSO с zero-click на основе iMessage, который использовался для нападения на саудовского активиста. В этой серии сообщений в нашем блоге, состоящей из двух частей, мы впервые опишем, как работает эксплойт iMessage с zero-click.

Основываясь на наших исследованиях и выводах, мы оцениваем это его как один из самых технически сложных эксплойтов, которые мы когда-либо видели, что еще раз демонстрирует, что возможности, которые предоставляет NSO, конкурируют с теми возможностями, которые ранее считались доступными только для нескольких национальных государств.

Уязвимость, обсуждаемая в этом сообщении в статье, была исправлена 13 сентября 2021 г в iOS 14.8 и имеет имя CVE-2021-30860.

NSO

NSO Group является одним из самых известных поставщиков "access-as-a-service", продавая комплексные хакерские решения, которые позволяют государственным деятелям без собственных наступательных кибер-возможностей "pay-to-play", значительно расширяя количество стран с такими кибервозможностями.

В течение многих лет такие группы, как Citizen Lab и Amnesty International, отслеживали использование мобильного шпионского пакета NSO "Pegasus". Несмотря на заявления NSO о том, что они "[оценивают] возможность неблагоприятного воздействия на права человека в результате неправомерного использования продуктов NSO", Pegasus была связана со взломом журналиста New York Times Бена Хаббарда, взломом правозащитников в Марокко и Бахрейн, нападения на сотрудников Amnesty International и десятки других дел.

В прошлом месяце Соединенные Штаты добавили NSO в "Список организаций", резко ограничив возможности американских компаний вести дела с NSO и заявив в пресс-релизе, что "[инструменты NSO] позволяют иностранным правительствам проводить транснациональные репрессии, что является практикой авторитарных правительств, преследующих диссидентов, журналистов и активистов за пределами своих суверенных границ, чтобы заставить замолчать диссидентов".

Citizen Lab удалось восстановить эти эксплойты Pegasus с iPhone, поэтому данный анализ охватывает возможности NSO в отношении iPhone. Нам известно, что NSO продает аналогичные решения zero-click, предназначенные для устройств Android; У Project Zero нет образцов этих эксплойтов, но если они у вас есть, свяжитесь с нами.

От единицы до нуля

В предыдущих случаях, жертвам отправляли ссылки в SMS-сообщениях:

1641717877336.png


Цель была взломана только тогда, когда она щелкнула ссылку, метод, известный как эксплойт в один клик. Однако недавно было задокументировано, что NSO предлагает своим клиентам технологию эксплойта с без кликом, когда даже очень технически подкованные люди, которые могут не щелкнуть фишинговую ссылку, совершенно не подозревают, что их уже преследуют. В сценарии с zero-click не требуется никакого взаимодействия с пользователем. Это означает, что злоумышленнику не нужно отправлять фишинговые сообщения; эксплойт просто тихо работает в фоновом режиме. За исключением того, что устройство не используется, нет способа предотвратить использование эксплойта с zero-click; это оружие, против которого нет защиты.

Один странный трюк

Начальной точкой входа для Pegasus на iPhone является iMessage. Это означает, что жертва может стать мишенью, просто используя свой номер телефона или имя пользователя AppleID.

iMessage имеет встроенную поддержку изображений GIF, обычно небольших и низкокачественных анимированных изображений, популярных в культуре мемов. Вы можете отправлять и получать GIF-файлы в чатах iMessage, и они отображаются в окне чата. Apple хотела, чтобы эти GIF-файлы зацикливались бесконечно, а не воспроизводились только один раз, поэтому на самом раннем этапе конвейера анализа и обработки iMessage (после получения сообщения, но задолго до его отображения) iMessage вызывает следующий метод в процессе IMTranscoderAgent (вне песочницы "BlastDoor"), передавая любой полученный файл изображения с расширением .gif:

[IMGIFUtils copyGifFromPath:toDestinationPath:error]

Глядя на имя селектора, здесь, вероятно, предполагалось просто скопировать файл GIF перед редактированием поля количества циклов, но семантика этого метода отличается. Под капотом он использует API-интерфейсы CoreGraphics для рендеринга исходного изображения в новый файл GIF по пути назначения. И только потому, что имя исходного файла должно заканчиваться на .gif, это не значит, что это действительно файл GIF.

Библиотека ImageIO, как подробно описано в предыдущей статье Project Zero, используется для угадывания правильного формата исходного файла и его анализа, полностью игнорируя расширение файла. Используя этот трюк с "фальшивым gif", более 20 кодеков изображений внезапно становятся частью поверхности атаки iMessage с zero-click, включая некоторые очень неясные и сложные форматы, удаленно раскрывая, вероятно, сотни тысяч строк кода.

Примечание. Apple сообщает нам, что они ограничили доступные форматы ImageIO, доступные из IMTranscoderAgent, начиная с iOS 14.8.1 (26 октября 2021 г.), и полностью удалили путь кода GIF из IMTranscoderAgent, начиная с iOS 15.0 (20 сентября 2021 г.), с декодированием GIF.

PDF в вашем GIF

NSO использует уловку "fake gif" для обнаружения уязвимости в анализаторе PDF CoreGraphics.

PDF был популярной целью для взлома около десяти лет назад из-за его повсеместного распространения и сложности. Кроме того, наличие javascript внутри PDF-файлов значительно упростило разработку надежных эксплойтов. Парсер CoreGraphics PDF, похоже, не интерпретирует javascript, но NSO удалось найти что-то столь же мощное в парсере CoreGraphics PDF...

Экстремальное сжатие

В конце 1990-х пропускная способность и объем памяти были гораздо более дефицитными, чем сейчас. Именно в этой среде появился стандарт JBIG2. JBIG2 — это доменный кодек изображений, предназначенный для сжатия изображений, в которых пиксели могут быть только черными или белыми.

Он был разработан для достижения чрезвычайно высокой степени сжатия при сканировании текстовых документов и был реализован и использовался в высокопроизводительных офисных сканерах/принтерах, таких как устройство XEROX WorkCenter, показанное ниже. Если вы использовали функцию сканирования в PDF такого устройства десять лет назад, в вашем PDF-файле, вероятно, был поток JBIG2.

1641717970120.png



Файлы PDF, созданные этими сканерами, были исключительно малы, возможно, всего несколько килобайт. Есть два новых метода, которые JBIG2 использует для достижения этих экстремальных коэффициентов сжатия, которые имеют отношение к этому эксплойту:

Техника 1: Сегментация и замена

Практически каждый текстовый документ, особенно написанный на языках с небольшим алфавитом, таких как английский или немецкий, состоит из множества повторяющихся букв (также известных как глифы) на каждой странице. JBIG2 пытается сегментировать каждую страницу на глифы, а затем использует простое сопоставление с образцом для сопоставления глифов, которые выглядят одинаково:

1641717992092.png


JBIG2 на самом деле ничего не знает о глифах и не выполняет OCR (оптическое распознавание символов). Кодер JBIG просто ищет связанные области пикселей и группирует похожие области вместе. Алгоритм сжатия заключается в простой замене всех достаточно похожих областей копией только одной из них:

1641718004645.png


В этом случае выходные данные прекрасно читаются, но объем сохраняемой информации значительно уменьшается. Вместо того, чтобы хранить всю исходную информацию о пикселях для всей страницы, вам нужна только сжатая версия "опорного глифа" для каждого символа и относительные координаты всех мест, где должны быть сделаны копии. Затем алгоритм декомпрессии обрабатывает выходную страницу как холст и "рисует" один и тот же глиф во всех сохраненных местах.

У такой схемы есть существенная проблема: плохой кодировщик слишком легко может случайно поменять местами похожие символы, и это может привести к интересным последствиям. В блоге Криселя есть несколько мотивирующих примеров, когда PDF-файлы отсканированных счетов-фактур имеют разные цифры или PDF-файлы отсканированных строительных чертежей заканчиваются неправильными измерениями. Это не те проблемы, которые мы рассматриваем, но они являются одной из важных причин, по которой JBIG2 больше не является распространенным форматом сжатия.

Техника 2: Уточняющее кодирование

Как упомянуто выше, выходные данные сжатия на основе замещения имеют потери. После раунда сжатия и распаковки визуализированный вывод не выглядит точно так же, как ввод. Но JBIG2 также поддерживает сжатие без потерь, а также промежуточный режим сжатия с меньшими потерями.

Он делает это, также сохраняя (и сжимая) разницу между замененным глифом и каждым исходным глифом. Вот пример, показывающий маску различия между замененным символом слева и исходным символом без потерь в середине:

image3.png


В этом простом примере кодировщик может сохранить разностную маску, показанную справа, затем во время распаковки разностную маску можно подвергнуть операции XOR с замененным символом, чтобы восстановить точные пиксели, составляющие исходный символ. Есть еще несколько приемов, выходящих за рамки этого сообщения в блоге, для дальнейшего сжатия этой разностной маски с использованием промежуточных форм заменяемого символа в качестве "контекста" для сжатия.

Вместо того, чтобы полностью кодировать всю разницу за один раз, это можно сделать поэтапно, при этом каждая итерация использует логический оператор (один из И, ИЛИ, XOR или XNOR) для установки, очистки или перестановки битов. Каждый последующий шаг уточнения приближает визуализированный вывод к оригиналу, что позволяет контролировать степень поретрь при сжатии. Реализация этих шагов уточняющего кодирования очень гибкая, и они также могут "считывать" значения, уже присутствующие на выходном холсте.

Поток JBIG2

Большая часть декодера CoreGraphics PDF, по-видимому, является проприетарным кодом Apple, но реализация JBIG2 взята из Xpdf, исходный код которого находится в свободном доступе.

Формат JBIG2 представляет собой серию сегментов, которую можно рассматривать как серию команд рисования, которые выполняются последовательно за один проход. Анализатор CoreGraphics JBIG2 поддерживает 19 различных типов сегментов, включая такие операции, как определение новой страницы, декодирование таблицы Хаффмана или рендеринг растрового изображения с заданными координатами на странице.

Сегменты представлены классом JBIG2Segment и его подклассами JBIG2Bitmap и JBIG2SymbolDict.

JBIG2Bitmap представляет собой прямоугольный массив пикселей. Его поле данных указывает на резервный буфер, содержащий холст рендеринга.

JBIG2SymbolDict группирует JBIG2Bitmap вместе. Целевая страница представлена в виде JBIG2Bitmap, как и отдельные глифы.

На JBIG2Segments можно ссылаться по номеру сегмента, а векторный тип GList хранит указатели на все JBIG2Segments. Для поиска сегмента по номеру сегмента GList сканируется последовательно.

Уязвимость

Уязвимость представляет собой классическое целочисленное переполнение при сопоставлении ссылочных сегментов:

Код:
  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)
        }
      }
    }
  }

numSyms — это 32-битное целое число, объявленное в (1). Предоставляя тщательно созданные эталонные сегменты, повторное добавление в (2) может привести к переполнению numSyms до контролируемого небольшого значения.

Это меньшее значение используется для размера выделения кучи в (3), что означает, что syms указывает на буфер меньшего размера.

Внутри самого внутреннего цикла в (4) значения указателя JBIG2Bitmap записываются в буфер syms меньшего размера.

Без другого трюка этот цикл записал бы более 32 ГБ данных в буфер syms меньшего размера, что, безусловно, вызвало бы сбой. Чтобы избежать этого сбоя, куча очищается таким образом, что первые несколько операций записи в конец буфера syms повреждают резервный буфер GList. Этот GList хранит все известные сегменты и используется подпрограммой findSegments для сопоставления номеров сегментов, переданных в refSegs, с указателями JBIG2Segment. Переполнение приводит к тому, что указатели JBIG2Segment в GList перезаписываются указателями JBIG2Bitmap в (4).

Удобно, поскольку JBIG2Bitmap наследует от JBIG2Segment, виртуальный вызов seg->getType() выполняется успешно даже на устройствах, где включена аутентификация указателя (которая используется для проверки слабого типа виртуальных вызовов), но возвращаемый тип теперь не будет равен jbig2SegSymbolDict, таким образом что приводит к тому, что дальнейшая запись в (4) не может быть достигнута, и ограничивает степень повреждения памяти.

1641718151748.png


Boundless unbounding

Сразу после поврежденных сегментов GList злоумышленник обрабатывает объект JBIG2Bitmap, который представляет текущую страницу (место, где отображаются текущие команды рисования).

JBIG2Bitmaps — это простые оболочки для резервного буфера, сохраняющие ширину и высоту буфера (в битах), а также значение строки, которое определяет, сколько байтов хранится для каждой строки.

1641718170824.png


Тщательно структурируя refSeg, они могут остановить переполнение после записи еще ровно трех указателей JBIG2Bitmap после окончания буфера сегментов Glist. Это перезаписывает указатель vtable и первые четыре поля JBIG2Bitmap, представляющие текущую страницу. Из-за характера структуры адресного пространства iOS эти указатели, скорее всего, будут находиться во вторых 4 ГБ виртуальной памяти с адресами от 0x100000000 до 0x1ffffffff.
Поскольку все оборудование iOS имеет обратный порядок байтов (это означает, что поля w и line, скорее всего, будут перезаписаны с помощью 0x1 — наиболее значащей половины указателя JBIG2Bitmap), а поля segNum и h, вероятно, будут перезаписаны с наименьшей значащей половиной такого указателя, довольно случайное значение, зависящее от расположения кучи и ASLR где-то между 0x100000 и 0xffffffff.

Это дает текущей целевой странице JBIG2Bitmap неизвестное, но очень большое значение для h. Поскольку это значение h используется для проверки границ и должно отражать выделенный размер резервного буфера страницы, это приводит к "размыканию" холста для рисования. Это означает, что последующие команды сегмента JBIG2 могут считывать и записывать память за пределами исходных границ резервного буфера страницы.

Уборщик кучи также помещает резервный буфер текущей страницы чуть ниже буфера syms меньшего размера, так что, когда страница JBIG2Bitmap не ограничена, она может читать и записывать свои собственные поля:

1641718200092.png


Отрисовывая 4-байтовые растровые изображения с правильными координатами холста, они могут записывать во все поля страницы JBIG2Bitmap, а тщательно выбирая новые значения для w, h и строки, они могут записывать произвольные смещения из резервного буфера страницы.

На этом этапе также можно было бы записывать в произвольные абсолютные адреса памяти, если бы вы знали их смещения из резервного буфера страницы. Но как вычислить эти смещения? До сих пор этот эксплойт выполнялся очень похоже на эксплойт "канонического" языка сценариев, который в Javascript может закончиться неограниченным объектом ArrayBuffer с доступом к памяти. Но в этих случаях злоумышленник может запустить произвольный Javascript, который, очевидно, может использоваться для вычисления смещений и выполнения произвольных вычислений. Как это сделать в однопроходном анализаторе изображений?

Мой другой формат сжатия по Тьюрингу!

Как упоминалось ранее, последовательность шагов, реализующих уточнение JBIG2, очень гибкая. Шаги уточнения могут ссылаться как на выходное растровое изображение, так и на любые ранее созданные сегменты, а также отображать вывод либо на текущую страницу, либо на сегмент. Тщательно прорабатывая контекстно-зависимую часть декомпрессии уточнения, можно создавать последовательности сегментов, в которых только операторы комбинации уточнения имеют какой-либо эффект.

На практике это означает, что можно применять логические операторы AND, OR, XOR и XNOR между областями памяти с произвольным смещением от резервного буфера текущей страницы JBIG2Bitmap. И так как это было неограниченным... можно выполнять эти логические операции с памятью при произвольных смещениях за пределами границ:

1641718227030.png


Когда вы дойдете до этого места, все становится действительно интересным. Что, если вместо того, чтобы работать с подпрямоугольниками размером с глиф, вы работаете с отдельными битами?

Теперь вы можете предоставить в качестве входных данных последовательность команд сегмента JBIG2, которые реализуют последовательность логических битовых операций для применения к странице. А поскольку буфер страницы не ограничен, эти битовые операции могут работать с произвольной памятью.

Так вы можете убедиться, что с помощью доступных логических операторов AND, OR, XOR и XNOR вы действительно можете вычислить любую вычислимую функцию — самое простое доказательство в том, что вы можете создать логическое НЕ. оператора, выполняя XOR с 1, а затем помещая перед ним вентиль AND, чтобы сформировать вентиль NAND:

1641718257611.png


Вентиль И-НЕ является примером универсального логического вентиля; один, из которого могут быть построены все остальные вентили и из которого может быть построена схема для вычисления любой вычислимой функции.

Практические схемы

JBIG2 не имеет возможностей сценариев, но в сочетании с уязвимостью у него есть возможность эмулировать схемы произвольных логических вентилей, работающих с произвольной памятью. Так почему бы просто не использовать это для создания собственной компьютерной архитектуры и сценария для этого!? Это именно то, что делает этот эксплойт. Используя более 70000 сегментных команд, определяющих логические битовые операции, они определяют архитектуру небольшого компьютера с такими функциями, как регистры и полный 64-битный сумматор и компаратор, которые они используют для поиска в памяти и выполнения арифметических операций. Это не так быстро, как Javascript, но по сути эквивалентно вычислительному процессу.

Операции начальной загрузки для эксплойта побега из песочницы написаны для работы на этой логической схеме, и все это работает в этой странной эмулируемой среде, созданной из одного прохода декомпрессии через поток JBIG2. Это довольно невероятно, и в то же время довольно пугающе.

В следующей статье (в настоящее время он завершается) мы рассмотрим, как именно эксплойт выходит из песочницы IMTranscoderAgent.

Источник: https://googleprojectzero.blogspot.com/2021/12/a-deep-dive-into-nso-zero-click.html
 
Это реально самый крутой эксплоит про который я читал. Обычно малварь свою виртуалку создает или протектор. А тут сам экслпоит и ещё на основе базовых блоков, это ппц просто😍
😍😍
 
Пожалуйста, обратите внимание, что пользователь заблокирован


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх