MailBomber - программа для отправки огромного
количества сообщений на указанный e-mail.
Очень неприятно обнаружить в собственном
почтовом ящике 300-400 сообщений от разных
адресатов. Еще неприятней знать, что среди
них какое-то количество тех, которые нужно
принять. В этой статье я расскажу о
некоторых способах защиты от такого
вандализма.

1. В диспетчере сообщений (есть
практически во всех почтовых клиентах)
принять только заголовки писем. Посмотреть
заголовок хотя бы одного не нужного письма.
Запомнить IP-адрес. Отметить все на удаление.
Потом просмотреть весь список, выбрать
нужные, отметить на получение и получить их.
Потом через whois узнать провайдера и
написать ему. Если не поможет - написать
матом со всяческими угрозами :-). В принципе
не долго, но геморно. Особенно пункт "просмотреть
весь список и выбрать нужные сообщения".
Провайдеры обычно из-за пары баксов
удавятся. Поэтому отправителю ничего не
будет (скорее всего). Письма с угрозами и
предупреждениями можно не посылать.

Есть несколько "НО". Хорошие MailBomber-ы
не только ставят в поле обратного адреса
разные адреса, но и умеют подделывать
заголовок, прикидываясь пересылочным
почтовым сервером. Мало того, что обратный
адрес определить очень тяжело, так еще и
разные темы, размеры и аттачи сообщений.
Есть еще и SOCK-5 прокси. Или, допустим, у меня
есть на странице форма для отправки
сообщения. Написать многопоточный флудер с
использованием этой формы и простого http-прокси
не так и сложно. Запустить у себя или с шелла
и все. Запросы идут через прокси, а в
обратном адресе стоит адрес sendmail хостера.

2. Идея реализации защиты в том, чтобы
получать только заголовки сообщений и
заданное количество строк. Потом искать
вхождение определенной строки (в любом
случае какая-то одинаковая строка для всех
сообщений будет) и автоматически удалять
сообщения на сервере. Поговорим о способах
реализации.

2.1. Способ для юзера. Поставить The Bat!. В
последних версиях есть создание правил для
приема сообщений. Прописать правило.
Инициализировать диспетчер сообщений.
Плюсы: просто, как у ребенка леденец
отобрать (так говорят те, кто никогда этого
не пробовал). Минусы: каждый раз нужно
создавать новое правило, искать где оно там
в меню и The Bat! все-таки платный. Хотя
программа настолько хороша, что можно и не
пожлобиться.

2.2. Способ для хакера. Написать скрипт.
Скрипт будет получать часть сообщений,
искать вхождение искомой строки и удалять,
удалять, удалять. Сунуть туда, где он
исполнится. Плюсы: не юзает твой траффик.
Минусы: надо иметь место, где он исполнится.
Вот самый простейший пример на Perl (необходим
модуль Mail::POP3Client), который просматривает
сообщения и удаляет все, в которых
содержится "stroka": 

#!/usr/bin/perl
use Mail::POP3Client;

$user = "user";
$password = "password";
$host = "pop3.domain.com";
$stroka = "127.0.0.1"

$pop = new Mail::POP3Client( USER => $user, PASSWORD => $password, HOST
=> $host );
for( $i = 1; $i <= $pop->Count(); $i++ ) 
{
foreach( $pop->HeadAndBody( $i ) ) 
{
chomp $stroka;
if (/$stroka/) 
{
$pop->Delete( $i );
}
}
}
$pop->Close(); 

Можно чуть усложнить: сделать вывод
сообщений, дописать получение $user, $password, $host,
$stroka из формы и т.д. Но все равно надо
получить почтовым клиентом или telnet-ом
парочку сообщений для определения строки
вхождения.

2.3. Настоящие герои всегда идут в обход.
Может под рукой не будет Perl или места, где
вышеописанный скрипт надо будет запустить.
Попробуем самим написать программу с
использованием неблокирующего сокета. Тем
более, что рабочие исходники простейшего
клиента, работающего на TCP/IP, всегда должны
быть под рукой. Почему на асинхронном
сокете? Плюсы: не надо покупать The Bat!, не
нужен шелл, Perl и т.п., к тому же разминка в
кодинге никогда не помешает. Минусы: надо
писать :-), использовать немного своего
траффика и Delphi (который стоит чуть-чуть
дороже The Bat! :-)). На самом деле Delphi покупать
не обязательно. Функции работы с сокетами
практически одинаковы на всех языках и
системах. Переписать нижеследующий код на
разновидность C или асма достаточно просто.
Итак, создаем новый проект с одним окном и
кидаем на форму 4 Edit-а (закладка Standart; юзер,
пароль, POP3-сервер и строка вхождения), 2 SpinEdit-а
(закладка Samples; тайм-аут и количество
получаемых строк кроме заголовка), 1 Button (старт/стоп)
и несколько Label-ов (чтоб потом ничего не
напутать). Нужные нам команды POP3-сервера:
USER - юзер;
PASS - пароль;
STAT - информация откуда получим кол-во
сообщений;
TOP - получение заголовка и указанных строк
выбранного сообщения.

Вот исходники "Unit1.pas" (Delphi32): 

var
Form1: TForm1;
StartD : Boolean = false;
addr : TSockAddrIn;
IPaddr : Cardinal;
s : TSocket;
WSAData : TWSAData;
Buf : array [1..4096] of Char;
BoolS : Byte;
sock_on, sock_off : Integer;

implementation

{$R *.DFM}

// функция отправки
почтовому серверу строки str

function postsend(str:string) : Boolean;
var
I1 :integer;
begin
Result:=false;
for I1:=1 to Length(str) do if send(s,str[I1],1,0)=SOCKET_ERROR then exit;
Result:=true;
end;

//Start/Stop
procedure TForm1.Button1Click(Sender: TObject);
var
DopS : String;
I1, DopI, DopI1 : Integer;

label l3, l2, l1;

//Перевод адреса в DWORD
function dns_addr(IPaddr : String) : Cardinal;
var
pa: PChar;
sa: TInAddr;
Host: PHostEnt;
begin
Result:=inet_addr(PChar(IPaddr));
if Result=INADDR_NONE then begin
host:=GetHostByName(PChar(IPaddr));
if Host = nil then exit
else begin
pa := Host^.h_addr_list^;
sa.S_un_b.s_b1 := pa[0];
sa.S_un_b.s_b2 := pa[1];
sa.S_un_b.s_b3 := pa[2];
sa.S_un_b.s_b4 := pa[3];
with TInAddr(sa).S_un_b do Result:= inet_addr(PChar(IntToStr(Ord(s_b1))+'.'+IntToStr(Ord(s_b2))+'.'
+IntToStr(Ord(s_b3))+'.'+ IntToStr(Ord(s_b4))));
end;
end;
end;

//select на сокет и тайм-аут
function postselect(s1 : TSocket; TimeS1 : Integer) : Boolean;
var
tvS : TTimeVal;
rfdsS : Tfdset;
begin
Result:=true;
//
Ждем пока не сможем
принять или тайм-аут 

while true do begin
//
Если отмена - выход
if not StartD then begin
Result:=false;
exit;
end;
Sleep(100);
//
Обнуляем дескриптор
сокетов 

FD_ZERO(rfdsS);
FD_SET(s1,rfdsS);
tvS.tv_sec:=0;
tvS.tv_usec:=100;
//
select-ируем сокет 
select(0,@rfdsS,nil,nil,@tvS);
TimeS1:=TimeS1-100;
//
Если можно читать -
выход и читаем 

if FD_ISSET(s1,rfdsS) then exit;
//
Если тайм-аут - выход
с false 

if TimeS1<=0 then begin
Result:=false;
exit;
end;
end;
end;

begin
if StartD then StartD:=false else begin
//
Начали
StartD:=true;
Form1.Button1.Caption:='Stop';
//
Создание сокета
sock_on:=1;
sock_off:=0;
if WSAStartUp(257, WSAData) <> 0 then goto l1;
s := socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
if s = INVALID_SOCKET then goto l1;
if dns_addr(Form1.Edit1.Text)<=0 then goto l1;
//
Переход в
неблокирующий режим

ioctlsocket(s,FIONBIO,sock_on);
addr.sin_family := AF_INET;
addr.sin_port := htons(110);
addr.sin_addr.S_addr:=dns_addr(Form1.Edit1.Text);
//
Соединение
connect(s,addr,sizeof(addr));
if not postselect(s,Form1.SpinEdit2.Value) then goto l2;

// Получим ответ
сервера

FillChar(Buf,4096,0);
recv(s,buf,sizeof(Buf),0);

// USER
if not postsend('user '+Form1.Edit2.Text+#13+#10) then goto l2;
if not postselect(s,Form1.SpinEdit2.Value) then goto l2;
FillChar(Buf,4096,0);
I1:=recv(s,buf,sizeof(Buf),0);
if (I1>0)and(buf[1]<>'+') then goto l2;

// PASSWORD
if not postsend('pass '+Form1.Edit3.Text+#13+#10) then goto l2;
if not postselect(s,Form1.SpinEdit2.Value) then goto l2;
FillChar(Buf,4096,0);
I1:=recv(s,buf,sizeof(Buf),0);
if (I1>0)and(buf[1]<>'+') then goto l2;

// Количество сообщений
(STAT)

if not postsend('stat'+#13+#10) then goto l2;
if not postselect(s,Form1.SpinEdit2.Value) then goto l2;
FillChar(Buf,4096,0);
I1:=recv(s,buf,sizeof(Buf),0);
if (I1>0)and(buf[1]<>'+') then goto l2;
DopS:=trim(Buf);
DopS:=Copy(Buf,5,length(DopS)-5);
if Pos(' ',DopS)>0 then DopS:=copy(DopS,1,Pos(' ',DopS)-1);
DopI:=StrToInt(DopS);

// DopI = кол-во сообщений.
Запускаем цикл если > 0

if DopI>0 then begin
for DopI1:=1 to DopI do begin
//
Получим заголовок и
указанное кол-во строк сообщения

if not postsend('top '+IntToStr(DopI1)+' '+IntToStr( Form1.SpinEdit1.Value)+#13+#10)
then goto l3;
if postselect(s,Form1.SpinEdit2.Value) then begin
FillChar(Buf,4096,0);
recv(s,buf,sizeof(Buf),0);
//
Если встречаются
вхождения - удалим

if Pos(Form1.Edit4.Text,Buf)>0 then begin
postsend('dele '+IntToStr(DopIl)+#13+#10);
if not postselect(s,Form1.SpinEdit2.Value) then goto l3;
FillChar(buf,4096,0);
I1:=recv(s,buf,sizeof(Buf),0);
if (I1>0)and(buf[1]<>'+') then goto l3;
break;
end;
end;
//
Следующее сообщение
l3:
dec(DopI);
end;
postsend('quit'+#13+#10);
end else ShowMessage('0 message');
end;
l2:
ioctlsocket(s,FIONBIO,sock_off);
closesocket(s);
l1:
StartD:=false;
Form1.Button1.Caption:='Start';
end;

end.

Ради уменьшения размера исходника, здесь
нет обработки ошибок, не совсем корректно
сделан "Stop" и прием ограничен 4096 байт,
но всё более или менее работает. Дописать не
проблема. Теперь как человек ни будет
изменять настройки MailBomber-а, писать сам
скрипты и программы, потеть и тратить свой
траффик или шелл на то, чтобы тебя зафлудить
- защита займет всего ~ 1-2 kB входящих данных
на каждое сообщение (при способе 2.3) и
несколько минут на настройки. Естественно,
способ 2.3 подходит для сравнительно
небольшого количества сообщений. Если же
атака осуществляется с шелла или
многопоточным флудером, то писем может быть
несколько тысяч. Тогда предпочтительней
способ 2.2.

Если же у человека есть список из
нескольких сот работающих прокси-серверов,
несколько шеллов, серверов с sendmail и формами
для отправки сообщений, мощная выделенка и
большой список с разными сообщениями,
темами, обратными адресами и т.д., то так
просто ты не отделаешься. Мыло тебе вряд ли
удастся сохранить. Можно конечно стукнуть в
CyberPolice, но.... Не красиво это. Хотя, можно всем
кто пишет сказать, чтобы вставляли в первую
строчку какую-то определенную фразу и
удалять все сообщения без этой фразы. В
общем, варианты есть.

antimb.zip -
исходники и программа, рассмотренные в
статье.

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии