Автор: @abbradar
Сервис предоставляет услуги по хранению и выводу пенсионных накоплений пользователей, и ориентирован на пенсионеров комической отрасли. Были реализованы операции ввода и вывода средств. Из-за нехватки сотрудников в организации ввод средств также был возложен на пользователей. Как итог, сервис представляет из себя хранилище ценных персональных и финансовых данных пользователей.
Поскольку работа с финансовыми операциями — ответственная задача, ядро сервиса было реализовано на ответственном и проверенном языке программирования Кобол. К сожалению, из-за высокой степени ответственности Веб-технологии в Коболе недостаточно хорошо поддерживаются. Веб-интерфейс для пользователей был реализован на Python, который взаимодействовал с ядром сервиса через т.н. кекстовые файлы.
Сервис использует встроенный в Кобол функционал работы с простыми базами данных: в языке можно задавать формат хранения данных в файле, называемый организацией (ORGANIZATION
). Формат хранения ORGANIZATION INDEXED
реализует хранение записей с доступом по ключу-одному из полей записи (RECORD KEY
), и возможностью задавать дополнительные индексы (ALTERNATE KEY
). Различные приложения на Коболе, реализующие разные запросы пользователей, работают с несколькими такими общими файлами.
Подробности запроса передаются каждому приложению через файл с фиксированным названием INPUT.TXT
и типом LINE SEQUENTIAL
. Такой файл состоит из нескольких строк, каждая из которых — запись с полями фиксированной длины.
Результаты работы представляются в форме отчётов, сформированных встроенными средствами языка Кобол, которые выводятся на экран для удобного восприятия пользователем.
Печать поля в отчётах выполняется инструкцией GENERATE
. Можно заметить, что в программе SHOW-PAYCHECKS.COB
, выводящей все сохранённые чеки пенсионера, инструкция GENERATE
используется два раза, и один раз — до проверки пароля:
READ PAYCHECKS RECORD KEY IS RETIREE-ID OF PAYCHECK
NOT INVALID KEY GENERATE REPORT-LINE
END-READ.
...
IF PASSCODE-VALID NOT = PASSCODE-ATTEMPT
EXIT PARAGRAPH
END-IF.
...
PERFORM FOREVER
READ PAYCHECKS PREVIOUS
...
GENERATE REPORT-LINE
END-PERFORM.
В момент поиска записи (инструкция READ ... RECORD KEY IS
) курсор чтения устанавливается на первую найденную запись в файле, удовлетворяющую условию. Таким образом, даже не зная правильный пароль, можно вывести содержимое первой записи в таблице. К счастью, запись в файл была устроена таким образом, что последняя введённая запись всегда была первой в выдаче. Соответственно, регулярно опрашивая сервис, можно было извлекать флаги по одному по мере их загрузки.
Достаточно поменять местами два блока инструкций: блок проверки пароля и блок поиска чеков.
В программе CHANGE-PASSCODE.COB
, как и в других, перед сменой пароля выполняется проверка текущего пароля, согласно всем требованиям безопасности. В нашем сервисе пароль представляет из себя числовой код. Перед сравнением введённый и реальный пароли копируются в локальные переменные PASSCODE-VALID
и PASSCODE-ATTEMPT
. Сравнивая разные программы, можно было заметить разницу в определении этих переменных:
WORKING-STORAGE SECTION.
01 PASSCODE-VALID PIC 9(16).
01 PASSCODE-ATTEMPT PIC 9(16).
SHOW-PAYCHECKS.COB
WORKING-STORAGE SECTION.
01 PASSCODE-VALID PIC 9.
01 PASSCODE-ATTEMPT PIC 9.
CHANGE-PASSCODE.COB
В языке Кобол PIC
обозначает формат данных в памяти. Символ 9
обозначает "десятичная цифра", а число в скобках после него — количество повторений. Таким образом, 9(16)
обозначает "16 десятичных цифр" (неиспользуемые разряды заполняются нулями автоматически), а просто 9
— одна десятичная цифра.
В момент копирования старшие разряды отбрасываются. Таким образом, зная только последнюю цифру кодового числа, возможно сменить пароль на собственный и получить доступ к сохранённым чекам. Эта цифра достаточно легко подбирается.
Заменить формат данных на верный из другого файла будет достаточно для исправления уязвимости.