Белое исследование взлома паролей с помощью машинного обучения

Предисловие

Не так давно считалось, что научить компьютер отличать кошек от собак - это было одним из самых современных исследований. Теперь классификация изображений - это «Hello World» машинного обучения (ML), что можно реализовать всего несколькими строками кода с помощью TensorFlow. Фактически, всего за несколько коротких лет область машинного обучения продвинулась настолько далеко, что сегодня с такой же легкостью можно создать потенциально спасающее жизнь или смертельное приложение. Таким образом, возникла необходимость обсудить как использование технологии, так и злоупотребление ею, в надежде, что мы сможем найти способы смягчить или защитить от злоупотребления. В этой статье я расскажу об одном потенциальном злоупотреблении этой технологией - взломе паролей с помощью машинного обучения.

Чтобы быть более конкретным (см. Рис. 1), можем ли мы выяснить, что кто-то набирает, просто слушая нажатия клавиш? Как вы понимаете, это имеет серьезные последствия для безопасности, например, взлом паролей.

Итак, я работал над проектом под названием kido (= декодирование нажатия клавиш), чтобы выяснить, возможно ли это (https://github.com/tikeswar/kido).

Наброски

Это можно рассматривать как проблему контролируемого машинного обучения, и мы рассмотрим все шаги.

  1. Сбор и подготовка данных
  2. Обучение и оценка
  3. Тестирование и анализ ошибок (повышение точности модели)
  4. Выводы; Ссылка на GitHub

Для этого проекта использовались Python, Keras и TensorFlow.

Сбор данных

Первый шаг - как собрать данные для обучения модели?

Есть много способов сделать это, но чтобы доказать, работает эта идея или нет, я использовал клавиатуру MacBook Pro для набора текста и QuickTime Player для записи звука набора текста через встроенный микрофон (рис. 2).

У этого подхода есть несколько преимуществ: 1. данные имеют меньшую изменчивость и, следовательно, 2. он помогает нам сосредоточиться на доказательстве (или опровержении) идеи, не отвлекаясь.

Подготовка данных

Следующим шагом является подготовка данных, чтобы мы могли передать их в нейронную сеть (NN) для обучения.

Quicktime сохраняет записанный звук в формате mp4. Сначала мы конвертируем mp4 в wav, так как есть хорошие библиотеки Python для работы с файлами wav. Каждый всплеск в правом верхнем подграфике соответствует нажатию клавиши (см. Рис. 3). Затем мы разбиваем звук на отдельные фрагменты, используя обнаружение тишины, чтобы каждый фрагмент содержал только одну букву. Теперь мы могли бы скормить эти отдельные куски сети, но есть лучший подход.

Преобразуем отдельные фрагменты в спектрограммы (рис. 4). И теперь у нас есть изображения, которые намного информативнее и с которыми проще работать с помощью сверточной нейронной сети (CNN).

Для обучения сети я собрал около 16 000 образцов, как описано выше, убедившись, что каждая буква содержит не менее 600 образцов (рис. 5).

Затем данные были перемешаны и разделены на наборы для обучения и проверки. В каждой букве было около 500 обучающих образцов + 100 проверочных образцов (рис. 6).

Итак, вкратце, это проблема машинного обучения, которая у нас есть… см. Рис. 7.

Обучение и проверка

Я использовал довольно небольшую и простую сетевую архитектуру (основанную на примере« камень-ножницы-бумага Лоуренса Морони»). См. Рис. 8 - входное изображение масштабируется до 150 x 150 пикселей и имеет 3 цветовых канала. Затем он проходит через серию слоев свертки + объединения, выравнивается (используется выпадение для предотвращения чрезмерной подгонки), подается на полностью подключенный слой и выходной слой в конце. Выходной слой имеет 26 классов, соответствующих каждой букве.

В TensorFlow модель выглядит так:

model = tf.keras.models.Sequential([
    # 1st convolution
    tf.keras.layers.Conv2D(64, (3,3), activation='relu', input_shape=(150, 150, 3)),
    tf.keras.layers.MaxPooling2D(2, 2),

    # 2nd convolution
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    
    # 3rd convolution
    tf.keras.layers.Conv2D(128, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    
    # 4th convolution
    tf.keras.layers.Conv2D(128, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    
    # Flatten the results to feed into a DNN
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.5),
    
    # FC layer
    tf.keras.layers.Dense(512, activation='relu'),
    
    # Output layer
    tf.keras.layers.Dense(26, activation='softmax')
])

и краткое изложение модели:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_4 (Conv2D)            (None, 148, 148, 64)      1792      
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 74, 74, 64)        0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 72, 72, 64)        36928     
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 (None, 36, 36, 64)        0         
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 34, 34, 128)       73856     
_________________________________________________________________
max_pooling2d_6 (MaxPooling2 (None, 17, 17, 128)       0         
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 15, 15, 128)       147584    
_________________________________________________________________
max_pooling2d_7 (MaxPooling2 (None, 7, 7, 128)         0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 6272)              0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 6272)              0         
_________________________________________________________________
dense_2 (Dense)              (None, 512)               3211776   
_________________________________________________________________
dense_3 (Dense)              (None, 26)                13338     
=================================================================
Total params: 3,485,274
Trainable params: 3,485,274
Non-trainable params: 0

Результат обучения показан на рис. 9. Примерно за 13 эпох он сходится к 80% точности проверки и 90% точности обучения. Я был приятно удивлен получением такого уровня точности, учитывая сложность проблемы и простую используемую сетевую архитектуру.

Результат пока выглядит очень многообещающим ... но учтите, что это точность на уровне символов, а не на уровне слов.

Что это обозначает? Чтобы угадать пароль, мы должны правильно угадать каждый символ, а не только большинство из них! См. Рис.10.

Тестирование

Итак, чтобы протестировать модель, я оцифровал еще 200 различных паролей из списка rockyou.txt, а затем попытался предсказать слова, используя только что обученную модель (рис. 11).

Рис. 12 показывает точность теста. Гистограммы показывают точность на уровне символов (левая диаграмма показывает количество правильных и неправильных, а правая диаграмма показывает то же самое в процентах). Точность теста составляет около 49% для уровня символа и 1,5% для уровня слова (сеть полностью вернула 3 из 200 тестовых слов).

Учитывая сложность задачи, точность на уровне слов 1,5% - это неплохо! Но можем ли мы повысить точность?

Анализ ошибок

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

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

Для слова «aaron» наша модель соответствует едва ли одному символу, для «canada» - правильно улавливает большинство символов, а для «lokita» - все символы правильно. Как показано на рис. 12, точность на уровне слов составила всего 1,5%.

Прищурившись, взглянув на тестовые примеры (рис. 14), особенно на слово «канада», мы понимаем, что он правильно передает большинство символов и очень близок к фактическому слову. Итак, что, если мы передадим результат CNN через проверку орфографии ?!

Это именно то, что я сделал (рис. 15), и, конечно же, это повысило точность с 1,5% до 8%! Таким образом, с помощью довольно простой модели архитектуры + проверки орфографии мы можем правильно предсказать 8 паролей из 100… это нетривиально !!

Я думаю, если мы будем использовать модель последовательности (RNN ?, Transformer?) Вместо простого средства проверки орфографии, мы сможем получить еще более высокую точность на уровне слов… и это может быть темой для дальнейших исследований.

Но давайте еще более внимательно посмотрим на результаты теста (рис. 16). Мы замечаем, что «a» предсказывается как «s», «n» как «b» и т. Д.

Так что, если мы сопоставим ошибки на клавиатуре? И как только мы нанесем это на карту (см. Рис. 17), коррелирует ли ошибка с близостью? Это выглядит как!

Далее, можем ли мы количественно оценить корреляцию этой ошибки с близостью?

На рис. 18 показана клавиатура MacBook Pro с микрофоном и расположение клавиш в масштабе. На рис. 19 показаны карты ошибок на цифровой клавиатуре для некоторых образцов букв.

На рис. 19 левый верхний график показывает, что «a» ошибочно предсказывается как «z», «x», «y», «k», «s», «w» или «q». Остальные подсюжеты интерпретируются аналогично.

Рис. 19 дает более четкое указание на то, что ошибка может быть связана с близостью. Однако можем ли мы получить еще более количественную оценку?

Пусть d_ref будет расстоянием от контрольной буквы до микрофона, d_predicted будет расстоянием от предполагаемой буквы до микрофона, а d будет абсолютным значением разницы между d_ref и d_predicted (см. Рис. 20).

На рис.21 показана гистограмма количества ошибок, разделенных на интервалы относительно. d. Мы видим очень четкую тенденцию - большинство ошибок происходит в непосредственной близости! Это также означает, что мы, вероятно, сможем повысить точность модели за счет большего количества данных, большей сети или сетевой архитектуры, которая может лучше это уловить.

Но как насчет расположения микрофона - связана ли ошибка с тем, насколько далеко от микрофона находится клавиша? Чтобы исследовать это, график% ошибок на рис. 12 был перестроен таким образом, чтобы буквы на оси x располагались в порядке возрастания расстояния от микрофона (см. Рис. 22). Здесь не наблюдается сильной корреляции с. d_ref, что указывает на то, что ошибки не зависят от местоположения микрофона.

На рис. 22 подчеркивается очень важный момент - микрофон можно разместить где угодно, чтобы слушать нажатия клавиш и иметь возможность взламывать! Жутко!

Улучшения модели

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

  • Нормальная скорость набора текста → Сложная обработка сигнала (для выделения отдельных нажатий клавиш). - Для этого исследования я медленно печатал по одной букве за раз.
  • Любые нажатия клавиш → Сложная обработка сигнала (Caps Lock on ?, Shift ?,…). - Для этого исследования я использовал только строчные буквы (прописные буквы, цифры, специальные символы, специальные нажатия клавиш и т. Д. Не использовались).
  • Фоновый шум → Добавить шум. - Для этого исследования во время записи данных в некоторых случаях присутствовал простой и легкий фоновый шум проезжающих автомобилей, но не было сложного фонового шума (например, фонового шума кафетерия).
  • Различные настройки клавиатуры и микрофона + разные люди, набирающие текст → Больше данных + увеличение объема данных + большая сеть + другая сетевая архитектура могут помочь улучшить модель.
  • → Можем ли мы использовать другие сигнатуры вибрации вместо звуковой сигнатуры?

Выводы

Принимая во внимание упрощения, сделанные для этого исследования,

  • Вроде можно взломать звуки нажатия клавиш
  • Имея довольно небольшой объем данных и простую архитектуру CNN + проверку орфографии, мы можем получить нетривиальную точность на уровне слов (8% в этом исследовании).
  • Анализ ошибок
    * Простая проверка орфографии может повысить точность на уровне слов (в данном случае с 1,5% до 8%)
    * Ошибки коррелируют с близостью к другим клавишам
    * Кажется, что ошибки не зависят от расположение микрофона

Ссылка на GitHub: https://github.com/tikeswar/kido

пс. Следите за нажатием клавиш, у стен есть уши!