[ << ALL_FEED ]

Как не бороться с обфускацией

Ещё в группе «Индикаторы и C2»

  • Этот ваш Siemens…

    Недавно наши коллеги из Центра промышленной экспертизы Позитива обнаружили на MalwareBazaar один любопытный Windows-образец. Вот его…

  • Операция Chewbacca

    В конце июня команда PT ESC в ходе расследования инцидентов обнаружила новую группу, нацеленную как минимум…

  • Ваш сервер Zimbra под угрозой

    Недавно наша команда PT ESC IR столкнулась с новой атакой ransomware-группировок на почтовые серверы Zimbra с…

  • Он вам не gsocket

    Он вам не gsocket 😑 В ходе расследования одного из инцидентов специалисты PT ESC IR наткнулись…

  • Ищем RAT’ов по их же сертификатам 🕵️

    Коллеги из Censys выкатили разбор семейства AsyncRAT, описав целое генеалогическое древо: AsyncRAT → DCRAT (DarkCrystal RAT)…

Как не бороться с обфускацией 🫤

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

Помимо техники Control Flow Flattening, которая сама по себе неприятна, он добавляет много мертвого кода, а также раскладывает арифметические выражения на набор, казалось бы, бессмысленных и случайных операций, например, как на скрине 1.

Значение, которое кладется в edx, — второй аргумент функции run_send_recv_timer — вычисляется весьма странным образом, хотя в итоге результат выглядит как на скрине 2.

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

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

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

Найти функцию расшифровки в дампе просто, нужный фрагмент кода — на скрине 3.

🧐 Встает проблема найти ссылку на функцию. Если бы семпл был x32, то задача была бы проста: найти начало функции и байты E8 <function-address-LE>, то есть call с операндом в виде адреса функции расшифровки.

Но в x64 вся адресация RIP-relative, то есть операнды-адреса — это смещения относительно конца текущей инструкции. Значит, мы найдем все инструкции call и проверим, равен ли операнд адресу начала функции расшифровки. Выглядит это так:


calls = self.mdmp.find_bytes(b"\xE8", segment_start, segment_size, find_first=False)
    decrypt_refs = []
for call_pos in calls:
    call_offset = self.mdmp.read(call_pos + 1, 4)
    call_offset = struct.unpack("<i", call_offset)[0]
    if call_pos + 5 + call_offset == decrypt_key_func_start:
        decrypt_refs.append(call_pos)
    if len(decrypt_refs) == 2:
        break
Code language: Python (python)


💡Примечание: ссылок две, потому что зашито два ключа — один для ECDH, второй для ECDSA, каждый расшифровывается в отдельной функции.

Найдя ссылку на функцию расшифровки, ищем начало вызывающей ее функции. Ее псевдокод — на скрине 4.

Зашифрованный ключ собирается на стеке и далее расшифровывается. Мы знаем, что за этой красотой стоит сильно обфусцированный ассемблерный код, значит, считать буфер «as is» будет тяжело.

Прибегнем к такому инструменту, как эмулятор. Мы не будем деобфусцировать это скриптом, воспроизводить логику, а просто «выполним» это и считаем результат.

Для этого, поскольку мы знаем адрес ссылки на функцию decrypt_KEY, мы должны всего лишь найти начало функции decrypt_ECK1, считать ее и отдать эмулятору, который сделает всю грязную работу. Для эмуляции используем Speakeasy, который умеет эмулировать не только инструкции, но и среду ОС.

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


def emulate_decrypt_key_func(self, func_body):
    emul = speakeasy.Speakeasy()
    shellcode = emul.load_shellcode(fpath=None, data=func_body, arch="amd64")
    ctx = {"entry": True, "mem": emul.mem_alloc(4), "skip_call": True}
    emul.add_code_hook(self.code_hook_key, ctx=ctx)
    emul.run_shellcode(shellcode)
    decrypted = self.decrypt(ctx["encrypted_string"], ctx["key"], ctx["length"])
    return decrypted
Code language: Python (python)


Внутри коллбэка мы пропускаем один call — вызов пустышки nullsub_4 — и останавливаемся перед вызовом decrypt_key. В этот момент в одном из параметров лежит готовый буфер с зашифрованным ключом. Далее этот буфер считывается и расшифровывается в ECDH-ключ, как видно на скрине 5.

Благодаря эмулятору, мы не стали пытаться изменить обфускацию, а приняли ее такой, какая она есть, чтобы получить желаемое 😌


#tip #trick #C2
@ptescalator

Ещё от global_author

  • Этот ваш Siemens…

    Недавно наши коллеги из Центра промышленной экспертизы Позитива обнаружили на MalwareBazaar один любопытный Windows-образец. Вот его…

  • Анти-антивирус

    Недавно нам на глаза попалась APK-шка с интригующим и внушающим доверие названием «Антивирус ФСБ.apk». Установив его,…

  • .exe .docm .xlsm

    .exe .docm .xlsm Вредоносные файлы с этими расширениями чаще всего встречаются в сетевом трафике компаний. Давайте…

  • Хаос, шок, приватные ключи от не менее приватного GitLab 💻

    Последние пару месяцев злоумышленник распространял трояны с нескольких npm-учеток: alex05255, mdrafiqulislamrabby, b.w1001, abdev8773 и mollspotwood54400. Список…

  • ::%16777216 — так что же ты такое?

    ::%16777216 — так что же ты такое? Известно, что в ходе атак злоумышленники могут использовать туннелирование.…

Ещё от global_author

  • Этот ваш Siemens…

    Недавно наши коллеги из Центра промышленной экспертизы Позитива обнаружили на MalwareBazaar один любопытный Windows-образец. Вот его…

  • Анти-антивирус

    Недавно нам на глаза попалась APK-шка с интригующим и внушающим доверие названием «Антивирус ФСБ.apk». Установив его,…

  • .exe .docm .xlsm

    .exe .docm .xlsm Вредоносные файлы с этими расширениями чаще всего встречаются в сетевом трафике компаний. Давайте…

  • Хаос, шок, приватные ключи от не менее приватного GitLab 💻

    Последние пару месяцев злоумышленник распространял трояны с нескольких npm-учеток: alex05255, mdrafiqulislamrabby, b.w1001, abdev8773 и mollspotwood54400. Список…

  • ::%16777216 — так что же ты такое?

    ::%16777216 — так что же ты такое? Известно, что в ходе атак злоумышленники могут использовать туннелирование.…

Ещё в группе «Индикаторы и C2»

  • Этот ваш Siemens…

    Недавно наши коллеги из Центра промышленной экспертизы Позитива обнаружили на MalwareBazaar один любопытный Windows-образец. Вот его…

  • Операция Chewbacca

    В конце июня команда PT ESC в ходе расследования инцидентов обнаружила новую группу, нацеленную как минимум…

  • Ваш сервер Zimbra под угрозой

    Недавно наша команда PT ESC IR столкнулась с новой атакой ransomware-группировок на почтовые серверы Zimbra с…

  • Он вам не gsocket

    Он вам не gsocket 😑 В ходе расследования одного из инцидентов специалисты PT ESC IR наткнулись…

  • Ищем RAT’ов по их же сертификатам 🕵️

    Коллеги из Censys выкатили разбор семейства AsyncRAT, описав целое генеалогическое древо: AsyncRAT → DCRAT (DarkCrystal RAT)…