В изра­иль­ской NSO Group соз­дали экс­пло­ит для iMessage, на­делав­ший мно­го шума. С помощью это­го экс­пло­ита тро­ян Pegasus был внед­рен в телефо­ны пуб­личных деяте­лей и полити­ков. Apple уже по­дала иск на NSO. Одна­ко оста­вим в сто­роне полити­ку — в этой статье мы сос­редото­чим­ся на самом экс­пло­ите, тем более что он прос­то взрыв­ной! Заража­ет девай­сы без учас­тия юзе­ра, укры­вает­ся внут­ри GIF и вклю­чает в себя кро­шеч­ный вир­туаль­ный компь­ютер.
 

NSO

На­чало тому, о чем мы будем говорить, было положе­но в августе 2016 года, ког­да изра­иль­ская ком­пания NSO Group, спе­циали­зиру­ющаяся на киберо­ружии, раз­работа­ла и выпус­тила шпи­онское ПО Pegasus, пред­назна­чен­ное для зараже­ния мобиль­ных устрой­ств под управле­нием Android и iOS. «Пегас» был спо­собен читать тек­сто­вые сооб­щения, отсле­живать звон­ки и мес­тополо­жение, собирать пароли, получать информа­цию с мик­рофона и камеры, а так­же дос­туп к лич­ной информа­ции поль­зовате­ля.

Тот ста­рый «Пегас» 2016 года исполь­зовал экс­пло­ит «одно­го нажатия» (one-click). То есть, ког­да поль­зователь‑жер­тва получал на свой смар­тфон «заряжен­ное» сооб­щение, что­бы акти­виро­вать под­ложен­ный сюр­приз, ему нуж­но было что‑то сде­лать, нап­ример клик­нуть по ссыл­ке. Зараже­ния было лег­ко избе­жать — дос­таточ­но было не нажимать на что попало.

Примеры фишинговых СМС
При­меры фишин­говых СМС

В июле 2021 года иссле­дова­телям из лабора­тории Citizen Lab при Уни­вер­ситете Торон­то уда­лось изу­чить экс­пло­ит «нулево­го нажатия» для iMessage, обна­ружен­ный на смар­тфо­не акти­вис­та из Саудов­ской Ара­вии. Экс­пло­ит работал вооб­ще без учас­тия поль­зовате­ля и сра­баты­вал сам — хакеру дос­таточ­но лишь отпра­вить полез­ную наг­рузку в мес­сен­дже­ре.

 

Опасный прием

Вход­ная точ­ка «Пегаса» в iPhone — при­ложе­ние iMessage. Это зна­чит, что ата­кующе­му дос­таточ­но знать телефон­ный номер или Apple ID жер­твы.

В iMessage есть натив­ная под­дер­жка GIF-ани­мации. Прис­ланная в чат гиф­ка вос­про­изво­дит­ся в цик­ле бес­конеч­но. Как толь­ко iMessage получа­ет сооб­щение, еще до его вывода на экран вызыва­ется метод в про­цес­се IMTranscoderAgent. Он, в свою оче­редь, выпол­няет­ся за пре­дела­ми песоч­ницы BlastDoor. При этом в парамет­ре метода переда­ется любое изоб­ражение с рас­ширени­ем gif. Вот таким обра­зом:

[IMGIFUtils copyGifFromPath:toDestinationPath:error]

Это при­мер кода на язы­ке Objective-C. Пос­мотри на селек­тор. Здесь, веро­ятно, было намере­ние прос­то ско­пиро­вать файл GIF перед редак­тирова­нием поля счет­чика цик­лов, но семан­тика это­го метода иная. Внут­ри он исполь­зует API CoreGraphics, что­бы отоб­разить исходное изоб­ражение в новый GIF-файл по задан­ному пути. Одна­ко то, что файл име­ет рас­ширение gif, вов­се не озна­чает, что он на самом деле гиф­ка.

Биб­лиоте­ка ImageIO при­меня­ется, что­бы опоз­нать фор­мат фай­ла и про­ана­лизи­ровать его, но при этом пол­ностью игно­риру­ет его рас­ширение. При исполь­зовании это­го трю­ка с «под­дель­ными гиф­ками» более 20 гра­фичес­ких кодеков ста­новят­ся потен­циаль­ными жер­тва­ми для ата­ки нулево­го нажатия в iMessage. Некото­рые из них очень слож­ны и сос­тоят из сотен тысяч строк кода. Огромное прос­транс­тво для хакер­ской сме­кал­ки!

Как сооб­щает иссле­дова­тель­ская груп­па Google Project Zero, с iOS 14.8.1 (26 октября 2021 года) Apple огра­ничи­ла фор­маты в ImageIO, дос­тупные из про­цес­са IMTranscoderAgent. Так­же инже­неры ком­пании пол­ностью уда­лили код для дос­тупа к GIF из IMTranscoderAgent с вер­сии iOS 15.0 (20 сен­тября 2021 года), вмес­те с тем пол­ностью перене­ся декоди­рова­ние GIF внутрь BlastDoor.

 

PDF внутри GIF

В NSO исполь­зовали дыру «под­дель­ный GIF», что­бы через нее заюзать уяз­вимость в пар­сере CoreGraphics PDF.

Дол­гие годы фор­мат PDF был излюблен­ной целью для атак — он дос­тупен вез­де и обла­дает дос­таточ­ной слож­ностью. При­ятный бонус для хакеров — под­дер­жка JavaScript внут­ри PDF. CoreGraphics PDF не интер­пре­тиру­ет JavaScript, тем не менее NSO уда­лось най­ти в нед­рах пар­сера кое‑что не менее мощ­ное.

Иан Бир (Ian Beer) и Сэмю­эл Гросс (Samuel Groß) из Project Zero рас­потро­шили экс­пло­ит NSO и под­робно рас­ска­зали, как он работа­ет. Даль­ше мы прос­ледим за их иссле­дова­нием, что­бы разоб­рать­ся, как кар­тинка прев­ратилась в нас­тоящий компь­ютер и помог­ла экс­пло­иту сбе­жать из песоч­ницы.

 

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

В кон­це девянос­тых мало у кого был ста­биль­ный и быс­трый интернет, боль­шинс­тво юзе­ров доз­ванива­лись к про­вай­деру по dial-up и работа­ли на смеш­ных сей­час ско­рос­тях. Да и дис­ки не отли­чались боль­шими емкостя­ми, поэто­му сжа­тие дан­ных было важ­ной тех­нологи­ей. PNG, JPEG и GIF нам зна­комы и по сей день, но были и дру­гие.

Фор­мат JBIG2 пред­назна­чал­ся для сжа­тия монох­ромных изоб­ражений (где пик­сели могут быть толь­ко чер­ными или белыми). Он при­менял­ся в офис­ных ска­нерах высокой ценовой катего­рии, таких как Xerox WorkCenter.

Xerox WorkCenter
Xerox WorkCenter

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

При­меча­тель­но, что эти фай­лы даже при дос­той­ном раз­решении ска­ниро­вания занима­ли все­го нес­коль­ко килобай­тов. JBIG2 исполь­зует два метода для дос­тижения такого мощ­ного сжа­тия. Сей­час мы их обсу­дим. Толь­ко не думай, что мы тут отвлек­лись на какую‑то побоч­ную ерун­ду, — все это име­ет непос­редс­твен­ное отно­шение к экс­плу­ата­ции дыры в iMessage!

 

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

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

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

Сопоставление с образцом позволяет найти все формы, в данном случае все буквы e
Со­пос­тавле­ние с образцом поз­воля­ет най­ти все фор­мы, в дан­ном слу­чае все бук­вы e

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

При этом алго­ритм сжа­тия заменя­ет все дос­таточ­но похожие на вид области копи­ей толь­ко одной из них.

Замена всех вхождений одной копией глифа позволяет достичь высоких коэффициентов сжатия
За­мена всех вхож­дений одной копи­ей гли­фа поз­воля­ет дос­тичь высоких коэф­фици­ентов сжа­тия

В таком слу­чае текст по‑преж­нему прек­расно чита­ется, одна­ко объ­ем хра­нимой информа­ции ста­новит­ся мень­ше. Вмес­то того что­бы хра­нить дан­ные о пик­селях всей стра­ницы, для их отоб­ражения нуж­на толь­ко сжа­тая вер­сия «ссы­лоч­ного гли­фа» для каж­дого сим­вола и отно­ситель­ные коор­динаты мест, где дол­жны быть раз­мещены его копии. При рас­паков­ке алго­ритм рас­став­ляет гли­фы по мес­там, как бы рисуя ими на хол­сте.

Та­кой под­ход таит в себе сущес­твен­ный недос­таток: кри­вой кодиров­щик может слу­чай­но спу­тать похожие на вид сим­волы. А это при­водит к печаль­ным пос­ледс­тви­ям. В сво­ем бло­ге Дэвид Кри­зель (David Kriesel) при­водит нес­коль­ко вдох­новля­ющих при­меров, ког­да в PDF-фай­лах ска­ниро­ван­ных сче­тов‑фак­тур и чер­тежей одни циф­ры меня­ются на дру­гие. Для нас в дан­ном слу­чае эти проб­лемы не важ­ны — раз­ве что ими мож­но объ­яснить поч­ти пол­ное вымира­ние JBIG2.

 

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

Итак, резуль­тат сжа­тия на осно­ве под­ста­нов­ки отоб­ража­ется с потеря­ми. То есть пос­ле сжа­тия и рас­паков­ки вывод на вид не будет в точ­ности соот­ветс­тво­вать вво­ду. Поэто­му JBIG2 под­держи­вает и сжа­тие без потерь, в которое вхо­дит про­межу­точ­ный этап «сжа­тия с мень­шими потеря­ми».

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

Использование оператора XOR на растрах для вычисления маски разности изображения
Ис­поль­зование опе­рато­ра XOR на рас­трах для вычис­ления мас­ки раз­ности изоб­ражения

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

Вмес­то того что­бы пол­ностью кодиро­вать всю раз­ность за один раз, это мож­но сде­лать поэтап­но, при этом на каж­дой ите­рации исполь­зует­ся логичес­кий опе­ратор (один из AND, OR, XOR или XNOR) для уста­нов­ки, сбро­са или перек­лючения битов.

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

 

Поток JBIG2

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

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

Сег­менты пред­став­лены клас­сом JBIG2Segment и его под­клас­сами JBIG2Bitmap и JBIG2SymbolDict. JBIG2Bitmap пред­став­ляет собой пря­моуголь­ный мас­сив пик­селей. Его поле дан­ных ука­зыва­ет на зад­ний буфер, содер­жащий повер­хность для рен­дерин­га. JBIG2SymbolDict груп­пиру­ет бит­мапы. А целевая стра­ница пред­став­лена как JBIG2Bitmap и сос­тоит из отдель­ных гли­фов. На сег­менты (JBIG2Segment) мож­но ссы­лать­ся по номеру, а век­торный тип GList хра­нит ука­зате­ли на все сег­менты. Что­бы най­ти сег­мент по его номеру, GList ска­ниру­ется пос­ледова­тель­но.

Кста­ти, если ты сей­час про­читал сло­во «джи‑лист» неп­равиль­но и раз­веселил­ся, как дет­садовец, то пос­тарай­ся скон­цен­три­ровать­ся, нас ждут куда более инте­рес­ные откры­тия.

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    2 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии