Cl0p: разбор несложной малвари для самых маленьких

cl0p.webp


Привет^3🦠

Сегодня покажу вам разбор несложной малвари под Linux.
Реверс-инжиниринг помогает разобраться в том, как работает ВПО (вредоносное программное обеспечение).

Cl0p. Часть 1. Cтатический анализ

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

Первым делом

Обычно я смотрю файл через утилиту Detect It Easy. Вот ее вывод:

Bash:
Info:
    Size: 1028096
    File type: ELF32
    String: ELF(386)
    Extension: elf
    Operation system: Red Hat Linux(ABI: 2.6.9)
    Architecture: 386
    Mode: 32-bit
    Type: EXEC
    Endianness: LE

Выглядит так, что таблица символов не удалена, поэтому можно сразу найти main. Закидываю бинарь в IDA Pro.

main

В функции main происходит создание процесса-демона с вызовом chroot() в корневую директорию /.

1765661623465.webp


Далее в бесконечном цикле вызывается функция do_heartbeat().

do_heartbeat()

Из функции можно извлечь все директории, с которыми малвара взимодействует.

1765661657389.webp


/u01, /u02, /u03, /u04 — это часто используемые точки монтирования в Linux при работе с базами данных Oracle.

find

Конечно же следом пойду смотреть фунцию find.

1765661683500.webp


Алгоритм функции достаточно простой:
1. Открывает директорию и проходится по всем файлам в ней. Если это . или .., то их пропускает;
2. Вызвает функцию CreatRadMe (да-да, это не опечатка). По названию понятно, что создается README файл;
3. Далее происходит вызов EncrFile, если не находит подстроку C_I_0P в пути до файла. Если же это директория, то рекурсивно вызывается find;

CreatRadMe

Ничего особо интересного тут нет. Просто создается файл со следующим содержанием:

1765661705911.webp


EncrFile

Думаю, что ключевая функция во всей малваре - EncrFile.

1765661734169.webp


По сути для файла изменяются права с помощью chmod() на rw-------. Эти же права используются далее для работы с файлами.
Файл шифруется с помощью алгоритма rc4. Ключ генерируется для каждого файла отдельно, и, что интересно, записывается в файл рядом с раширением .C_I_0P с помощью функции CreateKey. Это означает, что получится эти файлы расшифровать) При этом шифруется максимум 100'000'000 байт файла.

Итог статического анализа

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



Cl0p. Часть 2. Динамический анализ

Все файлы для скачивания находятся внизу.

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

[!] Обязательно сделайте снапшот перед запуском. Так же рекомендую выключить интернет, общие папки и отключить все USB-устройства.

Запуск

На виртуальной машине я создал файл с неким таинственным содержимым) Вам самим предстоит узнать что там) Этот файл называется important_file.txt. После запуска малваря рядом с ним появились 2 файла: important_file.txt.C_I_0P и README_C_I_0P.TXT. Как и ожидалось))

7.webp


С помощью утилиты hexdump посмотрю содержимое этих файлов:

important_file.txt:
Bash:
hexdump -C important_file.txt
00000000  4a be 11 18 a9 c4 e9 2e  b8 fe 88 cb 4e a0 df 2e  |J...........N...|
00000010  e5 4f dd c9 71 91 01 9e  24 d9 f0 cf              |.O..q...$...|
0000001c

important_file.txt.C_I_0P:
Bash:
hexdump -C important_file.txt.C_I_0P
00000000  00 ae 8b b7 4f d2 8f 7d  f5 15 f5 fa a6 cc a5 76  |....O..}.......v|
00000010  d5 7d 41 cc 2d c1 be 2e  de 9b c0 a9 98 d6 8b d4  |.}A.-...........|
00000020  3d e0 23 68 0c 44 71 71  35 81 e5 3b 54 35 e9 6d  |=.#h.Dqq5..;T5.m|
00000030  f6 07 83 e3 54 3d 6f 22  3f ce 5f b0 36 fb e5 96  |....T=o"?._.6...|
00000040  8a 51 5a 40 e4 ef c5 d6  9c 1e 1f 9e 02 07 bd 8f  |.QZ@............|
00000050  21 8b 2c 2a c9 c8 31 77  b5 90 38 3e e0 5d 85 92  |!.,*..1w..8>.]..|
00000060  59 fc 26 70 4b 97 05 fd  01 68 f3 3a 2b b1 29 79  |Y.&pK....h.:+.)y|
00000070  ec 96 da 9e 74 2d 00 00  00 00 00 00 00 00 00 00  |....t-..........|
00000080  00 ae 7e 03 00 80 81 00  00 01 00 00 00 00 00 00  |..~.............|
00000090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000a0  00 1c 00 00 00 00 00 00  00 00 10 00 00 08 00 00  |................|
000000b0  00 00 00 00 00 d1 e8 4a  68 13 67 a3 17 d1 e8 4a  |.......Jh.g....J|
000000c0  68 13 67 a3 17 fd e8 4a  68 64 1c 3c 2d ae 7e 03  |h.g....Jhd.<-.~.|
000000d0  00 00 00 00 00 01 00 00  00 00 40 80 40 1c 00 00  |..........@.@...|
000000e0  00 00 00 00 00 41 00 00  00 75 00 00 00 00 00 00  |.....A...u......|
000000f0  00 2f ff 7f 40 88 03 80  40 35 8a 04 08 18 ff 7f  |./..@...@5......|
00000100

Ничего не понятно, но очень интересно. Файл зашифрован, поэтому он так и выглядит. Убиваю все признаки малвары через kill, сохраняю эти файлы себе на основную тачку)

P.S: Я пропатчил функцию do_heartbeat(), чтобы она шифровала файлы только в одной директории. Безопасность прежде всего)

Написание декриптора

Начну разбираться, как расшифровать мой файл. Ранее я уже понял, что для шифрования используется алгоритм RC4. О нем я нашел следующую информацию:

Это потоковый шифр с переменным размером ключа. Работает в режиме OFB. Для шифрования использует S-блок размером 8x8. Его элементы представляют собой
перестановку чисел от 0 до 255, а перестановка зависит от ключа переменной длины. В алгоритме используется два счетчика i и j, которые инициализируются нулями.

Так же в прошлый раз из кода я уже вытащил ключ:

Python:
master_key = 'Jfkdskfku2ir32y7432uroduw8y7318i9018urewfdsZ2Oaifwuieh~~cudsffdsd'

Второй ключ для файла я возьму из important_file.txt.C_I_0P. Через wc посмотрю его длину:

Bash:
$ wc important_file.txt.C_I_0P                                                                                                                    
       0       3     256 important_file.txt.C_I_0P

Можно увидеть, что всего в файле 256 символов. Но стоп, если вернуться к функции EncrFile, то можно заметить, что малвара генерирует 117 символов ключа:

8.webp


Как часто шутят у меня в отделе — произошел киберобман) При первичном просмотре я не особо обратил внимание на функцию CreateKey, но вот сейчас она пригодится)

9.webp


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

10.webp


Значит из файла important_file.txt.C_I_0P по смещению 0x75 + 0x58 + 0x8 + 0x4 + 0x4 можно вытащить len. Так же можно заметить, что перед вызовом функции CreateKey ключ к файлу шифруется с помощью ssKeyKey:

C:
_rc4Full(szKeyKey, v3 - 1, rc4_key, 117u);
Createkey(pathname, rc4_key);

Обобщив всю информацию, можно составить следующий алгоритм для дешифрования:
1. Взять имя зашифрованного файла;
2. Прочитать файл с названием, состоящим из имени этого файла и расширения .C_I_0P;
3. Расшифровать первые 117 байт с помощью алгоритма RC4, чтобы получить ключ для дешифровки файла;
4. По смещению 0x75 + 0x58 + 0x8 + 0x4 + 0x4 получить длину зашифрованной части файла len;
5. Расшифровать len байт зашифрованного файла, добавить оставшиеся байты и сохранить на диск;

Напишу код на Python:

Python:
from arc4 import ARC4
import sys
import struct

def get_file_key(file: str) -> bytes:
    key_file_name = file + '.C_I_0P'
    print(f'[*] Read encrypted file key from {key_file_name}')
    with open(key_file_name, 'rb') as f:
        key = f.readline()
    return key

def main(file: str) -> None:
    master_key = (b'Jfkdskfku2ir32y7432uroduw8y7318i90'
                  b'18urewfdsZ2Oaifwuieh~~cudsffdsd')
    gen_len = 0x75
    file_key = get_file_key(file)
    print('[*] Extract encrypetd file len')
    # 0x58 + 0x75 + 0x8 + 0x4 + 0x4
    file_len_offset = 0x58 + 0x75 + 0x8 + 0x4 + 0x4
    try:
        encr_file_size = struct.unpack(
                'Q',
                file_key[file_len_offset: file_len_offset + 0x8]
        )[0]
    except struct.error:
        print('[-] Wrong encrypted file len')
    print('[*] Decrypt file key')
    cryptor = ARC4(master_key)
    file_rc4_key = cryptor.decrypt(file_key)[:gen_len]
    with open(file, 'rb') as f:
        crypted_file = f.read()
        cryptor = ARC4(file_rc4_key)
        decrypted_file = cryptor.decrypt(crypted_file[:encr_file_size])
        decrypted_file += crypted_file[encr_file_size:]
        decrypted_file_path = file + '.decrypted'
        print(f'[*] Save decrypted file to {decrypted_file_path}')
        with open(file + '.decrypted', 'wb') as f:
            f.write(decrypted_file)
    print('[*] Done')

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print(f'Usage {sys.argv[0]} <encrypted file>')
    else:
        main(sys.argv[1])

Протестировал на своем файле. Предлагаю и вам)

Сделано для @coffee_cube

Файлы для скачивания

Malware Link
:
important_file.txt: Скачать
important_file.txt.C_I_0P: Скачать
 

Вложения

  • 10.webp
    10.webp
    83,8 КБ · Просмотры: 12
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab