From 556af1f1a7990a0f0745d4ec067dbbbbbd8e3fed Mon Sep 17 00:00:00 2001 From: serafim Date: Mon, 24 Mar 2025 23:45:04 +0300 Subject: [PATCH] dev_nekitmilk_refactoring (#5) Co-authored-by: tieshagr Co-authored-by: oct Reviewed-on: https://gitea.serafimdev.com/serafim/dos/pulls/5 Reviewed-by: dr-wh0 <79003667309@yandex.ru> Co-authored-by: serafim Co-committed-by: serafim --- README.md | 6 +- src/DosAtk.cpp | 181 ++++++++++++++++++++++++++++++++++++++++--------- src/a.out | Bin 0 -> 57600 bytes 3 files changed, 155 insertions(+), 32 deletions(-) create mode 100755 src/a.out diff --git a/README.md b/README.md index 90d9c1c..7e15699 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,8 @@ git add * # Добавляем написанный код в комит git commit -m 'Написал код' # Комитим в локальную ветку git push origin my_dns # Пушим свою ветку в репозиторий # Теперь в интерфейсе https://gitea.serafimdev.com/serafim/dos создаём пул реквест и пишем мне в тг -``` \ No newline at end of file +``` + +Для компиляции: +g++ DosAtk.cpp -lcurl +Если ошибка отсутствия заголовочного файла "curl.h", то нужно установить: sudo apt-get install libcurl4-openssl-dev \ No newline at end of file diff --git a/src/DosAtk.cpp b/src/DosAtk.cpp index 725ef8f..e4ea23f 100644 --- a/src/DosAtk.cpp +++ b/src/DosAtk.cpp @@ -10,36 +10,42 @@ #include #include -// ====== DCL ====== // +std::string attack_type; // Тип атаки: scan или syn +std::string domain; // Доменное Имя +std::string ip; // Ip жертвы +std::string port; // Порт +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; // Сообщение, которое будет отправлено в телеграм -std::string attack_type; -std::string domain; -std::string ip; -std::string port; -std::string log_file; -std::string 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; +// ====== end of DCL ====== // +// Данная процедура записывает в глобальные переменные параметры +// (attack_type, domain, ip, port, log_file, telegram_id, telegram_token) проводимой атаки, поступившие при вызове программы +// На вход получает int argc, char **argv, возвращает код выполнения +// Коды возврата: +// 2 - Атака флуд, все нужные опции есть +// 1 - Атака порт скан, все нужные опции есть +// 0 - нужна помощь +// -1 - пользователь не ввел тип атаки или ввел неверный тип атаки +// -10 - Пользователь выбрал тип атаки порт сканнинг, но не ввел нужные параметры +// -20 - Пользователь выбрал тип атаки флуд, но не ввел нужные параметры +// -101 - неизвестная опция или потерян аргумент, следует предложить вызвать флаг помощи +// -600 - пользователь ввел токен, но не id или наоборот int my_check_params(int argc, char **argv) { - std::string debug_msg; - debug_msg = ""; - for (int i = 0; i < argc; i++) { - debug_msg += argv[i]; - debug_msg += " "; - } - printf("begin my_check_params (argc: %i, argv: %s)\n", argc, debug_msg.c_str()); - int status; int opt; - const char* short_options = "a:d:i:p:l:t:b:h"; - const struct option long_options[] = { + const char* short_options; + short_options = "a:d:i:p:l:t:b:h"; + const struct option long_options[] = + { {"attack", required_argument, NULL, 'a'}, {"domain", required_argument, NULL, 'd'}, {"ip", required_argument, NULL, 'i'}, @@ -51,6 +57,14 @@ int my_check_params(int argc, char **argv) {NULL, 0, NULL, 0} }; + std::string debug_msg; + debug_msg = ""; + for (int i = 0; i < argc; i++) { + debug_msg += argv[i]; + debug_msg += " "; + } + printf("begin my_check_params (argc: %i, argv: %s)\n", argc, debug_msg.c_str()); + while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { switch (opt) { case 'a': @@ -109,6 +123,8 @@ int my_check_params(int argc, char **argv) return status; } +// Данная функция вызывается в случае ошибки на каком-то этапе и на основании поступившего кода, +// формирует сообщение с описанием произошедшей ошибки void my_diag(int status) { printf("begin my_diag (status: %i)\n", status); @@ -145,18 +161,115 @@ void my_diag(int status) printf("end my_diag\n"); } -void my_msg() -{ - printf("begin my_msg()\n"); - printf("%s\n", msg.c_str()); - printf("end my_msg"); +// Функция для экранирования спецсимволов в JSON +std::string escape_json(const std::string& s) { + std::string result; + for (char c : s) { + switch (c) { + case '"': result += "\\\""; break; + case '\\': result += "\\\\"; break; + case '\b': result += "\\b"; break; + case '\f': result += "\\f"; break; + case '\n': result += "\\n"; break; + case '\r': result += "\\r"; break; + case '\t': result += "\\t"; break; + default: result += c; break; + } + } + return result; } +// Проверка, является ли строка числом (включая отрицательные) +bool is_numeric(const std::string& s) { + size_t start; + if (s.empty()) return false; + + start = 0; + if (s[0] == '-') { + if (s.size() == 1) return false; + start = 1; + } + + for (size_t i = start; i < s.size(); ++i) { + if (!isdigit(s[i])) return false; + } + return true; +} + +int my_msg() { + CURL* curl; + std::string escaped_msg; + std::cout << msg << std::endl; + std::string chat_id_field; + std::string json_data; + struct curl_slist* headers; + headers = nullptr; + long http_code; + CURLcode res; + + if (telegram_token.empty() || telegram_id.empty()) { + return 0; // Интеграция не настроена + } + + curl = curl_easy_init(); + if (!curl) return 6; // Ошибка инициализации CURL + + // Экранируем сообщение + escaped_msg = escape_json(msg); + + // Формируем поле chat_id + if (is_numeric(telegram_id)) { + chat_id_field = "\"chat_id\": " + telegram_id; + } else { + chat_id_field = "\"chat_id\": \"" + telegram_id + "\""; + } + + // Формируем JSON + json_data = "{" + chat_id_field + ", \"text\": \"" + escaped_msg + "\"}"; + // Настраиваем заголовоки + headers = curl_slist_append(headers, "Content-Type: application/json"); + + // Настраиваем параметры CURL + curl_easy_setopt(curl, CURLOPT_URL, ("https://api.telegram.org/bot" + telegram_token + "/sendMessage").c_str()); + curl_easy_setopt(curl, CURLOPT_POST, 1L); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data.c_str()); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl/7.68.0"); + + // Игнорируем вывод ответа + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, [](void*, size_t size, size_t nmemb, void*) -> size_t { + return size * nmemb; + }); + + // Выполняем запрос + res = curl_easy_perform(curl); + + http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + // Освобождаем ресурсы + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + + if (res != CURLE_OK) return 5; + + switch (http_code) { + case 200: return 0; + case 401: return 1; + case 400: return 2; + case 404: return 3; + default: + if (http_code >= 500) return 4; + return 4; + } +} +// Данная функция записывает в файл лога сообщение int my_log() { return 0; } +// Данная функция завершает программу и рассчитывает итоговое время выполнения программы void my_fin() { auto end_timestamp = std::chrono::system_clock::now(); @@ -189,21 +302,25 @@ void my_fin() std::exit(0); } +// Данная процедура сопостовляет доменное имя с IP int my_dns() { return 0; } +// Данная процедура выполняет TCP SYN Flood атаку int my_tcp_syn() { return 2; } +// Данная процедура выполняет UDP Flood (port scanning) атаку int my_udp() { return 2; } +// Тело программы int main(int argc, char **argv) { int check_params_status; @@ -217,9 +334,11 @@ int main(int argc, char **argv) n_fail_requests = 0; start_timestamp = std::chrono::system_clock::now(); - time_t now_time_t = std::chrono::system_clock::to_time_t(start_timestamp); + time_t now_time_t; + now_time_t = std::chrono::system_clock::to_time_t(start_timestamp); - std::chrono::milliseconds ms = std::chrono::duration_cast(start_timestamp.time_since_epoch()) % 1000; + std::chrono::milliseconds ms; + ms = std::chrono::duration_cast(start_timestamp.time_since_epoch()) % 1000; printf("Starting DosAtk at %04d-%02d-%02d %02d:%02d:%02d.%03ld\n", std::localtime(&now_time_t)->tm_year + 1900, diff --git a/src/a.out b/src/a.out new file mode 100755 index 0000000000000000000000000000000000000000..4f5b5792f2db3746c274241df95f010d743a372a GIT binary patch literal 57600 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