НОВОСТИ Loki 1.8: досье на молодой и подающий надежды Data Stealer

NewsBot
Оффлайн

NewsBot

.
.
Регистрация
21.07.20
Сообщения
40.408
Реакции
1
Репутация
0
bgtyb0k_fuonrpa0kg6rp8qs09y.jpeg


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

Опасные письма, замаскированную под обращение министра здравоохранения Республики Казахстан, перехватила система Threat Detection System (TDS) Group-IB. Во вложении письма находились документы, при запуске которых на компьютер устанавливалась вредоносная программа из семейства Loki PWS (Password Stealer), предназначенная для кражи логинов и паролей с зараженного компьютера. В дальнейшем злоумышленники могут использовать их для получения доступа к почтовым аккаунтам для финансового мошенничества, шпионажа или продать на хакерских форумах.

В этой статье Никита Карпов, аналитик CERT-GIB, рассматривает экземпляр одного из самых популярных сейчас Data Stealer’ов — Loki.

Сегодня мы рассмотрим одну из популярных версий бота — 1.8. Она активно продается, а админ панель можно найти даже в открытом доступе: .

Пример админ-панели:

fdhrmf1qxmbpp1l6ixtf9bzt08s.png



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

Распаковка и получение работоспособного дампа ВПО


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

По маркеру инжекта можно предположить о наличии Loader.

q6e_o5t5mkyfrqdyeczac0rbl_4.png


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

df27esvpqausmg8u_dp1_ob2um0.png


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

j1pvn9e0h0nmsmxcq40sh-roszu.png


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

zkk4v1cokcv8ftkbbb7swqctttq.png


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

Работоспособность дампа проверим с помощью системы TDS Huntbox.

dcwmgytf_cenf6ahlgm2rgnoszc.png


Функционал бота


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

unzzjpmtsb7tma26-nrcigroi1y.png


Названия функций для удобства были переименованы в более информативные.
Функционал бота определяется двумя главными функциями:

  1. Data Stealer — первая функция, отвечающая за похищение данных из 101 приложения и отправку на сервер.
  2. 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 общается с сервером.

Сетевое взаимодействие


Для записи сетевого взаимодействия необходимо решить две проблемы:

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

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

t9p4yowgegbbodvzrx4mjr2n4ns.png


Перед каждой коммуникацией бот проверяет доступность 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 пакета:

  1. Структура записанных данных зависит от версии бота, и в более ранних версиях отсутствуют поля, которые отвечают за опции шифрования и компрессии.
  2. По типу запроса сервер определяет, как обрабатывать полученные данные. Существует 7 типов данных, которые может прочитать сервер:
    • 0x26 Похищенные данные кошельков
    • 0x27 Похищенные данные приложений
    • 0x28 Запрос команд от сервера
    • 0x29 Выгрузка похищенного файла
    • 0x2A POS
    • 0x2B Данные кейлоггера
    • 0x2C Скриншот
  3. В исследованном экземпляре присутствовали только 0x27, 0x28 и 0x2B.
  4. В каждом запросе есть общая информация о боте и зараженной системе, по которой сервер идентифицирует все отчеты по одной машине, а после идет информация, которая зависит от типа запроса.
  5. В последней версии бота реализовано только сжатие данных, а поля с шифрованием заготовлены на будущее и не обрабатываются сервером.
  6. Для сжатия данных используется открытая библиотека 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]



#1
Загрузка библиотеки DLL

[00 00 00 00]

[00 00 00 01]

[00 00 00 00]

[00 00 00 23]



#2
Загрузка EXE-файла

[00 00 00 00]

[00 00 00 02]

[00 00 00 00]

[00 00 00 23]



#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]



#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('')) == -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': {' '}, 'username': {'[email protected]'}, 'password': {'test'}}}
{'Module': {'NppFTP'}, 'Version': {0}, 'Data': {b'\r\n\r\n
\r\n\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 существует три варианта записи данных приложений:

  1. В виде SQL-базы данных (парсер сохраняет базу данных и выводит все доступные строки в ней).
  2. В открытом виде, как у Firefox в примере.
  3. В виде 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


Полный код парсера доступен по ссылке:

Заключение


В этой статье мы ближе познакомились с ВПО 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»
 
Сверху Снизу