Что случилось, когда мы взломали выставку? +57


QRCODE через мобильное приложение для сканирования бейджей участников выставки проектов по информационной безопасности.

В прошлом году мы посетили большую выставку проектов по информационной безопасности в Лондоне. В ходе подготовки нам прислали наши пропуска в виде PDF-ников «распечатай сам».

Toms exhibitor badge

Мы сразу обратили внимание на два вида штрихкода. Что интересно, QR-код выглядел слишком плотным, учитывая, что в нём достаточно хранить только ID участника. Будучи любознательными по своей природе, мы запустили QR-сканер и получили содержимое кода:

{"CJe";"BHEEZST","DO";"Cvmmfuqsppg","G";"upn","KU";"Qfofusbujpo uftufs","T";"xzbuu"}

Это оказался «почти-но-не-совсем-JSON». Одним из плюсов такого короткого имени, как у меня, является то, что оно бросается в глаза в подобных ситуациях. Поэтому я сразу заметил, что моё имя закодировано в ROT-25 («tom» превратилось в «upn»). Он также известен как Шифр Цезаря, где каждая буква заменена на другую с фиксированным смещением (в данном случае вместо каждой буквы использовалась соседняя в алфавите). Прогнав строку через декодер (с учётом разметки JSON), мы получили:

{"BId";"AGDDYRS","CN";"Bulletproof","F";"tom","JT";"Penetration tester","S";"wyatt"}

Это уже более читаемо.

Сломаем?


Любопытно, что QR-код хранит информацию, похоже, связанную с полем «BId» в базе данных. С чего бы? Что ж, это довольно просто. Организаторы сделали мобильное приложение для вендоров, которое помогает им собирать контакты участников в ходе выставки. Мы предположили, что данные забиты в QR-код на тот случай, когда Wi-Fi или сотовый сигнал неустойчивы.

Пока мы мало что можем сделать с этой информацией, кроме как поменять наши данные, чтобы избежать спама от вендоров с мероприятия. Это было бы забавно, но врядли достойно емейла разработчику системы. Итак, мы отправились в Play Market и установили соответствующее приложение, чтобы посмотреть, что оно делает.

Screenshot of the app

И тут мы столкнулись с проблемой: у нас не было необходимых данных от организаторов мероприятия. Мы подумали, что могли бы подделать ответ сервера с помощью MiTM proxy, и приложение пустит нас. Мы настроили Burpsuite и записали несколько неудачных попыток входа, надеясь перехватить трафик и поиграться с ним.

Увы, у нас не получилось. Приложение направляло все запросы с помощью SOAP, а ответы были неочевидны. Впрочем, сервер публикует WSDL документы для приложения.

Это не конец


Почему бы не написать поддельный веб-сервис, чтобы больше не обращаться к настоящему серверу приложения? Через несколько часов у нас был такой сервис, и весь трафик был завёрнут на него. Работает! Приложение аутентифицировалось с любыми данными и подключалось к фейковому мероприятию.

Fake show in app

Мы отсканировали пару бейджей, и, похоже, всё работало правильно. Прогресс! После блуждания по приложению некоторое время стало очевидно, что оно использует какой-то фреймворк на основе WebView. Немного поковырявшись в APK, мы нашли ряд упоминаний Sencha и Ext.js, что подтвердило наше предположение.

А теперь — самое интересное. Если приложение состоит из обычной смеси HTML и JavaScript, может ли оно быть уязвимым для стандартных веб-атак? Мы завернули несколько XSS'ок в «не-совсем-JSON», который ожидает приложение, отсканировали их, и…

Fake ID in app

Мы сломали его


Превосходно! HTML-инъекция в поле «JT» показала изображение. Мы можем добавить атрибут «onerror» в этот тэг, чтбы добиться выполнения скрипта, но упираемся в ограничение максимальной длины QR-кода. В итоге мы создали полезную нагрузку, которая скачивала JS-файл с сервера и запускала его на устройстве. Вот, например, стандартный тест на «alert()»:

coding an alert

Сканирование штрихкода вызывает срабатывание XSS и исполнение кода:

Showing an XSS flaw

Мы ужали это так, чтобы оно аккуратно умещалось в максимальный размер читаемого QR-кода, не слишком плотного для печати на пропуске. После чтения документации на API Ext.js и сопоставления её с декомпилированным кодом APK нам удалось сделать штрихкод, который:

  1. Скачивает JS-файл с удалённого сервера
  2. Считывает сессионные ключи со смартфона и отправляет их на наш сервер
  3. Считывает содержимое закэшированной базы данных контактов из приложения, включающей имена и адреса электронной почты всех, чьи пропуска были отсканированы данным устройством
  4. Удаляет свою запись со смартфона

Затем атака сводится к следующему: вендор сканирует мой QR-код в обмен на бесплатную ручку, а я получаю полный список всех контактов, отсканированных этим устройством.

Полезная нагрузка:

Showing the Payload

Запросы к веб-серверу:

Showing the server response

Всё хорошо, что хорошо кончается


Мы обратили на это внимание вендоров на выставке, и после некоторого обсуждения они решили не использовать приложение в этом году. Всего несколько человек на мероприятии воспользовались приложением, в то время как большинство предпочли ему простые небольшие сканеры штрихкодов. Приложение из Маркета скачали всего около 500 раз. Тем не менее, это интересный вектор для XSS, который показывает, что вам действительно нужно фильтровать данные перед использованием независимо от их источника.

Хотя это конкретное приложение не использовалось широко, представьте, если бы уязвимость была в приложении, котором пользуются тысячи или скачивают миллионы? Все эти данные достались бы злоумышленникам, которые бы распорядились ими на своё усмотрение: от фишинговых кампаний до брутфорс-атак.

Вы можете помочь и перевести немного средств на развитие сайта



Комментарии (5):

  1. DrZlodberg
    /#18906229 / +5

    Куда же без этой картинки

    drop database
    image

  2. Maccimo
    /#18909295

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

    • legolegs
      /#18910659

      — И, боже вас сохрани, не устанавливайте до обеда мобильные приложения, написанные на JS
      — Гм… Да ведь других нет.
      — Вот никаких и не устанавливайте.

  3. g0rd1as
    /#18912671

    Проблема QR-кодов в их нечитаемости, что давно известно. Вектор просто очевиден. Ребята молодцы, что проэксплуатировали. :)