Шифрование по-индийски. Взламываем Tally ERP 9: аналог 1С из страны контрастов

Содержание статьи

Что такое Tally ERP 9

Несмотря на более чем сомнительное описание, Tally ERP 9 достаточно популярный в Индии продукт с более чем двумя миллионами пользователей. С учетом размера целевой аудитории, Tally — одно из самых популярных решений такого рода в Индии.

Неудивительно, что индийская полиция обратилась к разработчикам «Элкомсофт» с просьбой взломать защищенное хранилище Tally ERP 9. В таких случаях мы стараемся не просто взломать конкретную базу данных, а добавить поддержку соответствующего формата в один из наших продуктов. Именно по этому сценарию и начали развиваться события.

Каким образом обычно шифруют документы и внутренние базы данных? Как правило, компании действуют без огонька. В качестве алгоритма шифрования выбирают AES с ключом длиной 128, 192 или 256 бит. Ключ шифрования данных Media Encryption Key (MEK) создается одним из стандартных криптографически стойких алгоритмов генерации случайных чисел, после чего этот ключ шифруется ключом шифрования ключа шифрования Key Encryption Key (KEK). KEK, в свою очередь, генерируется на основе комбинации пароля пользователя и соли с помощью одной из стандартных хеш-функций (чаще всего это SHA-1, SHA-256 или SHA-512). Стойкость алгоритма усиливается увеличением числа итераций хеш-функции; нам попадались варианты от 10 тысяч итераций (это очень быстрый перебор) до миллиона (соответственно, перебор очень медленный) включительно. Если упростить до предела, для того чтобы добавить поддержку нового формата, нам нужно просто определить, каким именно алгоритмом хеширования воспользовался производитель, найти число итераций и место, куда сохраняется соль.

В случае с Tally ERP 9 все пошло не так.

Шифрование Tally Vault

В состав Tally ERP 9 входит реализация безопасного хранилища под названием Tally Vault. Шифрование в ERP 9 опциональное; пароль задавать совершенно не обязательно. Пароль хранилища можно задать как при создании компании, так и в любой момент после этого.

Когда пользователь задает пароль, система создает новое, защищенное хранилище. Старое, незащищенное, остается; впоследствии пользователь может его удалить. Для нас же эта схема чрезвычайно удобна: зашифрованную копию хранилища можно напрямую сравнить с незашифрованной.

Вот как выглядит выбор компании, если есть и зашифрованная, и незашифрованная версия данных.

Данные в последних версиях Tally ERP 9 по умолчанию сохраняются в c:\Users\Public\Tally.ERP9\Data\(1nnnn).

Зашифрованы будут все файлы с расширением .900, размер которых превышает 512 байт. Основной файл хранилища — Company.900. В этом файле сохраняется информация о пользователях, если включена опция Use security control. Вот как выглядит этот файл в hex-редакторе до шифрования.

А вот так — после.

Формат файла

Файл логически разбит на секторы/страницы по 512 байт. В начале каждой страницы записаны четыре байта контрольной суммы (CRC). При проверке блока на целостность вычисляется CRC остальных 512 – 4 байт и сравнивается с первыми четырьмя байтами.

Ключ шифрования

Ключ шифрования получается из пароля напрямую; никакой соли и тем более разделения на Media Encryption Key и Key Encryption Key здесь нет. Индийские разработчики решили не полагаться на существующие криптографические преобразования и создали свой собственный вариант, настоящий кошмар криптографа.

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

К примеру, вот так выглядят ключи шифрования на основе паролей, в которых попарно различается один символ:

Пароль Ключ
pwd1 0x653C68AC 0x4BA84BA8 (ac 68 3c 65 a8 4b a8 4b)
pwd2 0x653C69A7 0x4BA84BA8 (a7 69 3c 65 a8 4b a8 4b)
password1 0x74258DD3 0x57CE36D7 (d3 8d 25 74 d7 36 ce 57)
password2 0x90A78DD3 0xB34C36D7 (d3 8d a7 90 d7 36 4c b3)
password12345678 0xC6C57C3D 0xE52EC739 (3d 7c c5 c6 39 c7 2e e5)
password12345679 0xC6C51936 0xE52EA232 (36 19 c5 c6 32 a2 2e e5)
qwertyui123456789 0xD15D72DD 0x06309E8D (dd 72 5d d1 8d 9e 30 06)
qwertyuj123456789 0xD15D4D77 0x0630A127 (77 4d 5d d1 27 a1 30 06)

Алгоритм шифрования

Страницы шифруются алгоритмом, принцип работы которого сильно напоминает обычный DES. Для шифрования используется 64-битный ключ (который во время работы разворачивается в расширенный 128-битный, как и у настоящего DES). Шифрование блочное, размер блока — привычные для алгоритма DES 64 бита. Алгоритм используется в режиме CBC с первоначальной инициализацией IV нулями.

Напомню, DES (Data Encryption Standard) — алгоритм симметричного шифрования, утвержденный правительством США в 1977 году в качестве официального стандарта. В 2001-м от использования DES отказались; ему на смену пришел привычный нам алгоритм AES. Что заставило индийских разработчиков взять за основу принципы работы именно этого алгоритма — для нас загадка, но если ставку сделали на «никто не догадается», то они ошиблись.

Уже на этом месте можно прекратить исследование и реализовать простейшую атаку на ключ. На современном оборудовании все пространство ключей можно перебрать за считаные дни. При желании можно выполнить рефакторинг ключей; впрочем, принцип «неуловимого Джо» надежно защищает Tally от подобных атак.

Проверка пароля

В коде Tally Vault пароль проверяется так: расшифровывается страница (все 512 – 4 байт), вычисляется ее контрольная сумма (CRC) и сравнивается со значением, записанным в начале страницы. По замыслу разработчиков, для расшифровки всей страницы и полной проверки пароля потребуется расшифровать 64 блока по 8 байт (64 бита). Однако в данном случае дьявол кроется в деталях, и для проверки пароля вычислять контрольную сумму всей страницы совершенно не обязательно.

Вернемся к первому скриншоту.

В начале каждой страницы есть служебная информация, содержимое которой фиксировано или может быть известно заранее. Например, сразу после CRC, по смещению 4, находится 32-битная фиксированная последовательность DWORD 0x00000001. Назначение этой последовательности нам неизвестно; предположительно, это флаг страницы данных. Соответственно, чтобы ускорить проверку правильности пароля, можно прервать расшифровку страницы сразу после первого блока, если содержимое этих 32 бит данных не 0x00000001. Разумеется, 32 бита данных гарантированно дадут коллизии, которые потенциально приведут к ложным срабатываниям. Поэтому в случаях, когда значение расшифрованных очередным ключом 32 бит данных совпало со значением 0x00000001, мы расшифруем блок до конца, вычислим CRC и сравним контрольную сумму со значением, записанным в первых 4 байтах страницы. Однако количество таких коллизий будет порядка 1 к 4 миллиардам, что практически не влияет на скорость перебора паролей.

Кстати, если после прочтения этой статьи индийские разработчики изменят или вовсе уберут фиксированное значение по смещению 4, можно использовать и другие константы. Например, по смещению 12 записывается последовательный номер страницы, если страница не последняя.

Результат

Вооружившись знанием об использованных алгоритмах хеширования и шифрования, мы разработали две версии плагина для Elcomsoft Distributed Password Recovery. В первой версии плагина реализована «лобовая» атака, в которой правильность пароля проверяется именно так, как задумали индийские разработчики. Во второй для проверки используется константа в первом зашифрованном блоке. Как и ожидалось, разница в скорости впечатляет.

Сравнение скорости на двух CPU:

|Скорость (паролей в секунду)|При полной расшифровке страницы|При проверке константы в первом блоке (сейчас используется в EDPR)|
|Intel Core i7 6700|170 000|5 400 000|
|Intel Core i7 9700K|345 000|11 400 000|

11 миллионов паролей в секунду на одном процессоре, без использования GPU — много это или мало? Для сравнения: скорость атаки на CPU для документов в формате .docx, созданных в Microsoft Office 2016, составляет порядка 40 паролей в секунду, OpenOffice — 9000. Скорость атаки на контейнеры VeraCrypt — чуть больше одного пароля в секунду. Атака на резервные копии iTunes — примерно один пароль в десять секунд. Архивы RAR — порядка 64 паролей в секунду, 7zip — около 25.

Взлом

Для взлома паролей Tally Vault воспользуемся Elcomsoft Distributed Password Recovery с соответствующим плагином. Откроем файл Company.900.

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

Пароль обнаружился менее чем за секунду.

Усложнив задачу, запустили полный перебор, чтобы посмотреть скорость атаки, которая стабилизировалась на 11,1 миллиона паролей в секунду.

Как было бы правильно

Как можно было бы реализовать шифрование правильным образом? В данном случае достаточно было бы сделать «как все», а именно:

  1. В качестве алгоритма шифрования использовать стандартный AES с длиной ключа 256 бит.
  2. Для шифрования данных использовать ключ Media Encryption Key (MEK), созданный криптографически стойким генератором случайных чисел.
  3. MEK сохранять в зашифрованном виде. Шифровать при помощи ключа Key Encryption Key (KEK).
  4. Key Encryption Key вычислять посредством одной из готовых KDF (Key Derivation Function), использующих многочисленные (порядка сотен тысяч) итерации хеш-функции SHA-256 или SHA-512 на основе пароля пользователя и соли.

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

Заключение

Tally ERP 9 полностью оправдал заявку маркетологов «создано для наслаждения». Мы получили редкое удовольствие, создавая атаку на данные Tally Vault, словно вернувшись на двадцать лет назад во времена слабой, зарегулированной экспортными ограничениями защиты.

Что же касается самого Tally Vault, то разработчики совершили все возможные и невозможные ошибки. Мы не смогли найти ни одного аспекта защиты, который был бы реализован на уровне хотя бы школьника-энтузиаста. Беспросветно плохо здесь абсолютно все. Здесь и прямое преобразование пароля в ключ шифрования, и пренебрежение солью, и единственная итерация доморощенного (и абсолютно безграмотно реализованного) хеширования. Использование алгоритма на основе DES более чем сорокалетней давности в комбинации с коротким ключом шифрования делают возможной атаку на ключ (а не на пароль), и только отсутствие спроса защищает продукт от полного рефакторинга. Исправить эти алгоритмы принципиально невозможно, можно лишь сделать заново.

Впрочем, здесь тот случай, когда и «сделать заново», вероятно, не поможет. Фиксированные данные, находящиеся в самом начале страницы данных, позволяют ограничиться расшифровкой единственного 64-битного блока, что более чем в 30 раз ускоряет проверку. Нам же остается порадоваться очередному достижению: более 11 миллионов паролей в секунду на единственном CPU, без использования даже аппаратного ускорения — наш абсолютный рекорд за все время работы.

Читать новость в источнике Xakep

0