Всем доброго времени суток! Эта статья является мини-обзором по опенсорсному RAT на базе телеграмм бота. Статья не является каким-либо руководством к чему-либо противозаконному, разбор ниже приводится исключительно в ознакомительных целях. Ни автор софта, ни автор статьи не несет ответственности за возможный причиненный ущерб любого рода.
Github →
Использование телеграмм в качестве C&C не является чем-то новым, скорее всего просто удобным. Ничего делать особо не нужно, достаточно через батю ботов (BotFather) создать нового бота, взять его токен и вшить в зверька, как и приводится в оригинальном описании.
Ратник имеет достаточно большой функционал, где есть возможность подключаться к микрофону, к камере, также имеем функционал стиллера для сбора сохраненных паролей, клиппера для подмены адресов криптокошелька на свой, функции кейлоггера и т.д. Но так как автор более 3 лет не поддерживает свой продукт, было проведено изучение и модификация проекта.
Начнем с того, как вообще работает бот. При запуске бинарника, в отдельном потоке запускается обработчик команд. Через класс WebClient функией DownloadString() скачивается всё содержимое JSON-объекта. Затем через парсер SimpleJson получаем значение из поля id. Это ID чата того, кто написал боту. Записываем его в переменную chatId, и если ID отличается от того, что указан в конфиге, то просто игнорируем. Как уже понятно, это сделано для того, чтобы никто кроме нас не смог написать боту. Как только бот устанавливает подключение, он сообщает, что подключился готов принимать команды.
Теперь по поводу команд. Так как в проекте их обработка реализована как передача аргументов, то есть принятая команда имеет 0 индекс, вторая 1 и тд, то возникает основная проблема – это содержание пробелов. К примеру, скопировать файл из C:\Program Files\... куда-либо не получится, взять в кавычки тоже, так как JSON парсер не сможет их обработать и экранировать. Поэтому, если имеется содержание пробелов, их можно заменить символом подчеркивания.
Например, команда /CopyFile выглядит так:
Аналогично другим командам, по типу CopyDir, MoveDir, MoveFile.
Для удобства рассмотрим весь список команд. Примерно 10% было убрано, дабы уменьшить палевность зверька. И примерно 75% доработано / исправлено.
Поскольку мы говорим о неком «шпионаже», то боту нужен какой-то механизм для закрепления в системе.
Самый банальный способ – добавление себя в планировщик заданий. Удобно? Да. Но первый же опытный юзер его заметит. Поэтому, добавлять его в корень планировщика не стоит. Следует засовывать куда-то поглубже, а чтобы замаскироваться от всевидящего Autoruns, вместо бинарника бота указываем pcalua.exe, через аргументы -a <путь>
указываем уже путь на бинарник зверька. Так мы сможем убрать жирную красную строку в большом списке, которая говорит об отсутствии действительной подписи, чтобы в глаза не бросалось.
Далее, зверьку нужен какой-то механизм самозащиты. Сюда входит анти-виртуализация для защиты от запуска на виртуалке и анти-отладка, тут почти никаких изменений не было. Разве что принцип нахождения виртуальный среды. Это можно определять по модели монитора. На реальной машине будет выдана строка, а в виртуальной будет ошибка, которую можно обработать.
Далее, чтобы затруднить обнаружение бота, добавляем ещё 2 метода для двух потоков. Первый будет искать в фоне NetLimiter, второй CrowdInspect и при нахождении такового просто замораживать его. Просто завершать процесс слишком скучно)
На последок, был добавлен механизм подмены родительского процесса, от которого будут унаследованых все привиллегии.
Пока на этом всё. Дальнейшая доработка имеет место быть, проект очень интересный. Хотелось бы добавить инжектор основной полезной нагрузки, какой-нибудь патчинг AMSI и возможно изучить использование D/Invoke. Ознакомиться с проектом можно в архиве.
Пароль на архив:
Готов почитать комментарии)
Github →
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
Использование телеграмм в качестве C&C не является чем-то новым, скорее всего просто удобным. Ничего делать особо не нужно, достаточно через батю ботов (BotFather) создать нового бота, взять его токен и вшить в зверька, как и приводится в оригинальном описании.
Ратник имеет достаточно большой функционал, где есть возможность подключаться к микрофону, к камере, также имеем функционал стиллера для сбора сохраненных паролей, клиппера для подмены адресов криптокошелька на свой, функции кейлоггера и т.д. Но так как автор более 3 лет не поддерживает свой продукт, было проведено изучение и модификация проекта.
Начнем с того, как вообще работает бот. При запуске бинарника, в отдельном потоке запускается обработчик команд. Через класс WebClient функией DownloadString() скачивается всё содержимое JSON-объекта. Затем через парсер SimpleJson получаем значение из поля id. Это ID чата того, кто написал боту. Записываем его в переменную chatId, и если ID отличается от того, что указан в конфиге, то просто игнорируем. Как уже понятно, это сделано для того, чтобы никто кроме нас не смог написать боту. Как только бот устанавливает подключение, он сообщает, что подключился готов принимать команды.
Теперь по поводу команд. Так как в проекте их обработка реализована как передача аргументов, то есть принятая команда имеет 0 индекс, вторая 1 и тд, то возникает основная проблема – это содержание пробелов. К примеру, скопировать файл из C:\Program Files\... куда-либо не получится, взять в кавычки тоже, так как JSON парсер не сможет их обработать и экранировать. Поэтому, если имеется содержание пробелов, их можно заменить символом подчеркивания.
Например, команда /CopyFile выглядит так:
COPYFILE:
case "COPYFILE":
{
// Check if args exists
string path1 = "", path2 = "";
try
{
path1 = args[1].Replace('_', ' ').Replace('|', '_');
path2 = args[2].Replace('_', ' ').Replace('|', '_');
}
catch (IndexOutOfRangeException)
{
tg.sendText("No arguments <file>, <file> found!");
break;
}
// If file not exists
if (!File.Exists(path1))
{
tg.sendText(string.Format("File \"{0}\" not found!", path1));
break;
}
// Copy file
try
{
File.Copy(path1, path2);
}
catch
{
tg.sendText(string.Format("File \"{0}\" not copied to: \"{1}\"", path1, path2));
break;
}
tg.sendText(string.Format("✅ File \"{0}\" copied to: \"{1}\"", path1, path2));
break;
}
Аналогично другим командам, по типу CopyDir, MoveDir, MoveFile.
Для удобства рассмотрим весь список команд. Примерно 10% было убрано, дабы уменьшить палевность зверька. И примерно 75% доработано / исправлено.
/ComputerInfo – Сбор информации о системе. Это первое, что следует выполнить на удаленной машине, дабы знать, с чем мы работаем. Пример:
Здесь думаю всё понятно, не будет останавливаться.
/ActiveWindow – узнать текст заголовка активного окна. Чем это может быть полезно? Например, в заголовке содержится название проигрывателя, или музыкальная композиция – понятно, жертва слушает музыку. Или другой пример, в заголовке имеется название соц. Сети или переписка. Тут можно сделать скриншот, не привлекая внимания, об этом позже.
/Whoami – узнать привилегии в системе. Стандартная команда консоли, выполненная нестандартным способом. Так как на whoami ругаются многие AV, то стоит задействовать WMI.
Так мы будем знать, какие у нас права. Аналогичным способом узнаем имя компьютера и имя пользователя по процессу проводника (explorer.exe).
/ProcessList – Вывести список процессов c их process id (svchost исключен по умолчанию, так как он не представляет интерес и его очень много). Тут ничего необычного, но, есть важный момент. Телеграм бот не способен передавать более 4096 символов одним сообщением, это ограничение самого телеграма. Поэтому делаем некие нарезания по 4096 символов, если сообщение не умещается.
/ProcessKill <процесс> - Убить указанный процесс по его имени. Указывать .exe в конце не нужно. Все процессы, которые имеют это имя, будут закрыты;
/ProcessKillid <pid> - То же, что и ProcessKill, но по id конкретного процесса;
/ProcessStart <процесс> - Запустить процесс, указав имя исполняемого файла или его полный путь;
/ProcessFreeze <id> [timeout] – Приостановить (заморозить) процесс. Можно, но не обязательно, указать timeout – время, по истечении которого бот снова возобновит указанный процесс;
/MakeUntrusted <имяпроцесса> - “Поломать” указанный процесс по имени (ставит уровень целостности на Недоверенный). Удаляет привилегии у процесса. Лучше не применять на svchost. Это сделает винду полурабочей и придется выключать с кнопки. Забавный результат будет, если натравить на диспетчер задач или тот же ProcessHacker, наши подопытные будут лишены возможности просматривать какие либо процессы до перезапуска.
/ProcAddEx <процесс1,процесс2...> - Добавляет в исключение имена выводимых процессов для команды /processlist. Например, у нас имеется многочисленные процессы браузера, которые также не представляют интерес. На данный момент исключенные имена процессов нигде не сохраняются. При следующем запуске бота снова будет 1 исключенный svchost.
/ProcRemEx <процесс1,процесс2...> - Удаляет исключенные имена выводимых процессов для команды /processlist;
/ProcShowExList – Показать, какие процессы исключены и не выводятся по команде /processlist;
/MinimizeAllWindows – свернуть все окна;
/MaximizeAllWindows – развернуть все окна;
/CreateFile <C:\путь\к\файлу.txt> - Создать новый файл. Указывать имя или полный путь;
/WriteToFile <C:\путь\к\файлу.txt>|<содержимое> - Создать новый файл, если он не существует и записать что-либо (какой-то текст). Наличие вертикальной черты ‘|’ служит для определения с какого места считывать желаемое содержимое файла. Пробелы также учитываются и кавычки не требуются;
/DownloadFile <file/dir> - Скачать файл или каталог с компьютера. Указывать полный путь, если путь содержит пробелы, кавычки не использовать;
/UploadFile <drop/url> - Загрузить файл на целевой компьютер. Можно просто бросить файл на окно телеграма;
/RunFile <file> - Просто открывает файл, например, если это текстовый документ, он откроется редактором по умолчанию;
/ListFiles <dir> - Показывает файлы и каталоги. Аналогично с ProcessList – сообщения будут поделены на куски, если не умещается. Пробелы также учитываются, кавычки ставить не надо.
/RemoveFile <file> - Удалить файл, указав полный путь без кавычек;
/RemoveDir <dir> - Удалить каталог, указав полный путь также без кавычек;
/MoveFile <path_to_file> <path_to_file> - Переместить файл. Следует заменить знак пробела на знак подчеркивания, если путь содержит пробелы
/CopyFile <path_to_file> <path_to_file> - Скопировать файл. Как ранее говорилось, содержание пробелов заменяется символом подчеркивания _
/MoveDir <path_to_dir> <path_to_dir> - тоже что и /MoveFile, но с каталогом
/CopyDir <path_to_dir> <path_to_dir> - скопировать каталог.
/Setdir <dir> - Сделать указанный каталог рабочим каталогом для бота;
/Workdir <dir> - Указанный каталог будет рабочим для cmd или powershell (об этом ниже)
/SetDate <формат> <file/dir> - Установить дату-время на файл или каталог в формате ДД:ММ:ГГГГ чч:мм;
/GetDate <file/dir> - получить дату-время из файла или каталога;
/Shell <command> - запускает cmd.exe с указанной командой в скрытом режиме. Ключ /c не требуется. Изначально, ошибка в cmd ни к чему не приводила. Было не понятно, было ли выполнено действие или нет. Теперь через установку для консоли правильной кодировки в случае ошибки она будет передана обратно в чат оператору.
/Powershell <command> - Запускает powershell в скрытом режиме с указанной командой (команды по умолчанию шифрованы в base64 через ключ -encodedcommand);
/OpenURL <url> - открыть ссылку (сайт) по указанному URL в браузере по умолчанию;
/Uninstall – Удаляет бота из системы;
/Desktop – Сделать скриншот. На этот раз через WinAPI учитывается масштабирование экрана.
/Check – проверка бота на активность, дабы узнать не умер ли он. Стоит использовать, так как бот при неактивности игнорирует команды и при следующем запуске исполнит последнюю.
/BlockInput <секунды> - блокирует ввод с клавиатуры и мыши на определенный интервал;
/Monitor <on/off/standby> - выключает или включает монитор;
/BSoD – вызвать синий экран смерти. Изначально это было реализовано через WinAPI NtRaiseHardError, затем через запуск powershell с аргументом wininit, но это всё уже не работает, если бот изначально был запущен от имени системы. Было решено установкой процесса бота как критический и просто закрытие текущего процесса.
/Shutdown – Выключить ПК
/Reboot - Перезагрузка
/Hibernate - Гибернация
/Logoff – Завершение сеанса (выход из системы)
/Help – Помощь по командам в самом боте
По командам всё.
--Computer info--
System: Windows 10 Корпоративная (64 Bit)
User name: 7D787F1D-608B-4\WDAGUtilityAccount
System time: 00-01-0001 00:00:00 AM
--Protection--
Installed antivirus: N/A
--Hardware--
CPU: AMD Ryzen 5 4500U with Radeon Graphics
GPU:
Microsoft Remote Display Adapter
RAM: 4094MB
Motherboard: Microsoft Corporation Virtual Machine
HWID: 0000000000000000
--LocalDisks--
Description Name
Локальный несъемный диск C:
System: Windows 10 Корпоративная (64 Bit)
User name: 7D787F1D-608B-4\WDAGUtilityAccount
System time: 00-01-0001 00:00:00 AM
--Protection--
Installed antivirus: N/A
--Hardware--
CPU: AMD Ryzen 5 4500U with Radeon Graphics
GPU:
Microsoft Remote Display Adapter
RAM: 4094MB
Motherboard: Microsoft Corporation Virtual Machine
HWID: 0000000000000000
--LocalDisks--
Description Name
Локальный несъемный диск C:
Здесь думаю всё понятно, не будет останавливаться.
/ActiveWindow – узнать текст заголовка активного окна. Чем это может быть полезно? Например, в заголовке содержится название проигрывателя, или музыкальная композиция – понятно, жертва слушает музыку. Или другой пример, в заголовке имеется название соц. Сети или переписка. Тут можно сделать скриншот, не привлекая внимания, об этом позже.
/Whoami – узнать привилегии в системе. Стандартная команда консоли, выполненная нестандартным способом. Так как на whoami ругаются многие AV, то стоит задействовать WMI.
C#:
public static string GetProcessOwner(int processId)
{
foreach (ManagementObject managementObject in new ManagementObjectSearcher("Select * From Win32_Process Where ProcessID = " + processId.ToString()).Get())
{
string[] args = new string[2]
{
string.Empty,
string.Empty
};
if (Convert.ToInt32(managementObject.InvokeMethod("GetOwner", (object[])args)) == 0)
return args[1] + "\\" + args[0];
}
return "NO OWNER";
}
Так мы будем знать, какие у нас права. Аналогичным способом узнаем имя компьютера и имя пользователя по процессу проводника (explorer.exe).
/ProcessList – Вывести список процессов c их process id (svchost исключен по умолчанию, так как он не представляет интерес и его очень много). Тут ничего необычного, но, есть важный момент. Телеграм бот не способен передавать более 4096 символов одним сообщением, это ограничение самого телеграма. Поэтому делаем некие нарезания по 4096 символов, если сообщение не умещается.
C#:
public static async void DisplayRunningProcesses()
{
int chunkSize = 4096;
List<string> procs = new List<string>();
foreach (Process p in Process.GetProcesses().OrderBy(p => p.ProcessName).ToList())
{
try
{
if (!exclusionList.Contains(p.ProcessName.ToLower()))
{
//Console.WriteLine($"- {p.ProcessName}");
string proc = p.ProcessName + " | " + p.Id;
procs.Add(proc);
}
}
catch (Exception)
{
continue;
}
}
StringBuilder list = new StringBuilder("Processes:\n\n");
foreach (var item in procs)
{
list.AppendLine(item);
}
string resultString = list.ToString();
List<string> messageChunks = utils.SplitString(resultString, chunkSize);
foreach (var chunk in messageChunks)
{
tg.sendText(chunk);
await Task.Delay(500);
}
}
/ProcessKill <процесс> - Убить указанный процесс по его имени. Указывать .exe в конце не нужно. Все процессы, которые имеют это имя, будут закрыты;
/ProcessKillid <pid> - То же, что и ProcessKill, но по id конкретного процесса;
/ProcessStart <процесс> - Запустить процесс, указав имя исполняемого файла или его полный путь;
/ProcessFreeze <id> [timeout] – Приостановить (заморозить) процесс. Можно, но не обязательно, указать timeout – время, по истечении которого бот снова возобновит указанный процесс;
/MakeUntrusted <имяпроцесса> - “Поломать” указанный процесс по имени (ставит уровень целостности на Недоверенный). Удаляет привилегии у процесса. Лучше не применять на svchost. Это сделает винду полурабочей и придется выключать с кнопки. Забавный результат будет, если натравить на диспетчер задач или тот же ProcessHacker, наши подопытные будут лишены возможности просматривать какие либо процессы до перезапуска.
/ProcAddEx <процесс1,процесс2...> - Добавляет в исключение имена выводимых процессов для команды /processlist. Например, у нас имеется многочисленные процессы браузера, которые также не представляют интерес. На данный момент исключенные имена процессов нигде не сохраняются. При следующем запуске бота снова будет 1 исключенный svchost.
/ProcRemEx <процесс1,процесс2...> - Удаляет исключенные имена выводимых процессов для команды /processlist;
/ProcShowExList – Показать, какие процессы исключены и не выводятся по команде /processlist;
/MinimizeAllWindows – свернуть все окна;
/MaximizeAllWindows – развернуть все окна;
/CreateFile <C:\путь\к\файлу.txt> - Создать новый файл. Указывать имя или полный путь;
/WriteToFile <C:\путь\к\файлу.txt>|<содержимое> - Создать новый файл, если он не существует и записать что-либо (какой-то текст). Наличие вертикальной черты ‘|’ служит для определения с какого места считывать желаемое содержимое файла. Пробелы также учитываются и кавычки не требуются;
/DownloadFile <file/dir> - Скачать файл или каталог с компьютера. Указывать полный путь, если путь содержит пробелы, кавычки не использовать;
/UploadFile <drop/url> - Загрузить файл на целевой компьютер. Можно просто бросить файл на окно телеграма;
/RunFile <file> - Просто открывает файл, например, если это текстовый документ, он откроется редактором по умолчанию;
/ListFiles <dir> - Показывает файлы и каталоги. Аналогично с ProcessList – сообщения будут поделены на куски, если не умещается. Пробелы также учитываются, кавычки ставить не надо.
/RemoveFile <file> - Удалить файл, указав полный путь без кавычек;
/RemoveDir <dir> - Удалить каталог, указав полный путь также без кавычек;
/MoveFile <path_to_file> <path_to_file> - Переместить файл. Следует заменить знак пробела на знак подчеркивания, если путь содержит пробелы
/CopyFile <path_to_file> <path_to_file> - Скопировать файл. Как ранее говорилось, содержание пробелов заменяется символом подчеркивания _
/MoveDir <path_to_dir> <path_to_dir> - тоже что и /MoveFile, но с каталогом
/CopyDir <path_to_dir> <path_to_dir> - скопировать каталог.
/Setdir <dir> - Сделать указанный каталог рабочим каталогом для бота;
/Workdir <dir> - Указанный каталог будет рабочим для cmd или powershell (об этом ниже)
/SetDate <формат> <file/dir> - Установить дату-время на файл или каталог в формате ДД:ММ:ГГГГ чч:мм;
/GetDate <file/dir> - получить дату-время из файла или каталога;
/Shell <command> - запускает cmd.exe с указанной командой в скрытом режиме. Ключ /c не требуется. Изначально, ошибка в cmd ни к чему не приводила. Было не понятно, было ли выполнено действие или нет. Теперь через установку для консоли правильной кодировки в случае ошибки она будет передана обратно в чат оператору.
/Powershell <command> - Запускает powershell в скрытом режиме с указанной командой (команды по умолчанию шифрованы в base64 через ключ -encodedcommand);
/OpenURL <url> - открыть ссылку (сайт) по указанному URL в браузере по умолчанию;
/Uninstall – Удаляет бота из системы;
/Desktop – Сделать скриншот. На этот раз через WinAPI учитывается масштабирование экрана.
/Check – проверка бота на активность, дабы узнать не умер ли он. Стоит использовать, так как бот при неактивности игнорирует команды и при следующем запуске исполнит последнюю.
/BlockInput <секунды> - блокирует ввод с клавиатуры и мыши на определенный интервал;
/Monitor <on/off/standby> - выключает или включает монитор;
/BSoD – вызвать синий экран смерти. Изначально это было реализовано через WinAPI NtRaiseHardError, затем через запуск powershell с аргументом wininit, но это всё уже не работает, если бот изначально был запущен от имени системы. Было решено установкой процесса бота как критический и просто закрытие текущего процесса.
/Shutdown – Выключить ПК
/Reboot - Перезагрузка
/Hibernate - Гибернация
/Logoff – Завершение сеанса (выход из системы)
/Help – Помощь по командам в самом боте
По командам всё.
Поскольку мы говорим о неком «шпионаже», то боту нужен какой-то механизм для закрепления в системе.
Самый банальный способ – добавление себя в планировщик заданий. Удобно? Да. Но первый же опытный юзер его заметит. Поэтому, добавлять его в корень планировщика не стоит. Следует засовывать куда-то поглубже, а чтобы замаскироваться от всевидящего Autoruns, вместо бинарника бота указываем pcalua.exe, через аргументы -a <путь>
указываем уже путь на бинарник зверька. Так мы сможем убрать жирную красную строку в большом списке, которая говорит об отсутствии действительной подписи, чтобы в глаза не бросалось.
Далее, зверьку нужен какой-то механизм самозащиты. Сюда входит анти-виртуализация для защиты от запуска на виртуалке и анти-отладка, тут почти никаких изменений не было. Разве что принцип нахождения виртуальный среды. Это можно определять по модели монитора. На реальной машине будет выдана строка, а в виртуальной будет ошибка, которую можно обработать.
Далее, чтобы затруднить обнаружение бота, добавляем ещё 2 метода для двух потоков. Первый будет искать в фоне NetLimiter, второй CrowdInspect и при нахождении такового просто замораживать его. Просто завершать процесс слишком скучно)
На последок, был добавлен механизм подмены родительского процесса, от которого будут унаследованых все привиллегии.
Пока на этом всё. Дальнейшая доработка имеет место быть, проект очень интересный. Хотелось бы добавить инжектор основной полезной нагрузки, какой-нибудь патчинг AMSI и возможно изучить использование D/Invoke. Ознакомиться с проектом можно в архиве.
Пароль на архив:
Вам нужно авторизоваться, чтобы просмотреть содержимое.
Готов почитать комментарии)