[IT-инфраструктура, Информационная безопасность, Исследования и прогнозы в IT, Реверс-инжиниринг] Loki 1.8: досье на молодой и подающий надежды Data Stealer

Автор Сообщение
news_bot ®

Стаж: 6 лет 2 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
16-Сен-2020 14:30


В середине июня борьба с коронавирусом в Казахстане была в самом разгаре. Встревоженные ростом числа заболевших (тогда заразился даже бывший президент Нурсултан Назарбаев), местные власти решились вновь позакрывать все торгово-развлекательные центры, сетевые магазины, рынки и базары. И в этот момент ситуацией воспользовались киберпреступники, отправившие по российским и международным компаниям вредоносную рассылку.
Опасные письма, замаскированную под обращение министра здравоохранения Республики Казахстан, перехватила система Threat Detection System (TDS) Group-IB. Во вложении письма находились документы, при запуске которых на компьютер устанавливалась вредоносная программа из семейства Loki PWS (Password Stealer), предназначенная для кражи логинов и паролей с зараженного компьютера. В дальнейшем злоумышленники могут использовать их для получения доступа к почтовым аккаунтам для финансового мошенничества, шпионажа или продать на хакерских форумах.
В этой статье Никита Карпов, аналитик CERT-GIB, рассматривает экземпляр одного из самых популярных сейчас Data Stealer’ов — Loki.
Сегодня мы рассмотрим одну из популярных версий бота — 1.8. Она активно продается, а админ панель можно найти даже в открытом доступе: здесь.
Пример админ-панели:

Loki написан на языке C++ и является одним из самых популярных ВПО, используемых для похищения пользовательской информации с зараженного компьютера. Как и бич нашего времени — вирусы-шифровальщики — Data Stealer после попадания на компьютер жертвы с очень большой скоростью выполняют поставленную задачу — ему не надо закрепляться и повышать свои привилегии в системе, он практически не оставляет времени на защиту от атаки. Поэтому в событиях с ВПО, которое похищает пользовательские данные, главную роль играет расследование инцидента.
Распаковка и получение работоспособного дампа ВПО
Распространение в большинстве случаев происходит через вложения в рассылках писем. Пользователь под видом легитимного файла загружает и открывает вложение, запуская работу ВПО.
По маркеру инжекта можно предположить о наличии Loader.

С помощью DIE получаем информацию, что исходный файл написан на VB6.

График энтропии свидетельствует о большом количестве зашифрованных данных.

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

Выполняем дамп фрагмента памяти, содержащего Loki, и производим корректировку PE-заголовка.
Работоспособность дампа проверим с помощью системы TDS Huntbox.

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

Названия функций для удобства были переименованы в более информативные.
Функционал бота определяется двумя главными функциями:
  • Data Stealer — первая функция, отвечающая за похищение данных из 101 приложения и отправку на сервер.
  • Downloader — запрос от CnC (Command & Control) команд для исполнения.

Для удобства в таблице, приведенной ниже, представлены все приложения, из которых исследуемый экземпляр Loki пытается похитить данные.
ID функции
Приложение
ID функции
Приложение
ID функции
Приложение
1
Mozilla Firefox
35
FTPInfo
69
ClassicFTP
2
Comodo IceDragon
36
LinasFTP
70
PuTTY/KiTTY
3
Apple Safari
37
FileZilla
71
Thunderbird
4
K-Meleon
38
Staff-FTP
72
Foxmail
5
SeaMonkey
39
BlazeFtp
73
Pocomail
6
Flock
40
NETFile
74
IncrediMail
7
NETGATE BlackHawk
41
GoFTP
75
Gmail notifier pro
8
Lunascape
42
ALFTP
76
Checkmail
9
Google Chrome
43
DeluxeFTP
77
WinFtp
10
Opera
44
Total Commander
78
Martin Prikryl
11
QTWeb Browser
45
FTPGetter
79
32BitFtp
12
QupZilla
46
WS_FTP
80
FTP Navigator
13
Internet Explorer
47
Mail Client configuration files
81
Mailing
(softwarenetz)
14
Opera 2
48
Full Tilt Poker
82
Opera Mail
15
Cyberfox
49
PokerStars
83
Postbox
16
Pale Moon
50
ExpanDrive
84
FossaMail
17
Waterfox
51
Steed
85
Becky!
18
Pidgin
52
FlashFXP
86
POP3
19
SuperPutty
53
NovaFTP
87
Outlook
20
FTPShell
54
NetDrive
88
Ymail2
21
NppFTP
55
Total Commander 2
89
Trojitá
22
MyFTP
56
SmartFTP
90
TrulyMail
23
FTPBox
57
FAR Manager
91
.spn Files
24
sherrod FTP
58
Bitvise
92
To-Do Desklist
25
FTP Now
59
RealVNC
TightVNC
93
Stickies
26
NexusFile
60
mSecure Wallet
94
NoteFly
27
Xftp
61
Syncovery
95
NoteZilla
28
EasyFTP
62
FreshFTP
96
Sticky Notes
29
SftpNetDrive
63
BitKinex
97
KeePass
30
AbleFTP
64
UltraFXP
98
Enpass
31
JaSFtp
65
FTP Now 2
99
My RoboForm
32
Automize
66
Vandyk SecureFX
100
1Password
33
Cyberduck
67
Odin Secure FTP Expert
101
Mikrotik WinBox
34
Fullsync
68
Fling
На этом этапе завершен статический анализ ВПО и в следующем разделе рассмотрим, как Loki общается с сервером.
Сетевое взаимодействие

Для записи сетевого взаимодействия необходимо решить две проблемы:
  • Командный центр доступен только на момент проведения атаки.
  • Wireshark не фиксирует коммуникации бота в loopback, поэтому нужно пользоваться другими средствами.

Самое простое решение — переадресовать адрес CnC, с которым Loki будет устанавливать коммуникацию, на localhost. Для бота сервер теперь доступен в любое время, хоть и не отвечает, но для записи коммуникаций бота это и не нужно. Для решения второй проблемы воспользуемся утилитой RawCap, которая позволяет записать в pcap необходимые нам коммуникации. Далее записанный pcap будем разбирать уже в Wireshark.

Перед каждой коммуникацией бот проверяет доступность CnC и, если он доступен — открывает socket. Все сетевые коммуникации проходят на транспортном уровне по протоколу TCP, а на прикладном используется HTTP.
В таблице ниже представлены заголовки пакета, которые стандартно использует Loki.
Поле
Значение
Описание
User-agent
Mozilla/4.08 (Charon; Inferno)
Характерный юзерагент для Loki
Accept
*/*
Content-Type
application/octet-stream
Content-Encoding
binary
Content-Key
7DE968CC
Результат хеширования предыдущих заголовков (хеширование происходит кастомным алгоритмом CRC с полиномом 0xE8677835)
Connection
close
Обратим внимание на body пакета:
  • Структура записанных данных зависит от версии бота, и в более ранних версиях отсутствуют поля, которые отвечают за опции шифрования и компрессии.
  • По типу запроса сервер определяет, как обрабатывать полученные данные. Существует 7 типов данных, которые может прочитать сервер:
    • 0x26 Похищенные данные кошельков
    • 0x27 Похищенные данные приложений
    • 0x28 Запрос команд от сервера
    • 0x29 Выгрузка похищенного файла
    • 0x2A POS
    • 0x2B Данные кейлоггера
    • 0x2C Скриншот
  • В исследованном экземпляре присутствовали только 0x27, 0x28 и 0x2B.
  • В каждом запросе есть общая информация о боте и зараженной системе, по которой сервер идентифицирует все отчеты по одной машине, а после идет информация, которая зависит от типа запроса.
  • В последней версии бота реализовано только сжатие данных, а поля с шифрованием заготовлены на будущее и не обрабатываются сервером.
  • Для сжатия данных используется открытая библиотека APLib.

При формировании запроса с похищенными данными бот выделяет буфер размером 0x1388 (5000 байт). Структура запросов 0x27 представлена в таблице ниже:
Смещение
Размер
Значение
Описание
0x0
0x2
0x0012
Версия бота
0x2
0x2
0x0027
Тип запроса (отправка похищенных данных)
0x4
0xD
ckav.ru
Binary ID (также встречается значение XXXXX11111)
0x11
0x10
-
Имя пользователя
0x21
0x12
-
Имя компьютера
0x33
0x12
-
Доменное имя компьютера
0x45
0x4
-
Разрешение экрана (ширина и высота)
0x49
0x4
-
0x4D
0x2
0x0001
Флаг прав пользователя (1, если администратор)
0x4F
0x2
0x0001
Флаг идентификатора безопасности (1, если установлен)
0x51
0x2
0x0001
Флаг разрядности системы (1, если x64)
0x53
0x2
0x0006
Версия Windows (major version number)
0x55
0x2
0x0001
Версия Windows (minor version number)
0x57
0x2
0x0001
Дополнительная информация о системе (1 = VER_NT_WORKSTATION)
0x59
0x2
-
0x5B
0x2
0x0000
Отправлялись ли похищенные данные
0x5D
0x2
0x0001
Использовалось ли сжатие данных
0x5F
0x2
0x0000
Тип сжатия
0x61
0x2
0x0000
Использовалось ли шифрование данных
0x63
0x2
0x0000
Тип шифрования
0x65
0x36
-
MD5 от значения регистра MachineGuid
0x9B
-
-
Сжатые похищенные данные
Второй этап взаимодействия с сервером начинается после закрепления в системе. Бот отправляет запрос с типом 0x28, структура которого представлена ниже:
Размер буфера: 0x2BC (700 байт)
Смещение
Размер
Значение
Описание
0x0
0x2
0x0012
Версия бота
0x2
0x2
0x0028
Тип запроса (запрос команд от командного центра)
0x4
0xD
ckav.ru
Binary ID (также встречается значение XXXXX11111)
0x11
0x10
-
Имя пользователя
0x21
0x12
-
Имя компьютера
0x33
0x12
-
Доменное имя компьютера
0x45
0x4
-
Разрешение экрана (ширина и высота)
0x49
0x4
-
0x4D
0x2
0x0001
Флаг прав пользователя (1, если администратор)
0x4F
0x2
0x0001
Флаг идентификатора безопасности (1, если установлен)
0x51
0x2
0x0001
Флаг разрядности системы (1, если x64)
0x53
0x2
0x0006
Версия Windows (major version number)
0x55
0x2
0x0001
Версия Windows (minor version number)
0x57
0x2
0x0001
Дополнительная информация о системе (1 = VER_NT_WORKSTATION)
0x59
0x2
0xFED0
0x5B
0x36
-
MD5 от значения регистра MachineGuid
После запроса бот ожидает получить ответ от сервера, содержащий количество и сами команды. Возможные варианты команд получены с помощью статического анализа декомпилированного кода ВПО и представлены ниже.
Размер буфера: 0x10 (16 байт) + 0x10 (16 байт) за каждую команду в пакете.
HTTP- заголовок (начало данных)
\r\n\r\n
[0D 0A 0D 0A]
4 байта
Суммарная длина данных
-
-
4 байта
Количество команд
2
[00 00 00 02]
4 байта
Команда
Пропускаемые байты
4 байта
Команды
4 байта
Пропускаемые байты
4 байта
Длина передаваемой строки
4 байта
Передаваемая строка
(пример)
#0
Загрузка и запуск EXE-файла
[00 00 00 00]
[00 00 00 00]
[00 00 00 00]
[00 00 00 23]
www.notsogood.site/malicious.exe
#1
Загрузка библиотеки DLL
[00 00 00 00]
[00 00 00 01]
[00 00 00 00]
[00 00 00 23]
www.notsogood.site/malicious.dll
#2
Загрузка EXE-файла
[00 00 00 00]
[00 00 00 02]
[00 00 00 00]
[00 00 00 23]
www.notsogood.site/malicious.exe
#8
Удаление базы данных хешей (HDB file)
[00 00 00 00]
[00 00 00 08]
[00 00 00 00]
[00 00 00 00]
-
#9
Старт кейлоггера
[00 00 00 00]
[00 00 00 09]
[00 00 00 00]
[00 00 00 00]
-
#10
Похищение данных и отправка на сервер
[00 00 00 00]
[00 00 00 0A]
[00 00 00 00]
[00 00 00 00]
-
#14
Завершение работы Loki
[00 00 00 00]
[00 00 00 0E]
[00 00 00 00]
[00 00 00 00]
-
#15
Загрузка новой версии Loki и удаление старой
[00 00 00 00]
[00 00 00 0F]
[00 00 00 00]
[00 00 00 23]
www.notsogood.site/malicious.exe
#16
Изменение частоты проверки ответа от сервера
[00 00 00 00]
[00 00 00 10]
[00 00 00 00]
[00 00 00 01]
5
#17
Удалить Loki и завершить работу
[00 00 00 00]
[00 00 00 11]
[00 00 00 00]
[00 00 00 00]
-
Парсер сетевого трафика

Благодаря проведенному анализу у нас есть вся необходимая информация для парсинга сетевых взаимодействий Loki.
Парсер реализован на языке Python, на вход получает pcap-файл и в нем находит все коммуникации, принадлежащие Loki.
Для начала воспользуемся библиотекой dkpt для поиска всех TCP-пакетов. Для получения только http-пакетов поставим фильтр на используемый порт. Среди полученных http-пакетов отберем те, что содержат известные заголовки Loki, и получим коммуникации, которые необходимо распарсить, чтобы извлечь из них информацию в читаемом виде.
for ts, buf in pcap:
    eth = dpkt.ethernet.Ethernet(buf)
    if not isinstance(eth.data, dpkt.ip.IP):
        ip = dpkt.ip.IP(buf)
    else:
        ip = eth.data
    if isinstance(ip.data, dpkt.tcp.TCP):
        tcp = ip.data
        try:
            if tcp.dport == 80 and len(tcp.data) > 0:  # HTTP REQUEST
                if str(tcp.data).find('POST') != -1:
                    http += 1
                    httpheader = tcp.data
                    continue
                else:
                    if httpheader != "":
                        print('Request information:')
                        pkt = httpheader + tcp.data
                        httpheader = ""
                        if debug:
                            print(pkt)
                        req += 1
                        request = dpkt.http.Request(pkt)
                        uri = request.headers['host'] + request.uri
                        parsed_payload['Network']['Source IP'] = socket.inet_ntoa(ip.src)
                        parsed_payload['Network']['Destination IP'] = socket.inet_ntoa(ip.dst)
                        parsed_payload_same['Network']['CnC'] = uri
                        parsed_payload['Network']['HTTP Method'] = request.method
                        if uri.find("fre.php"):
                            print("Loki detected!")
                        pt = parseLokicontent(tcp.data, debug)
                        parsed_payload_same['Malware Artifacts/IOCs']['User-Agent String'] = request.headers['user-agent']
                        print(json.dumps(parsed_payload, ensure_ascii=False, sort_keys=False, indent=4))
                        parsed_payload['Network'].clear()
                        parsed_payload['Compromised Host/User Data'].clear()
                        parsed_payload['Malware Artifacts/IOCs'].clear()
                        print("----------------------")
            if tcp.sport == 80 and len(tcp.data) > 0:  # HTTP RESPONCE
                resp += 1
                if pt == 40:
                    print('Responce information:')
                    parseC2commands(tcp.data, debug)
                    print("----------------------")
                    pt = 0
        except(dpkt.dpkt.NeedData, dpkt.dpkt.UnpackError):
            continue

Во всех запросах Loki первые 4 байта отвечают за версию бота и тип запроса. По этим двум параметрам определяем, как будем обрабатывать данные.
def parseLokicontent(data, debug):
    index = 0
    botV = int.from_bytes(data[0:2], byteorder=sys.byteorder)
    parsed_payload_same['Malware Artifacts/IOCs']['Loki-Bot Version'] =  botV
    payloadtype = int.from_bytes(data[2:4], byteorder=sys.byteorder)
    index = 4
    print("Payload type: : %s" % payloadtype)
    if payloadtype == 39:
        parsed_payload['Network']['Traffic Purpose'] =  "Exfiltrate Application/Credential Data"
        parse_type27(data, debug)
    elif payloadtype == 40:
        parsed_payload['Network']['Traffic Purpose'] = "Get C2 Commands"
        parse_type28(data, debug)
    elif payloadtype == 43:
        parsed_payload['Network']['Traffic Purpose'] = "Exfiltrate Keylogger Data"
        parse_type2b(lb_payload)
    elif payloadtype == 38:
        parsed_payload['Network']['Traffic Purpose'] = "Exfiltrate Cryptocurrency Wallet"
    elif payloadtype == 41:
        parsed_payload['Network']['Traffic Purpose'] = "Exfiltrate Files"
    elif payloadtype == 42:
        parsed_payload['Network'].['Traffic Purpose'] = "Exfiltrate POS Data"
    elif payloadtype == 44:
        parsed_payload['Network']['Traffic Purpose'] = "Exfiltrate Screenshots"
    return payloadtype

Следующим в очереди будет разбор ответа от сервера. Для считывания только полезной информации ищем последовательность \r\n\r\n, которая определяет конец заголовков пакета и начало команд от сервера.
def parseC2commands(data, debug):
    word = 2
    dword = 4
    end = data.find(b'\r\n\r\n')
    if end != -1:
        index = end + 4
        if (str(data).find('<html>')) == -1:
            if debug:
                print(data)
            fullsize = getDWord(data, index)
            print("Body size: : %s" % fullsize)
            index += dword
            count = getDWord(data, index)
            print("Commands: : %s" % count)
            if count == 0:
                print('No commands received')
            else:
                index += dword
                for i in range(count):
                    print("Command: %s" % (i + 1))
                    id = getDWord(data, index)
                    print("Command ID: %s" % id)
                    index += dword
                    type = getDWord(data, index)
                    print("Command type: %s" % type)
                    index += dword
                    timelimit = getDWord(data, index)
                    print("Command timelimit: %s" % timelimit)
                    index += dword
                    datalen = getDWord(data, index)
                    index += dword
                    command_data = getString(data, index, datalen)
                    print("Command data: %s" % command_data)
                    index += datalen
        else:
            print('No commands received')
    return None

На этом заканчиваем разбор основной части алгоритма работы парсера и переходим к результату, который получаем на выходе. Вся информация выводится в json-формате.
Ниже представлены изображения результата работы парсера, полученные из коммуникаций различных ботов, с разными CnC и записанные в разных окружениях.
Request information:
Loki detected!
Payload type: 39
Decompressed data:
{'Module': {'Mozilla Firefox'}, 'Version': {0}, 'Data': {'domain': {'https://accounts.google.com'}, 'username': {'none@gmail.com'}, 'password': {'test'}}}
{'Module': {'NppFTP'}, 'Version': {0}, 'Data': {b'<?xml version="1.0" encoding="UTF-8" ?>\r\n<NppFTP defaultCache="%CONFIGDIR%\\Cache\\%USERNAME%@%HOSTNAME%" outputShown="0" windowRatio="0.5" clearCache="0" clearCachePermanent="0">\r\n    <Profiles />\r\n</NppFTP>\r\n'}}
{
    "Network": {
        "Source IP": "-",
        "Destination IP": "185.141.27.187",
        "HTTP Method": "POST",
        "Traffic Purpose": "Exfiltrate Application/Credential Data",
        "First Transmission": true
    },
    "Compromised Host/User Data": {},
    "Malware Artifacts/IOCs": {}
}

Выше представлен пример запроса на сервер 0x27 (выгрузка данных приложений). Для тестирования были созданы аккаунты в трех приложениях: Mozilla Firefox, NppFTP и FileZilla. У Loki существует три варианта записи данных приложений:
  • В виде SQL-базы данных (парсер сохраняет базу данных и выводит все доступные строки в ней).
  • В открытом виде, как у Firefox в примере.
  • В виде xml-файла, как у NppFTP и FileZilla.

Request information:
Loki detected!
Payload type: 39
No data stolen
{
    "Network": {
        "Source IP": "-",
        "Destination IP": "185.141.27.187",
        "HTTP Method": "POST",
        "Traffic Purpose": "Exfiltrate Application/Credential Data",
        "First Transmission": false
    },
    "Compromised Host/User Data": {},
    "Malware Artifacts/IOCs": {}
}

Второй запрос имеет тип 0x28 и запрашивает команды от сервера.
Responce information:
Body size: 26
Commands: 1
Command: 1
Command ID: 0
Command type: 9
Command timelimit: 0
Command data: 35

Пример ответа от CnC, который отправил в ответ одну команду на старт кейлоггера. И последующая выгрузка данных кейлоггера.
Request information:
Loki detected!
Payload type: : 43
{
    "Network": {
        "Source IP": "-",
        "Destination IP": "185.141.27.187",
        "HTTP Method": "POST",
        "Traffic Purpose": "Exfiltrate Keylogger Data"
    },
    "Compromised Host/User Data": {},
    "Malware Artifacts/IOCs": {}
}

В конце работы парсер выводит информацию, которая содержится в каждом запросе от бота (информацию о боте и о системе), и количество запросов и ответов, связанных с Loki в pcap-файле.
General information:
{
    "Network": {
        "CnC": "nganyin-my.com/chief6/five/fre.php"
    },
    "Compromised Host/User Description": {
        "User Name": "-",
        "Hostname": "-",
        "Domain Hostname": "-",
        "Screen Resolution": "1024x768",
        "Local Admin": true,
        "Built-In Admin": true,
        "64bit OS": false,
        "Operating System": "Windows 7 Workstation"
    },
    "Malware Artifacts/IOCs": {
        "Loki-Bot Version": 18,
        "Binary ID": "ckav.ru",
        "MD5 from GUID": "-",
        "User-Agent String": "Mozilla/4.08 (Charon; Inferno)"
    }
}
Requests: 3
Responces: 3

Полный код парсера доступен по ссылке: github.com/Group-IB/LokiParser
Заключение

В этой статье мы ближе познакомились с ВПО Loki, разобрали его функционал и реализовали парсер сетевого трафика, который значительно упростит процесс анализа инцидента и поможет понять, что именно было похищено с зараженного компьютера. Хотя разработка Loki все еще продолжается, была слита только версия 1.8 (и более ранние), именно с этой версией специалисты по безопасности сталкиваются каждый день.
В следующей статье мы разберем еще один популярный Data Stealer, Pony, и сравним эти ВПО.
Indicator of Compromise (IOCs):

Urls:
  • nganyin-my.com/chief6/five/fre.php
  • wardia.com.pe/wp-includes/texts/five/fre.php
  • broken2.cf/Work2/fre.php
  • 185.141.27.187/danielsden/ver.php
  • MD5 hash: B0C33B1EF30110C424BABD66126017E5
  • User-Agent String: «Mozilla/4.08 (Charon; Inferno)»
  • Binary ID: «ckav.ru»

===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_itinfrastruktura (IT-инфраструктура), #_informatsionnaja_bezopasnost (Информационная безопасность), #_issledovanija_i_prognozy_v_it (Исследования и прогнозы в IT), #_reversinzhiniring (Реверс-инжиниринг), #_malware, #_vredonos (вредонос), #_vpo (ВПО), #_vredonosnoe_po (вредоносное ПО), #_stealer, #_stiler (стилер), #_vredonosnoe_programmnoe_obespechenie (вредоносное программное обеспечение), #_analiz_koda (анализ кода), #_analiz_virusov (анализ вирусов), #_analiz_vredonosov (анализ вредоносов), #_analiz_vredonosnogo_po (анализ вредоносного по), #_blog_kompanii_groupib (
Блог компании Group-IB
)
, #_itinfrastruktura (
IT-инфраструктура
)
, #_informatsionnaja_bezopasnost (
Информационная безопасность
)
, #_issledovanija_i_prognozy_v_it (
Исследования и прогнозы в IT
)
, #_reversinzhiniring (
Реверс-инжиниринг
)
Профиль  ЛС 
Показать сообщения:     

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

Текущее время: 28-Апр 16:09
Часовой пояс: UTC + 5