В данной статье хочу рассказать о небольшом исследовании безопасности касающегося использования электронной цифровой подписи (ЭЦП) на казахстанских ресурсах. В ней вы узнаете о последствиях некорректной реализации проверки ЭЦП в информационных системах в масштабах страны. Техническое описание и инструменты для выявления такой уязвимости прилагаются. Будет актуально всем, кто работает с похожими системами, а казахстанским компаниям и разработчикам — обязательно к прочтению.
Что такое ЭЦП и как ее использовать в общих чертах и в контексте Республики Казахстан кратко описано тут и тут. Но самое важное, что ЭЦП позволяет не только аутентифицировать ее владельца в различных ИС, она так же равнозначна собственноручной подписи и имеет такую же юридическую силу (статья 10, закона об ЭЦП РК).
В этой ИС использовалась подпись в формате XML-Dsig, как указано в примере на скриншоте ниже:
Пример подписи XML-Dsig
Здесь можно выделить 3 элемента XML:
Однако, я пошел дальше и понял, что подпись самого сертификата так же не проверялась, а значит я мог изменять любые значения в нем, в том числе и ИИН пользователя.
Сам сертификат X.509 — это бинарный файл, кодированный с помощью Distinguished Encoding Rules (DER) и сериализованный в ASN.1. Править его руками в HEX-редакторе занятие непростое: при изменении длины строки вся структура смещается и нужно менять кучу значений во всей структуре. Для этих целей существует специальное ПО, например ASN.1 Editor.
У сертифката есть набор свойств: серийный номер, алгоритм подписи, информация об издателе и владельце, срок действия, открытый ключ, цифровая подпись самого сертифката для его проверки и прочее. Для идентифкации свойств используятся Object identifier (OID).
Например, для хранения ИИН владельша используется стандарнтый OID 2.5.4.5 (SerialNumber), 2.5.4.3 (CN) для имени и фамилии. Другие идентификаторы описаны в правилах выдачи регистрационных свидетельств национальным удостоверяющим центром РК.
Вот пример структуры сертификата физического лица, выданного НУЦ РК (значения изменены):
После изменения сертификата и упаковки его обратно в контейнер PKCS#12 (файл *.p12) NCALayer отказывался принимать его, что предсказуемо, ведь подпись сертификата теперь не может пройти проверку.
Хорошо, что количество цифр в ИИН фиксировано и эти 12 байт в бинарном виде сертификата можно поменять “налету”, не меняя структуру данных ASN.1. Что я и сделал в первом PoC для этой ИС: подменял ИИН в сертификате, кодировал его в BASE64, отправлял запрос на сервер с модифицированной подписью XML-Dsig, а в ответ получал идентификатор сессии.
Так я впервые обошел аутентификацию на основе ЭЦП. Забегая вперед, хочется сказать, что это была не худшая реализация работы с ЭЦП.
Используя Google-дорки, список авторизованных ИС для работы с ЭЦП и прочие порталы со списком популярных в РК сервисов для граждан, удалось найти больше 90 разных ИС. Однако проверить удалось только 80 из них. Остальные либо не работали, либо требовали закрытой регистрации.
В итоге 52 из 80 проверенных ИС оказались уязвимы и позволяли обойти механизм аутентификации ввиду отсутствия проверки сертификата пользователя. Уточню, что некоторые ресурсы использовали ЭЦП как один из факторов, и в этом случае риск был не так критичен.
В этом списке не учитывались ИС собщим бэкендом/провайдером аутентификации, если учитывать каждую, то можно смело увеличить этот список в двое.
Например, были найдены 4 системы документооборота, с которых работают крупнейшие организации страны, в том числе государственные органы (от 5 до 100 тысяч организаций (по данным официальных сайтов). Данные системы предоставляли доступ к платформе SaaS/PaaS, что позволяло (в теории) получить доступ к личным кабинетам клиентов, а в некоторых случаях и к административной части системы. В том числе была найдена система документооборота on-premises с множеством инстансов в РК.
Одна из проверенных ИС принадлежала банку, хотя и не была связана с ДБО. А также были ИС и порталы, вязанные со здравоохранением, образованием и социальными услугами для населения.
На одном из таких порталов мне удалось войти от имени пользователя с “очень большими“ привилегиями и доступом к персональным данными родителей и их детей общим количеством более миллиона записей. Не лучшая идея — делать административный интерфейс с такими привилегиями с доступом из публичной сети.
Ну и конечно же портал с электронными петициями, где также используется ЭЦП и из-за отсутствия нормальной проверки можно накрутить голоса. Вот ссылка на новость на inbusiness.kz.
Все детали уязвимостей были отправлены на Bug Bounty платформу Tumar. И тут надо сказать спасибо команде ЦАРКА за их труд, ибо общение с владельцами ИС — это совершенно неблагодарное занятие.
Ситуацию усугубляет тот факт, что по некоторым ИС отчеты были отправлены еще в феврале, а устранены были единицы и даже МЦРИАП (Министерство цифрового развития и аэрокосмической промышленности) ничего не может с этим поделать.
На большей части ИС проверялась подпись данных, но не сертификат, пришлось разбираться как подписать данные на Python в формате XML-Dsig, CMS и CAdES. Пришлось также разбираться как модифицировать сертификат, разбирать и собирать заново структуру ASN.1, что с моим уровнем владения Python было непросто.
Ситуацию осложняло и то, что разработчики в некоторых ИС радовали изобретательностью. В некоторых ИС от одного разработчика был общий бэкенд аутентификации, с несколькими запросами и редиректами на разные хосты, да и формат данных был везде разный. На одной из ИС вообще была обфускация отправляемых данных и самого JS-скрипта для их отправки!
В общем требовалось много времени на PoC для каждой ИС, а учитывая список из 40 штук (на тот момент) руки начали опускаться. Пока в голову не пришла отличная идея.
Для получения официального SDK, надо подписывать NDA и другие бумаги с НУЦ РК, что не выглядело разумной идеей. На официальном форуме (старом и новом), как и в репозитории на GitHub, информации по работе с NCALayer было мало. Буквально крохи информации.
Так что в ход пошли DevTools и Burp для анализ общения браузера и NCALayer. Еще очень помог ресурс с интерактивной документацией по KAZTOKEN mobile. Это не официальная документация, но очень близко кто тому-что было по факту.
Все общение сводилось к обмену сообщениями в формате JSON внутри WebSocket’a, и в обобщенном виде оно выглядело так:
Если не вдаваться в детали, то браузер сначала посылает запрос о статусе и получает в ответ готовность и версию, затем отправляет запрос на подписание данных.
В этом запросе указывается модуль для подписи, метод, сами данные для подписи и другие параметры. А в ответ получает цифровую подпись в запрошенном формате, либо сообщение об ошибке. Есть еще много нюансов, но они сейчас не важны.
Самих модулей и их методов много, но реализованы были лишь те, что попадались в проверяемых ИС.
Скрипт FCALayer.py получился довольно компактным, 1000+ строк, половина из которых комментарии. На данный момент в скрипте реализовано 17 методов в 4-х модулях и доступен следующий функционал:
Параметры запуска
Пример работы скрипта
В некоторых ИС для аутентификации требовался контейнер с ключами, а криптографические функции были реализованы на JavaScript. Некоторые ИС для аутентификации просто отправляли сертификат, без ЭЦП. В одной так и вовсе контейнер с ключами отправлялся на сервер, разумеется, перед этим спросив пользователя пароль от него (исправлено владельцем после отправки отчета).
А разработчики одной страховой компании совсем уж не стали заморачиваться со всей этой криптографией и решили отправлять только ИИН, открытым текстом без пароля и каких-либо проверок.
По этим причинам был создан еще один скрипт — make‑p12.py. Он просто генерирует сертификат с нужными свойствами и закрытый ключ, сохраняя все в контейнер PKCS#12.
Более подробную информацию можно найти в репозитории FCALayer (доступ быдет открыт позже).
Почему так случилось:
Собственно, такая попытка была со стороны одного SOC, но небольшой фикс и отчет был успешно отправлен на платформу. В текущей реализации я убрал этот фикс, позже верну.
Кому нужен FCALayer? Для аудиторов и разработчиков. Некоторые владельцы ИС заявляли модераторам платформы, что исправили уязвимость и просили перепроверить несколько раз. Но ничего не менялось. То есть отдельным разработчикам не только сложно реализовать проверку подлинности, но и проверить ее работу.
Еще я уверен, что такой инструмент должны разрабатывать те же люди что и NCALayer. При проверке некоторых ИС мне приходилось добиваться одинакового ответа как в NCALayer, буквально посимвольно: соблюдать длину строки для BASE64, правильно выбирать управляющие символы для конца строки (\r\n), соблюдать регистр тегов XML и многое другое.
На этом все, спасибо, что дочитали!
Источник
Предыстория
Впервые взглянуть на электронную цифровую подпись (ЭЦП) с технической точки зрения мне довелось осенью 2023 года во время проекта по тестированию на проникновение крупной государственной организации. В одной из ее информационных систем (ИС) была возможность использовать ЭЦП для входа в личный кабинет, с NCALayer в качестве посредника.Что такое ЭЦП и как ее использовать в общих чертах и в контексте Республики Казахстан кратко описано тут и тут. Но самое важное, что ЭЦП позволяет не только аутентифицировать ее владельца в различных ИС, она так же равнозначна собственноручной подписи и имеет такую же юридическую силу (статья 10, закона об ЭЦП РК).
В этой ИС использовалась подпись в формате XML-Dsig, как указано в примере на скриншоте ниже:
Пример подписи XML-Dsig
Здесь можно выделить 3 элемента XML:
- DigestValue - хэш подписываемых данных;
- SignatureValue – сама подпись;
- X509Certificate – сертификат пользователя с открытым ключом.
Однако, я пошел дальше и понял, что подпись самого сертификата так же не проверялась, а значит я мог изменять любые значения в нем, в том числе и ИИН пользователя.
Сам сертификат X.509 — это бинарный файл, кодированный с помощью Distinguished Encoding Rules (DER) и сериализованный в ASN.1. Править его руками в HEX-редакторе занятие непростое: при изменении длины строки вся структура смещается и нужно менять кучу значений во всей структуре. Для этих целей существует специальное ПО, например ASN.1 Editor.
У сертифката есть набор свойств: серийный номер, алгоритм подписи, информация об издателе и владельце, срок действия, открытый ключ, цифровая подпись самого сертифката для его проверки и прочее. Для идентифкации свойств используятся Object identifier (OID).
Например, для хранения ИИН владельша используется стандарнтый OID 2.5.4.5 (SerialNumber), 2.5.4.3 (CN) для имени и фамилии. Другие идентификаторы описаны в правилах выдачи регистрационных свидетельств национальным удостоверяющим центром РК.
Вот пример структуры сертификата физического лица, выданного НУЦ РК (значения изменены):
После изменения сертификата и упаковки его обратно в контейнер PKCS#12 (файл *.p12) NCALayer отказывался принимать его, что предсказуемо, ведь подпись сертификата теперь не может пройти проверку.
Хорошо, что количество цифр в ИИН фиксировано и эти 12 байт в бинарном виде сертификата можно поменять “налету”, не меняя структуру данных ASN.1. Что я и сделал в первом PoC для этой ИС: подменял ИИН в сертификате, кодировал его в BASE64, отправлял запрос на сервер с модифицированной подписью XML-Dsig, а в ответ получал идентификатор сессии.
Так я впервые обошел аутентификацию на основе ЭЦП. Забегая вперед, хочется сказать, что это была не худшая реализация работы с ЭЦП.
Больше уязвимостей богу уязвимостей
Исходя из опыта, я был уверен, что другие разработчики при работе с ЭЦП будут допускать аналогичные ошибки. А учитывая растущую популярность использования ЭЦП в различных организациях, таких систем должно быть немало.Используя Google-дорки, список авторизованных ИС для работы с ЭЦП и прочие порталы со списком популярных в РК сервисов для граждан, удалось найти больше 90 разных ИС. Однако проверить удалось только 80 из них. Остальные либо не работали, либо требовали закрытой регистрации.
В итоге 52 из 80 проверенных ИС оказались уязвимы и позволяли обойти механизм аутентификации ввиду отсутствия проверки сертификата пользователя. Уточню, что некоторые ресурсы использовали ЭЦП как один из факторов, и в этом случае риск был не так критичен.
В этом списке не учитывались ИС собщим бэкендом/провайдером аутентификации, если учитывать каждую, то можно смело увеличить этот список в двое.
Масштаб проблемы
Большинство уязвимых ИС принадлежат или созданы для государственных или квазигосударственных организаций. Часть из них принадлежала коммерческим организациям.Например, были найдены 4 системы документооборота, с которых работают крупнейшие организации страны, в том числе государственные органы (от 5 до 100 тысяч организаций (по данным официальных сайтов). Данные системы предоставляли доступ к платформе SaaS/PaaS, что позволяло (в теории) получить доступ к личным кабинетам клиентов, а в некоторых случаях и к административной части системы. В том числе была найдена система документооборота on-premises с множеством инстансов в РК.
Одна из проверенных ИС принадлежала банку, хотя и не была связана с ДБО. А также были ИС и порталы, вязанные со здравоохранением, образованием и социальными услугами для населения.
На одном из таких порталов мне удалось войти от имени пользователя с “очень большими“ привилегиями и доступом к персональным данными родителей и их детей общим количеством более миллиона записей. Не лучшая идея — делать административный интерфейс с такими привилегиями с доступом из публичной сети.
Ну и конечно же портал с электронными петициями, где также используется ЭЦП и из-за отсутствия нормальной проверки можно накрутить голоса. Вот ссылка на новость на inbusiness.kz.
Все детали уязвимостей были отправлены на Bug Bounty платформу Tumar. И тут надо сказать спасибо команде ЦАРКА за их труд, ибо общение с владельцами ИС — это совершенно неблагодарное занятие.
Ситуацию усугубляет тот факт, что по некоторым ИС отчеты были отправлены еще в феврале, а устранены были единицы и даже МЦРИАП (Министерство цифрового развития и аэрокосмической промышленности) ничего не может с этим поделать.
Рутина
Иногда найти уязвимость бывает проще, чем эксплуатировать. Перехватить запрос из браузера, поменять пару символов в сертификате или подписи не трудно. Но почти всегда нужно подменять другие значения в сертификате: ИИН/БИН, ФИО, email и т.д. Модифицированный сертификат в NCALayer использовать нельзя, да и писать огромную инструкцию для PoC с использованием кучи утилит не вариант. Такой отчет будут проверять очень долго и не факт, что примут, поэтому для каждой ИС нужно было писать свой скрипт для подтверждения концепции.На большей части ИС проверялась подпись данных, но не сертификат, пришлось разбираться как подписать данные на Python в формате XML-Dsig, CMS и CAdES. Пришлось также разбираться как модифицировать сертификат, разбирать и собирать заново структуру ASN.1, что с моим уровнем владения Python было непросто.
Ситуацию осложняло и то, что разработчики в некоторых ИС радовали изобретательностью. В некоторых ИС от одного разработчика был общий бэкенд аутентификации, с несколькими запросами и редиректами на разные хосты, да и формат данных был везде разный. На одной из ИС вообще была обфускация отправляемых данных и самого JS-скрипта для их отправки!
В общем требовалось много времени на PoC для каждой ИС, а учитывая список из 40 штук (на тот момент) руки начали опускаться. Пока в голову не пришла отличная идея.
Fake Certification Authority Layer
Практически на всех найденных ИС (за некоторым исключением) вся работа с криптографией реализована на стороне NCALayer, именно для этого он и создан. А то, как данные передаются от фронтенда к бэкенду особого значения не имеет. Осталось сымитировать работу NCALayer, отправив браузеру модифицированный сертификат или подпись. Звучит просто.Для получения официального SDK, надо подписывать NDA и другие бумаги с НУЦ РК, что не выглядело разумной идеей. На официальном форуме (старом и новом), как и в репозитории на GitHub, информации по работе с NCALayer было мало. Буквально крохи информации.
Так что в ход пошли DevTools и Burp для анализ общения браузера и NCALayer. Еще очень помог ресурс с интерактивной документацией по KAZTOKEN mobile. Это не официальная документация, но очень близко кто тому-что было по факту.
Все общение сводилось к обмену сообщениями в формате JSON внутри WebSocket’a, и в обобщенном виде оно выглядело так:
Если не вдаваться в детали, то браузер сначала посылает запрос о статусе и получает в ответ готовность и версию, затем отправляет запрос на подписание данных.
В этом запросе указывается модуль для подписи, метод, сами данные для подписи и другие параметры. А в ответ получает цифровую подпись в запрошенном формате, либо сообщение об ошибке. Есть еще много нюансов, но они сейчас не важны.
Самих модулей и их методов много, но реализованы были лишь те, что попадались в проверяемых ИС.
Скрипт FCALayer.py получился довольно компактным, 1000+ строк, половина из которых комментарии. На данный момент в скрипте реализовано 17 методов в 4-х модулях и доступен следующий функционал:
- Имитация работы NCALayer через WebSocket;
- Подпись данных в различных форматах — XML‑Dsig/CMS/CAdES;
- Создание не валидного сертификата для физ и юр. лиц с нужными свойствами при запуске по шаблону:
- Сертификат физ. лица для аутентификации (AUTH_RSA256_*.p12);
- Сертификат физ. лица для подписи (RSA256_*.p12);
- Сертификат юр. лица для аутентификации (AUTH_RSA256_*.p12);
- Использование валидного сертификата и ключа из файла PKCS#12 (.p12);
- Установка задержки отправки подписи для проверки истечения токена аутентификации в ИС;
- Намеренная поломка цифровой подписи данных для проверки ее валидации на ИС.
Параметры запуска
Пример работы скрипта
В некоторых ИС для аутентификации требовался контейнер с ключами, а криптографические функции были реализованы на JavaScript. Некоторые ИС для аутентификации просто отправляли сертификат, без ЭЦП. В одной так и вовсе контейнер с ключами отправлялся на сервер, разумеется, перед этим спросив пользователя пароль от него (исправлено владельцем после отправки отчета).
А разработчики одной страховой компании совсем уж не стали заморачиваться со всей этой криптографией и решили отправлять только ИИН, открытым текстом без пароля и каких-либо проверок.
По этим причинам был создан еще один скрипт — make‑p12.py. Он просто генерирует сертификат с нужными свойствами и закрытый ключ, сохраняя все в контейнер PKCS#12.
Более подробную информацию можно найти в репозитории FCALayer (доступ быдет открыт позже).
Почему так случилось и что с этим делать
Я не разработчик и не эксперт в криптографии и могу лишь предполагать о причинах таких проблем с реализацией работы ЭЦП. Также позволю себе несколько общих рекомендаций.Почему так случилось:
- В ТЗ не указали проверку ЭЦП и сертификата, хотя это прямо прописано в правилах проверки подлинности ЭЦП и в руководстве для ИС НУЦ РК;
- Официальный SDK есть не для всех языков. Я видел много сообщений на форуме на эту тему. И вероятно в некоторых ИС работа с ЭЦП была реализована «на коленках»;
- Возможно, SDK позволяет получить поля сертификата без его валидации;
- Непонимание принципов инфраструктуры открытых ключей и ЭЦП у отдельных разработчиков.
- Использовать официальный SDK или проверенные и надежные библиотеки для криптографии;
- Делать все проверки согласно правилам проверки подлинности ЭЦП, так как это ответственность владельцев ИС;
- Повышать осведомленность разработчиков и людей принимающих решения об угрозах ИБ;
- Провести аудит ИС, работающих с ЭЦП используя FCALayer;
- Ну и сигнатурная защита, о ней чуть ниже.
Собственно, такая попытка была со стороны одного SOC, но небольшой фикс и отчет был успешно отправлен на платформу. В текущей реализации я убрал этот фикс, позже верну.
Кому и зачем все это нужно
Кому нужна эта статья? Всем нам. Все так боятся утечки персональных данных, но никого не волнуют проблемы безопасности, из-за которых эти утечки происходят.Кому нужен FCALayer? Для аудиторов и разработчиков. Некоторые владельцы ИС заявляли модераторам платформы, что исправили уязвимость и просили перепроверить несколько раз. Но ничего не менялось. То есть отдельным разработчикам не только сложно реализовать проверку подлинности, но и проверить ее работу.
Еще я уверен, что такой инструмент должны разрабатывать те же люди что и NCALayer. При проверке некоторых ИС мне приходилось добиваться одинакового ответа как в NCALayer, буквально посимвольно: соблюдать длину строки для BASE64, правильно выбирать управляющие символы для конца строки (\r\n), соблюдать регистр тегов XML и многое другое.
На этом все, спасибо, что дочитали!
Ссылки
- FCALayer
- XCA — Управление сертификатами и ключами
- ASN.1 Editor — Графический редактор Abstract Syntax Notation One (ASN.1) на основе.NET
- Правила проверки подлинности электронной цифровой подписи МИР РК
- ASN.1 простыми словами (часть 1, часть 2, часть 3) — статья на Хабр
- Интеграция ЭЦП НУЦ РК в информационные системы на базе веб технологий — статья на Хабр
- pkigovkz — аккаунт НУЦ РК на GitHub.com
- Интерактивная документация по KAZTOKEN mobile
P.S.
Небольшой дисклеймер:- Содержание статьи личное мнение автора;
- egov.kz и pki.gov.kz не подвержены уязвимости;
- Уязвимости найдены в реализации проверки ЭЦП в конкретных ИС, а не в NCALayer;
- Статья имеет образовательный характер, использовать приведенное ПО необходимо только с согласия владельца информационной системы.
Источник









