Мобильные телефоны, а точнее смартфоны, плотно вошли в нашу жизнь. Не последнюю роль в них играет камера и возможность упрощать некоторые задачи с помощью сканирования QR кодов. Но в этом инструменте кроется одна большая проблема, атака при помощи QR кода, позволяет нанести немалый вред не внимательным пользователям. Сегодня мы расмотрим векторы реализации подобных атак.
QR-код (англ. Quick Response Code — код быстрого реагирования) — это матричный или двумерный штрих-код, который может содержать до 4296 символов ASCII. То есть, проще говоря, картинка, в которой зашифрован текст.
История вектора Атаки при помощи QR кода.
В мае 2013 года специалисты компании по сетевой безопасности Lookout Mobile разработали специальные QR-коды, которые смогли скомпрометировать очки Google Glass. На тот момент очки сканировали все фотографии, «которые могут быть полезны их владельцу», — и предоставили взломщикам полный удаленный доступ к устройству. Исследователи сообщили в Google о данной уязвимости, и ее закрыли буквально за несколько недель. К счастью, исправить успели до того, как ее можно было использовать вне лаборатории, ведь взлом очков реального пользователя мог привести к большим проблемам.
В 2014 году программа Barcode Scanner для мобильных устройств из проекта ZXing практически не проверяла тип URI, передаваемый через QR-код. В результате любой эксплоит, который мог быть исполнен браузером (например, написанный на JavaScript), можно было передать через QR.
Сканер пытался отфильтровать опасные виды атак с помощью регулярных выражений, требуя, чтобы URI имел период с последующим продлением как минимум на два символа, транспортный протокол длиной не менее двух символов, за которым следует двоеточие, и чтобы в URI не было пробелов.
Если содержимое не соответствует хотя бы одному из требований, то оно определяется как обычный текст, а не URI. Этот механизм блокирует атаки вроде javascript;alert("You have won 1000 dollars! Just Click The Open Browser Button");
, но, внеся пару простых изменений в код, мы получаем вариант, который программа исполняла в браузере, ведь она считала JS-код обыкновенным, «нормальным» URI!
Вот как это выглядело.
Как мы можем увидеть, уведомление появилось в браузере, а значит, URI с потенциально вредоносным кодом был выполнен. Однако выполняется данный JS-код лишь тогда, когда пользователь нажимает Open Browser (то есть «Открыть в браузере»).
Еще один интересный пример из 2012 года: эксперт по информационной безопасности Равишанкар Боргаонкар (Ravishankar Borgaonkar) продемонстрировал, как сканирование простейшего QR может привести к форматированию устройств Samsung! Что же было внутри? MMI-код для сброса до заводских настроек: *2767*3855#
, а также префикс tel:
для совершения USSD-запроса.
Самое опасное здесь — что человек без предварительной подготовки не может узнать содержимое кода, не отсканировав его. А человек очень любопытен: в различных исследованиях большинство испытуемых (которые, кстати, даже не знали об эксперименте) сканировали QR-код именно из любопытства, забывая о собственной безопасности. Поэтому всегда будь внимателен!
Если у тебя нет сканера кодов, но уйма свободного времени — можно попробовать расшифровать код вручную. Инструкция есть на Хабре.
QRGen — каждому по коду
Для демонстрации средств работы с QR-кодами я буду использовать Kali Linux 2019.2 с установленным Python версии 3.7 — это необходимо для корректной работы утилит.
Начнем с утилиты QRGen, которая позволяет создавать QR-коды с закодированными в них скриптами. Копируем репозиторий и переходим в папку с содержимым.
git clone https://github.com/h0nus/QRGen
cd QRGen && ls
QRGen требует Python версии 3.6 и выше. Если возникает ошибка, попробуй обновить интерпретатор.
Устанавливаем все зависимости и запускаем сам скрипт.
pip3 install -r requirements.txt
## или python3 -m pip install -r requirements.txt
python3 qrgen.py
Видим справку.
Аргумент -h
выведет то же самое, а вот запуск с ключом -l
приведет к генерации QR-кодов из определенной категории. Всего их восемь.
- SQL-инъекции.
- XSS.
- Инъекции команд.
- QR с форматированной строкой.
- XXE.
- Фаззинг строк.
- SSI-инъекции.
- LFI или получение доступа к скрытым каталогам.
Возможные атаки
Теперь давай посмотрим на примеры из каждой категории, а также разберемся, какой урон и каким устройствам они могут нанести.
1. 0'XOR(if(now()=sysdate(),sleep(6),0))XOR'Z
2. <svg onload=alert(1)>
3. cat /etc/passwd
4. %d%d%d%d%d%d%d%d%d%d
5. <!ENTITY % xxe SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd" >
6. "A" x 33
7. <pre><!--#exec cmd="ls" --></pre>
8. ../../../../../../etc/passwd
Посмотреть текстовые файлы со всеми вариантами «начинки» QR-кодов ты можешь в папке words
(они разделены по категориям, указанным выше).
Теперь пара слов о последствиях атак подобными нагрузками.
Первый класс атак — SQL-инъекции — используют при взломе БД и нарушении работы веб-сайтов. Например, запрос может вызывать зависание сайта.
Следующий пример (под номером 2) демонстрирует эксплуатацию XSS-уязвимости при атаке на веб-приложения с использованием SVG (Scalable Vector Graphic). К чему может привести XSS, ты, думаю, и без меня прекрасно знаешь, так что подробно на этом останавливаться не буду.
Третий пункт выводит на экран жертвы содержимое файла /etc/passwd
: список аккаунтов Linux-based-систем и дополнительную информацию о них (раньше — хеши паролей этих учетных записей). В подобных случаях обычно стараются получить /etc/shadow
и конфигурацию сервера, но все очень сильно зависит от цели, так что какие файлы читать — решай сам.
Четвертый пример представляет собой выражение, которое вызовет переполнение буфера (buffer overflow). Оно возникает, когда объем данных для записи или чтения больше, чем вмещает буфер, и способно вызвать аварийное завершение или зависание программы, ведущее к отказу в обслуживании (denial of service, DoS). Отдельные виды переполнений дают злоумышленнику возможность загрузить и выполнить произвольный машинный код от имени программы и с правами учетной записи, от которой она выполняется, что делает эту ошибку довольно опасной.
Пятый по счету класс атак (XXE Injections) представляет собой вариант получения скрытой информации веб-сервера с помощью анализа вывода XML-файлов. Конкретно в нашем примере при запросе к серверу тот ответит зашифрованным в Base64 содержимым файла /etc/passwd
, который уже упоминался. Однако расшифровать его не составит труда — достаточно лишь воспользоваться встроенной в большинство дистрибутивов Linux утилитой base64
либо же онлайн-конвертером.
Атаки форматной строки (пример 6) — это класс уязвимостей, который включает в себя предоставление «специфичных для языка маркеров формата» для выполнения произвольного кода или сбоя программы. Говоря человеческим языком, это класс атак, при которых приложение некорректно очищает пользовательский ввод от управляющих конструкций, из-за чего эти конструкции в результате исполняются. Если ты программировал на С, то, конечно, помнишь те интересности с выводом переменных через printf
: надо было в первом аргументе (который строка) указать на тип выводимого значения (%d
для десятичного числа и так далее).
Седьмой пункт представляет собой вариант command injection, которая выполняет определенный код на стороне сервера. В моем примере будет выполнена команда ls
, которая покажет содержимое текущей директории, но, конечно, там может быть гораздо более опасный код.
И наконец, последняя категория — это LFI-уязвимости (Local File Inclusion; включение локальных файлов), позволяющие просмотреть на уязвимых (или неправильно настроенных) серверах файлы и папки, которые не должны были быть видны всем. Один из возможных вариантов — просмотреть файл /etc/passwd
, о котором мы с тобой уже не раз говорили. Это может выглядеть вот так.
Обрати внимание, что в качестве тестового веб-приложения используется DVWA (Damn Vulnerable Web Application), который был специально разработан для обучения пентесту. Многие атаки на веб-приложения можно отработать на нем.
Практика
А сейчас перейдем к практике — протестируем эту утилиту сами.
Например, запустим ее с ключом -l 5
:
python3 qrgen.py -l 5
Утилита сгенерировала 46 QR-кодов с полезными нагрузками. Все они лежат в папке genqr
.
Каждый из них содержит вредоносный код, поэтому хоть я и приведу пример, но часть его будет вырезана.
Теперь можем запустить скрипт с флагом -w
(напомню, он заставляет скрипт использовать кастомный словарь), но сначала нам нужен файл с нашими полезными (и не очень) нагрузками. Можем использовать готовые нагрузки из Metasploit (в Kali они находятся по пути /usr/share/metasploit-framework/modules/payloads
) либо же создать новый текстовый документ и в него записать что-нибудь «плохое», например команду для удаления всех файлов на Linux-based-системе:
rm -rf /*
Итак, я назвал наш «вирус» clear.txt
и запускаю QRGen (предварительно удалив или очистив папку genqr
):
python3 qrgen.py -w /путь/до/clear.txt
Иногда может возникать ошибка, как на скриншоте ниже. Не пугайся, на работоспособность генератора кодов она не влияет.
Если ты перфекционист и хочешь ее исправить, то замени format(i-1)
на format(i)
в самом конце скрипта.
Теперь давай посмотрим на сам QR-код (естественно, с вырезанной частью) и отсканируем его на одном из онлайн-сервисов.
Как мы можем видеть из скриншота выше, наш текст был абсолютно верно перенесен в QR-код!
Эта утилита (и вектор атаки) направлена скорее на проверку незащищенного и непопулярного ПО либо же узкоспециализированных инструментов (вроде складских QR-сканеров, отправляющих SQL-запросы к базе данных компании). Большинство современных сканеров из соображений безопасности не выполняют находящийся в QR код. Соответственно, вариантов развития событий после сканирования два.
- Сканер просто выводит содержимое нашего изображения (невыгодный для хакера вариант).
- Сканер исполняет код, находящийся внутри изображения, либо же, используя пример, о котором мы говорили раньше, отправляет SQL-запрос к БД организации. Он и становится первым шагом к взлому базы данных компании. Естественно, глупо при таком раскладе рассчитывать, что распознанный текст будет выполнен как самостоятельный запрос, так что бери нагрузку вроде той, которую обычно используешь в веб-приложениях.
QRLJacker
Теперь переходим ко второму инструменту — QRLJacker. Он отчасти похож на QRGen, но представляет совершенно другой вектор атаки — QRLJacking.
SQRL (произносится как squirrel — белка, а расшифровывается как Secure, Quick, Reliable Login или Secure Quick Response Login) — открытый проект для безопасного входа на веб-сайт и аутентификации. При входе, естественно, используется QR-код, который обеспечивает проверку подлинности.
Как же выполняется вход при использовании данного способа аутентификации?
- Пользователь посещает сайт и открывает сессию.
- Сайт генерирует QR-код с ключом сессии. Этот код регулярно меняется в целях безопасности.
- Пользователь сканирует QR-код.
- Мобильное приложение генерирует аутентификационный сигнал, который содержит секретный токен (в него входят ID пользователя, код сессии, специальное сообщение, созданное с помощью приватного ключа пользователя).
- Сайт получает сигнал и идентифицирует пользователя, производя вход (если, конечно, верификация завершена корректно).
Довольно долго метод SQRL считался действительно безопасным, пока Мохамед Бассет (Mohamed Basset) не предложил способ атаки на сервисы, использующие SQRL, который был назван QRLJacking. Способ требует создать фишинговую страницу и разместить на ней генерируемый через определенные промежутки времени QR-код. Давай рассмотрим его поподробнее.
- Злоумышленник инициирует клиентскую QR-сессию и клонирует код QR-логина на фишинговую страницу.
- Жертве отправляется ссылка на эту страницу. Выглядит страничка вполне безопасно.
- Жертва сканирует поддельный QR-код, а приложение отправляет секретный токен, завершающий процесс аутентификации.
- Злоумышленник получает подтверждение от сервиса и теперь может контролировать аккаунт жертвы.
Именно для реализации данного метода была создана утилита QRLJacker, о которой сейчас и пойдет речь.
Какие веб-ресурсы уязвимы перед подобным вектором атаки? По заверению разработчиков, это популярные мессенджеры вроде WhatsApp, WeChat, Discord, Line, все сервисы Яндекса (ведь для входа в любой из них требуется вход в Яндекс.Паспорт, который и предоставляет возможность аутентификации через QR), популярные торговые площадки Alibaba, AliExpress, Tmall и Taobao, сервис AliPay, а также приложение для удаленного доступа AirDroid. Само собой, список неполный, ведь все ресурсы, использующие SQRL, просто не перечесть.
Теперь давай установим утилиту QRLJacker (программа работает только на Linux и macOS, более подробную информацию можешь найти в README проекта, к тому же нам необходим Python 3.7+).
- Заходим в систему от имени суперпользователя (root), иначе Firefox может выдать ошибку при запуске модулей фреймворка QRLJacker.
- Обновляем Firefox до последней версии.
-
Скачиваем самый новый
geckodriver
с GitHub и распаковываем файл, затем выполняем командыchmod +x geckodriver sudo mv -f geckodriver /usr/local/share/geckodriver sudo ln -s /usr/local/share/geckodriver /usr/local/bin/geckodriver sudo ln -s /usr/local/share/geckodriver /usr/bin/geckodriver
-
Клонируем репозиторий и переходим в папку с содержимым:
git clone https://github.com/OWASP/QRLJacking cd QRLJacking/QRLJacker && ls
-
Устанавливаем все зависимости:
python3.7 -m pip install -r requirements.txt
-
Запускаем фреймворк (с ключом
--help
для получения краткой справки):python3.7 QrlJacker.py --help
При обычном запуске (без аргументов вовсе) ты увидишь примерно такую картинку.
Прописав команду help
внутри фреймворка, ты получишь полную справку по командам QRLJacker.
Теперь давай запустим единственный (на данный момент) модуль — grabber/whatsapp
. Список всех доступных модулей можем посмотреть командой list
, выбрать модуль для использования — командой use
. Команда options
подскажет нам текущие значения опций, а set
задаст то или иное значение опции. Команда run
запустит наш модуль, а командой jobs
мы можем просмотреть активные задачи.
Порт 1337 стандартный для данного фреймворка, остальные опции я трогать не стал. HOST
оставил локальным (0.0.0.0), но вывести его в сеть — не проблема. Это можно сделать, используя, например, ngrok
:
ngrok http 1337
Параметр User-Agent
также решил оставить дефолтным (по умолчанию), но всего там три варианта: стандартный, случайный и кастомный (ручная настройка). Используй вариант, который тебе больше всего подходит.
После чего запускаю модуль и смотрю текущие задачи. Там указан их ID, название модуля, а также адрес, на котором располагается страница модуля. По стандарту она выглядит так (QR-код частично замазан для защиты от ~~людей в погонах~~ злоупотреблений):
Изменить эту страницу можно, поправив по своему вкусу файл QRLJacker/core/templates/phishing_page.html
.
Оригинальный исходник прост и незамысловат, что позволяет быстро изменить текст даже неподготовленному взломщику.
После внесения изменений в файле они будут автоматически применены в фреймворке.
Написание своих модулей
Давай обсудим, что необходимо для создания своего модуля для QRLJacker.
Документацию и инструкцию по созданию модулей ты можешь найти в репозитории проекта либо в папке, которую ты клонировал раньше (QRLJacker/docs/README.md
). Модули-грабберы — основа фреймворка, и располагаются они в QRLJacker/core/modules/grabber
. Когда ты добавляешь туда любой Python-файл, он появляется в фреймворке с тремя опциями — хост, порт и юзерагент.
Код модуля должен быть построен по такому шаблону:
## -*- coding: utf-8 -*-
from
core.module_utils import types
class info:
author = ""
short_description = ""
full_description = None
class execution:
module_type= types.grabber
name = ""
url = ""
image_xpath = ""
img_reload_button = None
change_identifier = ""
session_type = "localStorage"
Например, модуль grabber/whatsapp
сделан именно в этом формате, посмотреть его также можно в репозитории или открыв сам Python-файл, лежащий в QRJacker/core/modules/grabber/whatsapp.py
.
Теперь давай разберемся, что означает каждая из переменных, которые мы задаем на этих строках.
Класс info
Тут твое имя (или никнейм), которое появится при вызове справки модуля, краткое описание модуля и его полное описание (можно заполнять, можно оставить значение None
). Больше ничего интересного в классе info
нет, но прежде, чем мы перейдем к следующему (execution
), давай посмотрим вызов справки (которая будет черпать информацию из кода) на примере модуля WhatsApp. Вот код info
:
class info:
author = "Karim Shoair (D4Vinci)"
short_description = "Whatsapp QR-sessions grabber and controller"
full_description = None
А вот справка по модулю.
$ info grabber/whatsapp
Module : grabber/whatsapp Provided by : Karim Shoair (D4Vinci) Description : Whatsapp QR-sessions grabber and controller
Класс execution
Тут возни уже побольше: нужно не только название модуля, но и URL сайта, откуда будет браться QR-код и где будет производиться авторизация. Также нужен XPATH изображения с QR-кодом на странице. Чтобы понять, что это, опять обратимся к примеру в виде модуля WhatsApp. Там данный параметр выглядит как /html/body/div[1]/div/div/div[2]/div[1]/div/div[2]
, то есть путь до объекта внутри HTML-документа.
Далее нужен XPATH кнопки, которая обновляет QR-код на странице (если таковая имеется, в противном случае оставь значение None). Для большей конспирации используется XPATH элемента, который исчезает после получения сессии. Например, разработчики QRLJacker в модуле grabber/whatsapp
использовали чекбокс «Запомнить меня».
И напоследок нужна переменная, которая принимает значения localStorage
или Cookies
. Она должна соответствовать способу, с помощью которого на веб-сайте определяется пользовательская сессия.
Вот и все — после того как разберешься со всеми этими пунктами, тебе останется лишь добавить файл в папку с граббер-модулями и создать HTML-файл (index.html
) со страницей в core/www/твое_имя_модуля
.
Готово! Ты создал свой модуль.
Угоняем сессию
А теперь бегло посмотрим, как можно использовать этот фреймворк для атаки QRLJacking. Например, злоумышленник может скопировать оригинальный сайт web.whatsapp.com
и вставить туда фальшивый QR-код для получения доступа к сессии. Или пример, который приводит сам создатель утилиты QRLJacker.
Это плагин, который, если зайти на популярный зарубежный сайт Amazon, выдаст тематическое уведомление о «получении подарка от WhatsApp в честь Дня святого Валентина» (обрати внимание на правый верхний угол). Естественно, чтобы получить подарок, нужно отсканировать QR-код, что не даст тебе ничего, кроме утечки личных данных. Будь очень бдителен, ведь, как я и показал раньше, этот вектор атаки и утилиты для его использования находятся в открытом доступе, а написать модуль для QRLJacker — задача, посильная даже начинающему питонисту.
Итоги
Как ты (теперь) знаешь, даже использование QR-кода для логина больше нельзя считать безопасной практикой. Любой школьник с пачкой убедительно написанных писем может заманить на вполне настоящий сайт и угнать твой WhatsApp. Надеюсь, этот небольшой обзор отучит тебя бездумно сканировать каждый попавшийся на глаза код.