
Создание базового ботнета Command & Control на C
Этот хакпак проведет вас через реализацию базового фреймворка, который фундаментально характеризует ботнет. Возможно, будет полезно, если вы уже работали с C. Если вам понравился этот учебник, не забудьте поставить звезду этому репозиторию!
Примечание: Не используйте ничего из того, что вы узнаете здесь, в злонамеренных целях. Этот хакпак предназначен исключительно для изучения ботнетов в образовательных целях. Концепции, изученные в этом хакпаке, имеют широкие области применения (в основном все, что связано с сетями). Самое главное, этот хакпак предназначен для тестирования и развертывания локально (поэтому, пожалуйста, не делитесь тем, что вы создали в рамках этого хакпака, с другими хакерами). Конфиденциальность важна, поэтому, пожалуйста, уважайте ее.
Прежде чем создавать ботнет, важно понять, что такое ботнет. Ботнет — это сеть компьютеров, способных получать команды удаленно и выполнять их локально. При желании они могут передавать информацию обратно другим узлам сети. Они использовались для всего: от распределенных атак типа «отказ в обслуживании» до массового развертывания шпионского ПО. Возможно, вы слышали о многих ботнетах в прошлом. Наиболее известными являются, пожалуй, Mirai и Gameover Zeus, которые контролировали 3,8 тысячи и 3,6 миллиона устройств IoT соответственно. Существует много различий в том, как ботнеты реализуют определенные задачи. Но для успешного построения нашего ботнета необходимо обеспечить следующие функции в нашей рабочей сети.
Наш ботнет должен:
Эта структура характерна для так называемых ботнетов Command & Control. У таких ботнетов есть один главный сервер и множество ведомых серверов. Однако такой стиль ботнетов устарел и может быть легко выведен из строя путем отключения доступа к главному домену. Более современные и сложные ботнеты используют одноранговую архитектуру (peer-to-peer), где права администратора распределены по всем узлам или подмножеству узлов сети. Эти ботнеты доставляют большие головные боли специалистам по безопасности, поскольку у них нет центральной точки управления, и они могут разрастаться до миллионов узлов. Ликвидация таких ботнетов — интересная тема сама по себе. Однако для целей этого хакпака давайте не будем усложнять. Мы реализуем простой ведомый узел для ботнета C&C.

Этот хакпак в основном будет посвящен реализации клиентского вредоносного ПО. Для главного сервера мы можем использовать открытый TCP-сервер под названием Netcat. Netcat не имеет никакого отношения к ботнетам. Это просто удобный, проверенный инструмент, который мы можем приспособить для отправки текстовых пакетов от клиентов и к ним (а это, по сути, и есть мастер). Я немного доработал сервер Netcat и скомпилировал его в бинарник с именем «master». Больше никакой работы здесь не требуется! Наш мастер готов к использованию.
Перейдем к более интересной части: получению и выполнению удаленных команд (о маскировке нашего вредоносного ПО мы позаботимся позже). Цель здесь — сделать наш ведомый узел максимально простым и соответствующим требованиям, описанным выше. Обратите внимание, что многие константы уже определены в lib/macros.h, так что можете их использовать. Все сигнатуры реализованных функций можно найти в lib/connect.h или lib/utils.h.
Откройте файл bot.c. При запуске нового узла в нашем сервере нам, вероятно, стоит дать ему имя, чтобы мастер знал, на какие клиенты отправлять команды. Существует множество соглашений об именах. Использование IP-адреса, вероятно, лучше всего, так как это уникальный идентификатор для каждого клиента. Однако для большей читаемости для обычных людей давайте использовать имя пользователя компьютера. Используя функцию C getenv() с аргументом "USER", мы получаем то, что хранится в переменной окружения USER на компьютере. Это одно из мест, где хранится имя пользователя, так что воспользуемся этим. Также, теперь, когда ваш ведомый запущен, давайте найдем мастера. Для этого мы должны знать IP-адрес нашего мастера. Каждое сетевое устройство имеет IP-адрес. Он отвечает за идентификацию других узлов и адресацию местоположения. Кроме того, мастер может иметь множество серверов, работающих на разных портах. Поэтому нам нужно не только подключиться к мастеру, но и указать правильный порт. Этот порт выбирается мастером, но может быть изменен. В этом хакпаке мы хотим тестировать локально. Итак, мы будем использовать ваш компьютер в качестве нашей сети. Локальный IP-адрес каждого компьютера (на который также разрешается «localhost») — "127.0.0.1". В мастере я указал, что он работает на порту 9999. Имея эти три элемента (IP-адрес мастера, порт мастера и имя ведомого), мы можем запустить канал связи между сервером и клиентом, называемый сокетом. Передайте эти три аргумента в функцию init_socket(), чтобы создать сокет. init_socket() не является встроенной командой C. Скорее, нам нужно реализовать ее. Затем нам нужно выделить немного места в стеке для хранения входящих сообщений. Будем щедры и используем около 10 КБ стекового пространства. Назовем этот указатель стека msg. Наконец, есть оператор printf, который указывает, что все идет хорошо.
char* name = //Get the client's username and store it in name
int channel = //initiate a channel given SERVER, PORT, and name;
//Allocate stack space of size CMD_LENGTH to hold data of type char. Call the stack pointer msg
printf("%s joining the botnet\n", name);
Теперь переключитесь на lib/connect.c. Давайте реализуем init_channel(). Сначала я определил стековый буфер типа char с именем msg длиной CMD_LENGTH и специальную конструкцию C для работы с сетью, называемую server, которая содержит информацию о нашем подключении к мастеру. Сначала преобразуйте переданный IP-адрес из удобочитаемого формата (с числами и точками) в двоичный формат в сетевом порядке байтов. Это делается с помощью специальной функции C inet_addr() из библиотеки сокетов. Она принимает IP-адрес и выдает его в используемом сетью двоичном формате. В C мы можем легко задать сеть, заполнив поля структуры sockaddr_in. Наш экземпляр этой структуры называется server. Нам нужно заполнить 3 поля этой структуры: server.sin_addr.s_addr (IP-адрес мастера), server.sin_family (однобайтовое значение, определяющее домен связи) и server.sin_port (порт, к которому мы будем подключаться на мастере). sin_family можно задать с помощью C-макросов, предоставляемых библиотекой сокетов. Обычно, как и в этом случае, мы устанавливаем это поле в AF_INET. Это означает, что наше соединение идентифицирует сетевые узлы через их IP-адреса, что нам и нужно. Однако также возможно использовать PF_INET, который похож на AF_INET, но указывает, что сеть может использовать что угодно в рамках протокола для идентификации конкретных узлов. Есть также множество якобы исторических причин, почему существуют оба, но это то, о чем я не особо знаю и не очень забочусь. Просто используйте AF_INET. Наконец, при установке порта сервера мы должны передать port через специальную функцию htons() (host to network short). Она преобразует данные из порядка байтов хоста в порядок байтов сети. Эта путаница с порядком байтов связана с так называемым Endianness. Подробнее об этом можно прочитать здесь.