Виртуальный шифр. Анализируем энкодер для VMware ESXi

Содержание статьи

  • Уязвимость и общая схема атаки
  • Анализ вредоносных файлов
  • Скрипт encrypt.sh
  • Общий анализ атаки
  • Как предотвратить?

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

Ком­про­мета­ция гипер­визора или свя­зан­ной с ним инфраструк­туры может пос­тавить под угро­зу целую эко­сис­тему сер­веров, баз дан­ных и биз­нес‑при­ложе­ний. Неуди­витель­но, что хакер­ские груп­пы все чаще фокуси­руют свои ата­ки на VMware ESXi, соз­давая спе­циали­зиро­ван­ные прог­раммы‑шиф­роваль­щики, нацелен­ные на фай­лы вир­туаль­ных машин, такие как *.vmdk, *.vmx, *.vmsn, *.vswp, *.vmem и дру­гие. Сегод­ня мы рас­смот­рим кон­крет­ный слу­чай, в котором был обна­ружен бинар­ный ELF-файл с име­нем encrypt и соп­ровож­дающий его Bash-скрипт encrypt.sh. Я под­робно опи­шу эта­пы ата­ки: от про­ник­новения в сеть и получе­ния дос­тупа к ESXi до запус­ка фай­лов, шиф­рования вир­туаль­ных дис­ков и устра­нения сле­дов, что оставля­ет жер­тву перед выбором — зап­латить выкуп или потерять дан­ные.

 

Уязвимость и общая схема атаки

Что­бы понять всю глу­бину это­го инци­ден­та, нуж­но рас­смот­реть пос­ледова­тель­ность дей­ствий ата­кующих от момен­та экс­плу­ата­ции уяз­вимос­ти CVE-2021-44228 на VMware Horizon до непос­редс­твен­ного запус­ка шиф­рования на ESXi. Уяз­вимость, получив­шая наз­вание Log4Shell, ста­ла широко извес­тна зимой 2021–2022 годов и давала воз­можность зло­умыш­ленни­кам выпол­нять про­изволь­ный код в кон­тек­сте сер­вера, где исполь­зует­ся логиру­ющая биб­лиоте­ка Log4j уяз­вимых вер­сий. VMware Horizon, будучи слож­ным про­дук­том, базиру­ющим­ся на Java и в прош­лом вклю­чав­шим уяз­вимые ком­понен­ты, иног­да оста­вал­ся неп­ропат­ченным, что откры­вало воз­можность про­вес­ти RCE-ата­ку (remote code execution).

Зло­умыш­ленник, имея спе­циаль­ный экс­пло­ит, мог перес­лать сер­веру Horizon пакет, вклю­чав­ший вызов к JNDI с вре­донос­ным клас­сом. Биб­лиоте­ка Log4j динами­чес­ки заг­ружала его и исполня­ла. Как толь­ко этот класс попадал в сре­ду исполне­ния, он рас­кры­вал перед ата­кующим без­гра­нич­ные воз­можнос­ти — от уста­нов­ки допол­нитель­ного malware-инс­тру­мен­тария до внед­рения скрип­тов и эска­лации на уро­вень локаль­ного адми­нис­тра­тора. Имен­но так, сог­ласно соб­ранным дан­ным, в ряде слу­чаев уда­валось про­ник­нуть в кор­поратив­ную сеть и ском­про­мети­ровать сер­вер Horizon.

Пос­ле экс­плу­ата­ции уяз­вимос­ти CVE-2021-44228 ата­ка не оста­нав­лива­ется на одной машине, ведь обыч­но зло­умыш­ленни­кам инте­рес­ны более мас­штаб­ные цели. Поэто­му они ана­лизи­руют сетевую сре­ду, отыс­кива­ют уяз­вимые узлы и, самое важ­ное, осу­щест­вля­ют ата­ку SAM-хра­нили­ща в попыт­ке извлечь NTLM-хеш локаль­ного адми­нис­тра­тора. Если в ком­пании на мно­гих сер­верах исполь­зует­ся один и тот же пароль локаль­ного адми­на (или хотя бы на нес­коль­ких клю­чевых машинах), это дает ата­кующим воз­можность переме­щать­ся по сети (lateral movement) при помощи pass-the-hash.

Ког­да обна­ружи­вает­ся узел, где запуще­на сес­сия поль­зовате­ля из груп­пы «Адми­нис­тра­торы домена», то дамп lsass.exe или ана­логич­ное средс­тво поз­воля­ет получить NTLM-хеш домен­ного адми­на, пос­ле чего зло­умыш­ленни­ки могут выпол­нить любые дей­ствия от име­ни домен­ного адми­нис­тра­тора, в том чис­ле получить дос­туп к ESXi, если нас­тро­ена аутен­тифика­ция через домен­ные учет­ные записи.

Ес­ли учет­ка Domain Admin без жес­ткой изо­ляции тоже име­ет пра­во под­клю­чать­ся к ESXi, то зло­умыш­ленни­ки этим неп­ремен­но вос­поль­зуют­ся, ведь, овла­дев домен­ными при­виле­гиями, они без тру­да заг­рузят нуж­ную вре­донос­ную прог­рамму в /tmp или дру­гой каталог на гипер­визоре (с помощью SCP или иным спо­собом). В нашем слу­чае ата­кующие заг­ружа­ют фай­лы encrypt и encrypt.sh — двух ком­понен­тов, которые дей­ству­ют в связ­ке.

Ана­лиз VirusTotal фай­ла encrypt.sh

Ана­лиз VirusTotal фай­ла encrypt

Ана­лиз Cuckoo Sandbox фай­ла encrypt 

Анализ вредоносных файлов

Ана­лиз показал, что ELF-бинарь encrypt пред­став­ляет собой модуль‑вымога­тель, написан­ный под 64-бит­ную Linux-плат­форму. В ESXi внут­ренне исполь­зует­ся Linux-образ, поэто­му запуск ELF-фай­ла нап­рямую там воз­можен, осо­бен­но если уста­нов­лен параметр execInstalledOnly = 0 (или ском­пилиро­ваны нуж­ные shared-биб­лиоте­ки).

Па­рамет­ры фай­ла encrypt

Ло­гика запус­ка фай­ла encrypt — обра­бот­ка ошиб­ки, ког­да нет ссыл­ки на файл для шиф­рования. Если ссыл­ка при­сутс­тву­ет, то запус­кает­ся про­цесс шиф­рования.

Ло­гика запус­ка шиф­роваль­щика

Би­нарь при стар­те ждет от поль­зовате­ля аргу­мен­та — пути к фай­лу, который будет шиф­ровать­ся. При этом, если верить дизас­сем­бле­ру, в коде реали­зова­ны крип­топри­мити­вы Curve25519 (для обме­на или генера­ции клю­чей) и Sosemanuk (для быс­тро­го шиф­рования). Давай раз­берем всю пос­ледова­тель­ность дей­ствий этой соф­тины.

Ло­гика основной фун­кции encrypt_file

Вот при­мер­ный пошаго­вый алго­ритм выпол­нения фун­кции.

  • От­кры­тие фай­ла. Файл откры­вает­ся для чте­ния и записи в бинар­ном режиме. Если открыть файл не уда­лось (fopen64 вер­нул NULL), фун­кция воз­вра­щает 1.

    Ло­гика основной фун­кции encrypt_file

  • Вы­деле­ние памяти под ключ и ини­циали­зация базы дан­ных зна­чени­ями.

    Вы­деле­ние памяти под ключ и ини­циали­зация базы дан­ных зна­чени­ями

  • Де­коди­рова­ние стро­ки Base64 и генера­ция клю­ча.

    Де­коди­рова­ние стро­ки Base64 и генера­ция клю­ча

  • В коде мож­но най­ти вот такие кон­стан­ты:

    ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

    Они исполь­зуют­ся для Base64 в про­цес­се декоди­рова­ния встро­енной стро­ки‑клю­ча, «вши­той» пря­мо в бинарь. Исходная дли­на decoded_length записы­вает­ся сюда же, про­читан­ная стро­ка исполь­зует­ся для генера­ции нового клю­ча фун­кци­ей generate_key.

    Раз­верну­тая фун­кция generate_key

    Фун­кция generate_key при­нима­ет шесть аргу­мен­тов:

    • _int64 privateKey1 — пер­вый при­ват­ный ключ для Curve25519;
    • _int64 privateKey2 — вто­рой при­ват­ный ключ для Curve25519;
    • _BYTE *sosemanukStateBuffer — ука­затель на буфер сос­тояния Sosemanuk (поточ­ного шиф­ра);
    • _BYTE *curve25519PrivateArray — ука­затель на 32-бай­товый мас­сив для работы с Curve25519;
    • _int64 sharedSecret1 — буфер для резуль­тата пер­вого вызова фун­кции curve25519_donna;
    • _int64 sharedSecret2 — буфер для резуль­тата вто­рого вызова фун­кции curve25519_donna.

    Ша­ги выпол­нения этой час­ти вре­донос­ного при­ложе­ния.

    • Очис­тка памяти. На этом эта­пе очи­щают­ся мас­сивы для пос­леду­юще­го исполь­зования, что­бы гаран­тировать отсутс­твие оста­точ­ных дан­ных.
    • Мо­дифи­кация битов (в пер­вом и пос­леднем бай­тах мас­сива). Это стан­дар­тная про­цеду­ра для кор­рек­тной нас­трой­ки зак­рытого клю­ча для алго­рит­ма Curve25519.
    • Ге­нера­ция обще­го сек­рета с исполь­зовани­ем алго­рит­ма Диф­фи — Хел­лма­на пос­редс­твом Curve2579. Фун­кция curve25519_donna задей­ство­вана для выпол­нения опе­раций Диф­фи — Хел­лма­на с исполь­зовани­ем алго­рит­ма Curve25519. Зна­чения sharedSecret1 и sharedSecret2 генери­руют­ся с помощью зак­рытого клю­ча curve25519PrivateArray и двух раз­ных откры­тых клю­чей privateKey1 и privateKey2.
    • Пос­ле вычис­лений зак­рытый ключ curve25519PrivateArray очи­щает­ся с помощью фун­кции secure_memset, что­бы пре­дот­вра­тить утеч­ку чувс­тви­тель­ной информа­ции.
    • Соз­дает­ся хеш SHA-256 от sharedSecret2. sha256_init() и sha256_hash(), под­готав­лива­ется и вычис­ляет­ся хеш.
    • secure_memset(); очи­щает память, исполь­зован­ную для вычис­ления SHA-256, что­бы уда­лить про­межу­точ­ные дан­ные.
    • sosemanuk_schedule() готовит внут­ренние сос­тояния для шиф­ра Sosemanuk на осно­ве клю­ча (резуль­тата SHA-256).
    • sosemanuk_init() завер­шает ини­циали­зацию шиф­ра, переда­вая под­готов­ленный кон­текст.
    • Пос­ле исполь­зования клю­ча из SHA-256 он очи­щает­ся с помощью secure_memset.

    На сле­дующем эта­пе выпол­няет­ся ини­циали­зация спис­ка раз­делов и про­вер­ка фай­ловой сис­темы.

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

    Раз­верну­тая фун­кция check_file_system

    За­тем прог­рамма про­веря­ет, явля­ется ли вход­ная струк­тура валид­ной MBR или GPT.

    Раз­верну­тая фун­кция add_partition

    Источник: xakep.ru

    Ответить

    Ваш адрес email не будет опубликован. Обязательные поля помечены *