July 27

Writeup - Honeykeeper

Рабочий компьютер сотрудника был скомпрометирован в результате фишинговой атаки. По легенде задания злоумышленники использовали Linux-руткит eBee, распространяемый на подпольных «пчелиных» форумах.
Для анализа был предоставлен сжатый дамп оперативной памяти:

honeykeeper_dump.img.xz

Цель задания — исследовать дамп, обнаружить следы руткита и восстановить флаг.

Проверка и распаковка дампа


Сначала проверим целостность XZ-архива:

xz -t honeykeeper_dump.img.xz

Ошибок обнаружено не было.
Распаковываем дамп:

xz -dk honeykeeper_dump.img.xz

Определяем формат полученного файла:

file honeykeeper_dump.img

Результат показал, что перед нами не образ диска, а ELF core dump Linux x86-64 размером около 1,6 ГБ:

ELF 64-bit LSB core file, x86-64

Это полноценный снимок оперативной памяти виртуальной машины.

Первичный анализ строк


Для первоначального поиска индикаторов компрометации используем strings:

strings -a honeykeeper_dump.img | less

Также выполним поиск по названию предполагаемого руткита:

strings -a honeykeeper_dump.img | grep -i -E 'ebee|rootkit|bpf'

В памяти были обнаружены следующие строки:

bpf_prog_166a5b3876fbe624_eBeeKeys
bpf_prog_a0c6dd9bd609151f_eBeeIngress
bpf_prog_7c18515a1e8909af_eBeeEgress

Таким образом, в системе были загружены три подозрительные eBPF-программы:

  • eBeeKeys;
  • eBeeIngress;
  • eBeeEgress.

По названиям можно предположить следующее назначение компонентов
eBeeKeys - перехват нажатий клавиатуры
eBeeIngress - обработка входящего сетевого трафика
eBeeEgress - перехват исходящего сетевого трафика
Следовательно, компрометация системы подтверждается.


Информация об исследуемой системе


В дампе удалось найти информацию об операционной системе и ядре:

Linux 6.17.0-35-generic
Ubuntu 6.17.0-35.35-generic
x86-64

Также были обнаружены имя пользователя и hostname:

USER=honeykeeper
HOSTNAME=honeykeeper-pc

Для полноценного анализа Linux-дампа через Volatility требуется таблица символов, соответствующая конкретной версии ядра.
При попытке запуска стандартных Linux-плагинов Volatility без символов возникала ошибка:

Unsatisfied requirement:
kernel.layer_name
kernel.symbol_table_name

В дампе присутствовала подсказка:

rootkit or ebee lets go:
https://ebee-deps-imqs01in.avitoctf.ru/

Вероятно, по этому адресу ранее располагались необходимые символы ядра или дополнительные материалы для анализа. Однако для нахождения флага оказалось достаточно ручного исследования памяти и структур eBPF.

Анализ функциональности eBee


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

c2_details
enabled
c2_key_logging
crypto_key
key_logging

Также присутствовали структуры пакетов:

c2_datapacket
source
data
C2_NONE
C2_KEYLOGGING
keylog
symbol
salt

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

  • зашифрованный символ symbol;
  • значение salt;
  • источник данных;
  • идентификатор типа C2-пакета.
  • При этом для шифрования используется поле crypto_key.

Поиск флага в открытом виде


Первым делом проверим распространённые форматы флагов:

strings -a honeykeeper_dump.img | grep -Eio \
'avito\{[^}]+\}|flag\{[^}]+\}|ctf\{[^}]+\}'

Результатов получено не было.
Это означало, что флаг:

  • не хранится в памяти открытым текстом;
  • либо находится в бинарной структуре;
  • либо был зашифрован руткитом перед сохранением в eBPF-карте.


Основным объектом дальнейшего анализа стала программа eBeeKeys.

Поиск eBPF-карты кейлоггера


Рядом со структурами eBPF-программ были обнаружены ссылки на используемые карты.
Особый интерес представляла карта:

c2_databus

Она использовалась как буфер для передачи данных между компонентами руткита и содержала записи типа c2_datapacket.
Внутри записей находились значения:

symbol
salt

Также в конфигурационной структуре руткита было найдено значение криптографического ключа:

crypto_key = 0x31

После сопоставления нескольких записей стало понятно, что каждый символ зашифрован операцией XOR.
Формула расшифровки:

plain_symbol = encrypted_symbol ^ salt ^ crypto_key

Для найденного экземпляра руткита:

plain_symbol = encrypted_symbol ^ salt ^ 0x31

Расшифровка кейлогов


Для автоматической расшифровки записей можно использовать следующий Python-код:

CRYPTO_KEY = 0x31

def decrypt_symbol(encrypted_symbol: int, salt: int) -> int:
    return encrypted_symbol ^ salt ^ CRYPTO_KEY


records = [
    # (encrypted_symbol, salt)
    # Значения извлекаются из записей c2_datapacket карты c2_databus.
]

result = bytearray()

for encrypted_symbol, salt in records:
    symbol = decrypt_symbol(encrypted_symbol, salt)
    result.append(symbol)

print(result.decode("utf-8", errors="replace"))

После расшифровки и восстановления правильного порядка элементов очереди была получена следующая последовательность пользовательского ввода:

keeper<TAB>avito{eBeepf_is_awes8me_4_ev3ryth1ng}<ENTER>

Вероятно, пользователь вводил логин keeper, нажимал Tab, после чего вводил пароль или секретное значение.
Этим секретным значением и являлся флаг.

Дополнительные индикаторы компрометации


В дампе также были найдены сетевые индикаторы:

https://ebee-deps-imqs01in.avitoctf.ru/
http://honey-crm:8000/alert.html
192.168.122.1

В журнале ядра присутствовала запись:

apparmor="WARN"
dest="https://ebee-deps-imqs01in.avitoctf.ru/"
comm="firefox"
scope="network"
tracer="bpftaint"

Для страницы honey-crm:8000/alert.html был обнаружен заголовок:

Security Alert

Вероятно, данная страница использовалась как часть фишингового сценария. Пользователь перешёл на неё и ввёл учётные данные, которые были перехвачены компонентом eBeeKeys.