всем привет
по поводу моей прошлой статьи - к сожалению она была вырезана по причине не портить бизнес кодеру, ну и ладно
сегодня на руках сэмпл Amatera Stealer MaaS полученный путем хантинга app.any.run по метке stealer
по цене - 200$ за месяц, 500$ за 3 месяца, 900$ за 6 месяцев и 1500$ за 1 год
ехе никак не защищена и не закриптована - разобрать ее будет очень просто, чем я и занимался весь день(статью пишу под ночь)
у аналитиков на руках была более новая версия, в то время как я похоже смотрю на самые первые версии
функционал билда -
А теперь с технической стороны -
Билд весит всего 49кб
В билде отсутствует Анти-СНГ либо намеки на него, не исключаю, что веб при распарсе лога просто не примет его при нахождении русской/ любой другой снгшной локали
Переопределены операторы free, malloc
Скрытие вызовов через GetProcAddress
Заменены CRT функции:
#1 точка входа
Когда жертва запускает стиллак, то первым делом Amatera грузит либы из которых потом будет через вызов винапи GetProcAddress вытягивать адреса и вызывать их
Прошу заметить, что строки не зашифрованы во всем билде
После этого Amatera стучится на веб и хочет создать сессию по GUID, куда будет потом пофайлово закидывать лог
Для обмена пакетов между панелью и билдом стиллер использует обычное шифрование RC4
#2 Зачатки обфускации
Во всем билде имеются только 2 явных WinAPI колла - GetProcAddress и LoadLibraryW
Дальше я опишу как происходит вызов экспорта какой-либо библиотеки(или просто WinAPI)
В коде вызов выглядит вот так ->
CallProcAddress является простой оберткой ->
Некоторые функции имеют свой typedef и функцию поиска, в то время как другие в целях оптимизации могут делить одни и те же определения из-за оптимизации компилятора
Сам по себе стиллер очень простой, но стоит ему добавить ксор на строки с сисколлами и можно уже пушить на рынок(похоже,что это и есть итерация ближайшая к финальной)
#3 Граб железа
Выполняется 1ой функцией вызванной из entry стиллера, по завершению отправляет результат на сервак
Быстрый врайтап на эти функции сверху:
get_machine_guid - читает "guid" из "SOFTWARE\\Microsoft\\Cryptography"
get_computer_name - вызов GetComputerNameW апи
get_os_name - читает "ProductName" из "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
get_install_date - читает "InstallDate" из "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
get_current_user_locale - просто вызов GetUserDefaultLocaleName
get_time_zone - вызов GetDynamicTimeZoneInformation + высчитывание timezone bias
get_resolution_and_gpu_name - вызов EnumDisplaySettingsW, распарс с добавлением "x" между числами, потом EnumDisplayDevicesW для получения модели ГПУ
get_cpu_name - читает "ProcessorNameString" из "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"
get_total_ram - вызов GetPhysicallyInstalledSystemMemory
get_stealer_start_path - вызов GetModuleFileNameW
get_installed_applications - читает список из "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall" и потом парсит его
get_process_list - самый обычный геттер процессов через вызов CreateToolhelp32Snapshot
get_screenshot - вызов BitBlt, дальше не вижу смысла расписывать
get_clipboard_contents - вызов OpenClipboard, GetClipboardData, GlobalLock
#4 Граб телеги и стима и пр
В точке входа вызывается функция, которая потом вызывает внутри себя grab_steam + grab_telegram, так-что назовем эту функцию get_applications
Внутри себя она просто вызывает ExpandEnvironmentStringsW для получения путей
Для граба стима стиллер стучится в реестр и читает там "InstallPath" в "SOFTWARE\\WOW6432Node\\Valve\\Steam", после чего грабает все файлы по следующей маске -> "*.vdf"
Для граба телеги стиллер вызывает ExpandEnvironmentStringsW с аргументом "%appdata%\\Telegram Desktop\\tdata", после чего грабает тележку вызовом обертки ReadFile
К сожалению, меня не хватило на разбор того, что отправляется в панель с меткой wallets и grabber, но там идет такой же вызов ExpandEnvironmentStringsW + поиск по маске и дальше вызов обертки ReadFile
#5 Граб хрома и эджа
Когда Amatera доходит до этапа сборки данных из хрома, то происходит следующий процесс:
Сначала Amatera пытается грабнуть state_key из Local State, а если это не выходит, то вызывается уже app_bound_encrypted_key декрипт
Если описывать этот декрипт просто, то он выглядит вот так:
1. получить app_bound_encrypted_key
2. ^если не получилось, возвращаем 0
3. если app_bound_encrypted_key > 5, то создаем зомби процесс через CreateProcessW
4. аллоцируем в зомби процессе память
5. пишем в память зомбированного браузера шелл + плейсхолдер под app_bound_encrypted_key
6. CreateRemoteThread, WaitForSingleObject (если нужно обьяснение, то лучше пропустите это)
7. читаем память через вызов ReadProcessMemory
8. VirtualFreeEx, CloseHandle на все
9. найти и завершить процесс
Я не знаю почему, но мне кажется, что скорее всего это было спащенно с гитхаба, но не гарантирую
После всех этих манипуляций стиллер просто вызывает ExitProcess с кодом 0
Execution flow стилера выглядит вот так :
1. load_dll
2. create_stealer_session
3. systeminfo_getter
4. chromium::get_profiles
5. chromium::local_state_related
6. chromium::state_key_related
7. applications(телега, стим)
8. кошельки
9. граббер файлов
В общем - стиллер не плох, но судя по тому, что пишут о нем аналитики, называя это скачком в качестве стиллеров, то что-то в этом все таки есть
добавляю экспортированный из иды .C файлик где можно поближе посмотреть на код, но сразу говорю - многого не ожидайте
по поводу моей прошлой статьи - к сожалению она была вырезана по причине не портить бизнес кодеру, ну и ладно
сегодня на руках сэмпл Amatera Stealer MaaS полученный путем хантинга app.any.run по метке stealer
по цене - 200$ за месяц, 500$ за 3 месяца, 900$ за 6 месяцев и 1500$ за 1 год
ехе никак не защищена и не закриптована - разобрать ее будет очень просто, чем я и занимался весь день(статью пишу под ночь)
у аналитиков на руках была более новая версия, в то время как я похоже смотрю на самые первые версии
функционал билда -
Отправка на хост лога по частям
Граб telegram
Граб steam
Граб инжектом в хром, edge (шелл)
^Похоже, что оно расшифровывает их на стороне веба
Граб desktop wallets
Граб файлов
Граб clipboard
Фото экрана
Граб инфы о железе(machine_guid, разрешение экрана, гпу,памяти, таймзоны, версии винды, локали юзера)
Граб списка установленных на пк программ
Граб telegram
Граб steam
Граб инжектом в хром, edge (шелл)
^Похоже, что оно расшифровывает их на стороне веба
Граб desktop wallets
Граб файлов
Граб clipboard
Фото экрана
Граб инфы о железе(machine_guid, разрешение экрана, гпу,памяти, таймзоны, версии винды, локали юзера)
Граб списка установленных на пк программ
Билд весит всего 49кб
В билде отсутствует Анти-СНГ либо намеки на него, не исключаю, что веб при распарсе лога просто не примет его при нахождении русской/ любой другой снгшной локали
Переопределены операторы free, malloc
Скрытие вызовов через GetProcAddress
Заменены CRT функции:
#1 точка входа
Когда жертва запускает стиллак, то первым делом Amatera грузит либы из которых потом будет через вызов винапи GetProcAddress вытягивать адреса и вызывать их
Прошу заметить, что строки не зашифрованы во всем билде
Код:
void amatera::stealer::entry::load_dll()
{
kernel32_handle = LoadLibraryW(L"Kernel32.dll");
crypt32_handle = LoadLibraryW(L"Crypt32.dll");
user32_handle = LoadLibraryW(L"User32.dll");
advapi32_handle = LoadLibraryW(L"Advapi32.dll");
wininet_handle = LoadLibraryW(L"Wininet.dll");
gdi32_handle = LoadLibraryW(L"Gdi32.dll");
ole32_handle = LoadLibraryW(L"Ole32.dll");
oleaut32_handle = LoadLibraryW(L"OleAut32.dll");
getProcessHeap = func_0_arg(kernel32_handle, "GetProcessHeap");
}
Для обмена пакетов между панелью и билдом стиллер использует обычное шифрование RC4
#2 Зачатки обфускации
Во всем билде имеются только 2 явных WinAPI колла - GetProcAddress и LoadLibraryW
Дальше я опишу как происходит вызов экспорта какой-либо библиотеки(или просто WinAPI)
В коде вызов выглядит вот так ->
CallProcAddress_BitBlt((HMODULE)gdi32_handle, "BitBlt", dc, 0, 0, cx, cy, hdc, 0, 0, 0xCC0020);// 0xCC0020 <--- SRCCOPY ? ? ? CallProcAddress является простой оберткой ->
Код:
__int64 __fastcall CallProcAddress_BitBlt(
HMODULE a1,
const CHAR *a2,
__int64 a3,
unsigned int a4,
unsigned int a5,
unsigned int a6,
int a7,
__int64 a8,
int a9,
int a10,
int a11)
{
FARPROC ProcAddress; // rax
ProcAddress = GetProcAddress(a1, a2);
return ((__int64 (__fastcall *)(__int64, _QWORD, _QWORD, _QWORD, int, __int64, int, int, int))ProcAddress)(
a3,
a4,
a5,
a6,
a7,
a8,
a9,
a10,
a11);
}
Сам по себе стиллер очень простой, но стоит ему добавить ксор на строки с сисколлами и можно уже пушить на рынок(похоже,что это и есть итерация ближайшая к финальной)
#3 Граб железа
Выполняется 1ой функцией вызванной из entry стиллера, по завершению отправляет результат на сервак
Код:
void __fastcall amatera::stealer::systeminfo_constructor(unsigned __int64 *information_stream)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS NUMPAD "+" TO EXPAND]
qmemcpy(v2, malloc(Size), sizeof(v2));
qmemcpy(buf, v2, sizeof(buf));
amatera::stealer::get_machine_guid(buf); // <--- HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid getter
amatera::stealer::get_computer_name(buf); // fill computer name (GetComputerNameW)
amatera::stealer::get_os_name(buf); // fill os ver & name
amatera::stealer::get_current_user_locale(buf);// fill userprofile locale
amatera::stealer::get_install_date(buf); // fill installdate
amatera::stealer::get_time_zone(buf); // fill timezone_bias(GetDynamicTimeZoneInformation)
amatera::stealer::get_resolution_and_gpu_name(buf);// fill screen resolution & gpu name
amatera::stealer::get_cpu_name(buf); // fill cpu_name
amatera::stealer::get_total_ram(buf); // fill total_ram
amatera::stealer::get_stealer_start_path(buf);// fill start_path
amatera::stealer::get_installed_applications(buf);// fill installed applications Windows\\CurrentVersion\\Uninstall
amatera::stealer::get_process_list(buf); // fill process_list
amatera::stealer::get_screenshot(buf); // fill screenshot
amatera::stealer::get_clipboard_contents(buf);// fill clipboard data
amatera::crt::append_wstr_to_format(information_stream, L"system_info", buf[2], buf[1]);
amatera::crt::free(buf);
}
get_machine_guid - читает "guid" из "SOFTWARE\\Microsoft\\Cryptography"
get_computer_name - вызов GetComputerNameW апи
get_os_name - читает "ProductName" из "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
get_install_date - читает "InstallDate" из "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
get_current_user_locale - просто вызов GetUserDefaultLocaleName
get_time_zone - вызов GetDynamicTimeZoneInformation + высчитывание timezone bias
get_resolution_and_gpu_name - вызов EnumDisplaySettingsW, распарс с добавлением "x" между числами, потом EnumDisplayDevicesW для получения модели ГПУ
get_cpu_name - читает "ProcessorNameString" из "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"
get_total_ram - вызов GetPhysicallyInstalledSystemMemory
get_stealer_start_path - вызов GetModuleFileNameW
get_installed_applications - читает список из "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall" и потом парсит его
get_process_list - самый обычный геттер процессов через вызов CreateToolhelp32Snapshot
get_screenshot - вызов BitBlt, дальше не вижу смысла расписывать
get_clipboard_contents - вызов OpenClipboard, GetClipboardData, GlobalLock
#4 Граб телеги и стима и пр
В точке входа вызывается функция, которая потом вызывает внутри себя grab_steam + grab_telegram, так-что назовем эту функцию get_applications
Внутри себя она просто вызывает ExpandEnvironmentStringsW для получения путей
Для граба стима стиллер стучится в реестр и читает там "InstallPath" в "SOFTWARE\\WOW6432Node\\Valve\\Steam", после чего грабает все файлы по следующей маске -> "*.vdf"
Для граба телеги стиллер вызывает ExpandEnvironmentStringsW с аргументом "%appdata%\\Telegram Desktop\\tdata", после чего грабает тележку вызовом обертки ReadFile
К сожалению, меня не хватило на разбор того, что отправляется в панель с меткой wallets и grabber, но там идет такой же вызов ExpandEnvironmentStringsW + поиск по маске и дальше вызов обертки ReadFile
#5 Граб хрома и эджа
Когда Amatera доходит до этапа сборки данных из хрома, то происходит следующий процесс:
Сначала Amatera пытается грабнуть state_key из Local State, а если это не выходит, то вызывается уже app_bound_encrypted_key декрипт
Если описывать этот декрипт просто, то он выглядит вот так:
1. получить app_bound_encrypted_key
2. ^если не получилось, возвращаем 0
3. если app_bound_encrypted_key > 5, то создаем зомби процесс через CreateProcessW
4. аллоцируем в зомби процессе память
5. пишем в память зомбированного браузера шелл + плейсхолдер под app_bound_encrypted_key
6. CreateRemoteThread, WaitForSingleObject (если нужно обьяснение, то лучше пропустите это)
7. читаем память через вызов ReadProcessMemory
8. VirtualFreeEx, CloseHandle на все
9. найти и завершить процесс
Я не знаю почему, но мне кажется, что скорее всего это было спащенно с гитхаба, но не гарантирую
После всех этих манипуляций стиллер просто вызывает ExitProcess с кодом 0
Execution flow стилера выглядит вот так :
1. load_dll
2. create_stealer_session
3. systeminfo_getter
4. chromium::get_profiles
5. chromium::local_state_related
6. chromium::state_key_related
7. applications(телега, стим)
8. кошельки
9. граббер файлов
В общем - стиллер не плох, но судя по тому, что пишут о нем аналитики, называя это скачком в качестве стиллеров, то что-то в этом все таки есть
добавляю экспортированный из иды .C файлик где можно поближе посмотреть на код, но сразу говорю - многого не ожидайте
Вложения
Последнее редактирование: