О QR-кодах и социальной инженерии +4


Новости из будущего:
Группа анонимных хакеров придумала QR-код о вакцинации, которая вешает программу для его сканирования.

© Башорг

— Рабинович, вы уклонялись от уплаты налогов так, как рассказывал прокурор?
— Совсем нет. Но его схема таки тоже заслуживает внимания.

© Фольклор

Привет, Хабр.

В этом посте я хочу немного рассказать о том, как люди пытались дурить систему ковидных QR-кодов в России. Часть методов общеизвестна, часть — не так популярна, некоторые векторы атаки открыты до сих пор, разве что актуальность уже не та. За скобками останется совсем уж криминал вроде покупки сертификата или так называемого «укола в ватку», рассматривать я буду лишь методы, не требующие ничего, кроме компьютера и чуток лихости наглости.

Кратко напомню, что представляет собой QR-код российского ковид-сертификата. В нем содержится не что иное, как ссылка определенного формата. Использовались как местные государственные сайты (mos.ru), так и федеральные (gosuslugi.ru). Речь далее пойдет именно о госуслугах.

О форматах

Всего форматов ссылок на ковид-сертификаты было три:

  1. https://www.gosuslugi.ru/vaccine/cert/verify/unrz/{{unrz}}. Эти коды выдавались с самого начала. {{unrz}} расшифровывается как «уникальный номер реестровой записи» или, проще говоря, номер сертификата.

  2. https://www.gosuslugi.ru/covid-cert/verify/9{{unrz}}?ck={{hash}}. Такие коды стали выдавать в июне 2021 года. Обратите внимание на цифру 9 перед {{unrz}}. Это показатель того, что сертификат — именно вакцинированного, а не переболевшего (цифра 8), не об анализе на COVID-19 (цифра 7), не о наличии антител (цифра 6), не является каким-то временным сертификатом (цифра 4), что бы это ни значило. {{hash}} — это, по-видимому, некая контрольная сумма, но берущаяся непонятно от чего. При замене хеша сертификат не отображался. Судя по всему, хеши вводились для защиты от предъявления чужих кодов. О том, сильно ли это помогло, мы поговорим ниже.

  3. https://www.gosuslugi.ru/covid-cert/status/{{uuid}}. Третий формат кодов ввели в ноябре 2021 года, а в январе 2022 года перевели граждан на него принудительно: все предыдущие ссылки стали недействительными. Переход мог быть связан с крупной утечкой кодов старых форматов.

Собственные домены

Первым и очевидным решением от людей, которые не могли или не хотели показывать «легальные» QR-коды, стали фальшивые сертификаты, размещенные на собственных доменах. Основных подходов было два: завести на своем домене vasyan.ru поддомен в духе gosuslugi.ru.covid-cert.verify.vasyan.ru, либо завести отдельный домен в духе gosuslugl.ru. Первый вариант обычно использовался «для себя», второй чаще использовали мутные торгаши, которые предлагали за скромную сумму в несколько тысяч рублей завести персональную страничку на таком сайте.

Долго так продолжаться не могло. Власти практически сразу же стали стращать анальными карами штрафами как тех, кто предъявляет что попало, так и тех, кто невнимательно проверяет глазами доменные имена. Чуть позже власти выпустили официальное приложение с автоматической проверкой домена, которое на домен vasyan.ru уже не ходило.

Добыча чужих QR-кодов

Дальше интереснее. УНРЗ формировался как склейка номера региона и номера самого сертификата. Самый населенный и вакцинированный регион — это Москва, т.е. 77-й регион. А вот нумерация самих сертификатов была сквозной, т.е. шла просто по порядку. Подробнее можно почитать в неплохом расследовании Медузы. Таким образом, пока работала первая версия сертификатов, можно было взять номер самого населенного региона (77) и пойти добывать сертификаты обычным перебором.

Может возникнуть закономерный вопрос: как же пользоваться чужим QR-сертификатом? Ведь есть еще и второй фактор в виде паспорта. Действительно, в теории паспорт как второй фактор требовался всюду. На практике же этого не было и близко. В одних местах годился любой документ с датой рождения, в других местах проверяющие довольствовались даже фотографией или ксерокопией паспорта. Это само по себе открывало обширные возможности по использованию фотошопа, хотя мы такого и не одобряем. Ну а в третьих местах второй фактор не требовали вовсе. О том, почему это сводит на нет всю затею, была хорошая статья в ноябре.

Другой вариант майнинга

Также высказывалась не самая технологичная, но совершенно восхитительная по дерзости идея — надеть форму охранника, встать у входа в какой-нибудь ТЦ, просить предъявлять коды и фотографировать их на телефон. Есть подозрение, что такое могло бы сработать и в этих ваших Европах и Америках с высокотехнологичными криптографическими кодами. Я в этих странах бывал мало, но где бывал, с проверкой второго фактора дела обстояли ровно так же, как и в России.

Добыча кодов второй версии

По идее, наличие второй версии ссылок должно было положить конец майнингу кодов путем перебора. В самом деле: на то, чтобы добыть хеш для конкретного номера сертификата, требуются буквально космические мощности. Но вот беда — API для получения сертификатов первой версии прикрыто не было. И по какой-то причине через него можно было получить доступ как минимум к части сертификатов, выпущенных уже после июня 2021 года. Если пройти по ссылке первого вида и включить отладчик, можно увидеть обращение к вот такому адресу: https://www.gosuslugi.ru/api/vaccine/v1/cert/verify//unrz/{{unrz}}. Сейчас по нему, правда, отдается ошибка, однако раньше в случае корректного УНРЗ отдавался вполне себе JSON вот такого вида:

Ответ от API v1

{
"unrz":"9770000022021488",
"fio":"П**** В******* В***********",
"enFio":"P**** V******* V************",
"birthdate":"20.04.1889",
"doc":"12** ***890",
"enDoc":"",
"stuff":"Гам-КОВИД-Вак Комбинированная векторная вакцина для профилактики коронавирусной инфекции, вызываемой вирусом SARS-CoV-2",
"enStuff":"Gam-COVID-Vac (“Sputnik V”), combined heterologous recombinant adenovirus (rAd)-based vaccine for prophylaxis of coronavirus infectious diseases caused by SARS-CoV-2",
"singlePhase":"N",
"vcSeries":"ll-123456",
"lastName":"",
"expiredAt":"24.02.2022",
"status":"1",
"en":false,
"qr":"
iVBORw0KGgoAAAANSUhEUgAAAHsAAAB7AQMAAABuCW08AAAABlBMVEUAAAD///+l2Z/dAAAAAnRSTlP//8i138cAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAF0SURBVEiJ1dWxjYUwDAZgoxTpYIFIWSNdViILwMsCj5XoskakLBA6igifA8chXROfdMUdonj6iof5HRvAbxf8Z8gAoxRvE90KHQ82LA7R7xoD/ebBqiZZhr24AI4PRnhUPwKHIkvh+YBlNPRYXJ7SG0B5uKDq/QTUALo2jJOM89OGBmRJeSdKvQfteUDVvSw9VmcDAw8OS8+k9irq8MIEEH4lS7hflbYB1wIyAohXbRcLDis2inwvvbwrbcH5TjCskWDmAYa0hDhaQWV6JiDlTamXDgXy4DD6bdWwlt5cjWrDhpR3HbuXvDvXgsOIQ9JNJyh2TIAIVp3FqoEJdXQoD9XLz9KbkE0ZbZksjPZuVAswaB/o+KRDlo4HGcpkEs03gEYe1JkL6gzjWgZtoMme6kCULtx/2oK6C6lMmzx+rZwWnLuwNymDmtkw75FWzgjXzLHAoabjMITomFD3esqW8igzD+rXA9KyAm2pjQe/8Vn7G/ABJ3g+P8H1+/gAAAAASUVORK5CYII="
}

Обратите внимание на поле qr. В нем при помощи base64 кодировалось изображение QR-кода со ссылкой на сертификат второй версии. Т.е. можно было, зная один лишь только УНРЗ, получить его секретный хеш! До этого наверняка дошли не все «майнеры», но их было явно больше нуля.

Долго это все продолжаться не могло, и в конечном итоге огромная база кодов была слита в Интернет. Я полагаю, что дело все же в инсайде: майнить несколько миллиардов кодов — дело непростое и небыстрое, а толку от полученных данных, будем честными, не слишком много. Кроме того, чтобы не положить сервис госуслуг, явно пришлось бы еще и размазывать обращения во времени и пространстве. Организация ради этих данных мощного ботнета не выглядит самым рентабельным на свете мероприятием. Так или иначе, все коды, которые существовали до января, были отменены буквально в один день, а вместо старых QR-кодов всем выдали новые, третьей версии.

«Честные» коды с необычным поведением

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

  1. Самая брутальная и примитивная попытка режется защитой от XSS и выдает ошибку. При этом никакой конкретной информации не дается, сайт не сообщает о попытке взлома, но и как валидный запрос трактовать обращение не спешит.

  2. Некорректный UUID возвращает, как и следовало ожидать, Bad Request. Однако на странице ответа написано о недоступности сервиса. Где-то здесь уже можно почуять серьезные возможности для социальной инженерии. Но внезапная недоступность такого важного сервиса все же может показаться странной проверяющему. Вот бы были еще какие-нибудь предварительные «звоночки» для усыпления бдительности…

  3. И их, как выяснилось, можно организовать. Если отправить чуть более хитрый запрос, то защита отдаст ошибку (ту же, что в первом пункте) при загрузке не целого документа, а одного из его компонентов. Это приводит к любопытному эффекту: гифка, которая изображает загрузку сайта, не сменяется показом сертификата, что создает впечатление того, что сайт завис.

По словам знакомого, после предъявления кода с вечной загрузкой, а потом — с недоступностью сервиса, терялись даже бывалые вахтеры. Обычно, впрочем, хватало и одного только «вечного» варианта. Рассказывали также еще об одном забавном случае, когда вахтер сообщил, что надо было полностью сертификат выкачивать на телефон, а не только QR-код с монитора фотографировать. Потому что сфотографировали с кривой перспективы, вот код и сбоит :)

Заключение

На полноту обзора методов в таком щекотливом вопросе претендовать сложно. Не исключаю, что эксплуатация XSS у кого-нибудь все же увенчалась успехом. Или, может, кто-то и вовсе нашел способ попасть в базу QR-кодов напрямую. Но что-то нетривиальное, я надеюсь, в статье все же было. В конечном счете, это все теперь неактуально: как известно, мы в очередной раз окончательно победили коронавирус, и все ограничения были сняты. Вся информация предоставлена исключительно для ознакомительных целей и все такое. Не болейте, берегите себя и своих близких.




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

  1. Maxim_Q
    /#24364778

    Пасхалок в тексте всего 2 или есть еще?

    Если интересно найти самому пасхалки НЕ открывайте спойлер

    1я в QR коде на фото в заголовке, 2я в тексте где в base64 сидит png картинка, а на картинке QR код

    • red_void
      /#24365446

      Есть еще одна «явная», т.е. прямо написано про пасхальное яйцо, и еще есть не совсем пасхалка, скорее просто шутка.

      • Maxim_Q
        /#24365960

        Итого 4? Я сдаюсь, не могу найти еще 1 явную пасхалку и еще одну шутку. Спрячте под спойлер еще не достающие 2 пасхалки.

        • red_void
          /#24366004 / +1

          Спойлер
          1. Некорректный UUID в разделе про честные коды с необычным поведением содержит пару слов.
          2. Дата рождения в ответе API v1 выбрана не случайно.

  2. Gudd-Head
    /#24365294 / +2

    Я просто попросил друга скинуть его QR код мне.

  3. ifap
    /#24365614 / +2

    Был еще интересный способ (не знаю, универсальный ли). Пишешь в поддержку госуслуг: я болел, где мой код, доколе?! И в ответ почти сразу получаешь извинения, обещания разобраться и настоящий трехдневный промо QR-код ;) ЧСХ, постоянный мне так и не выдали. Впрочем, у меня ни разу и не спрашивали.

  4. brukva
    /#24367938 / +1

    А ещё можно сделать нечитаемый QR-код. Он для человека выглядит, как код, а читалки его игнорируют. Потом, правда, придётся убеждать вахтёра, что у него читалка битая, на это не все поведутся.