Pull to refresh

Уязвимость в MACROSCOP (устранена с версии 1.9.72)

Reading time8 min
Views12K
Я давно увлекаюсь информационной безопасностью, но одно дело – понимание поверхностной логики работы программного обеспечения, и совершенно другое – понимание логики его внутренней реализации. Внешне любая программа может выглядеть замечательно и гармонично, создавая иллюзию полной безопасности и защищённости, но стоит углубиться, копнуть глубже, и на поверхности окажутся нелицеприятные факты, которые могут привести к взлому системы и, в конечном счёте, к утечке или потере данных, а также временным и финансовым потерям. Причиной наличия уязвимости в приложении может быть как банальная невнимательность, катастрофическая нехватка времени, алгоритмическая или архитектурная сложность, незнание особенностей работы или реализации стороннего API, так и корыстный умысел. Зачастую сложно судить о том, что конкретно могло послужить причиной возникновения той либо иной уязвимости, но более важным моментом является скорость реакции разработчиков по её устранению.

Сегодня же пойдёт речь об уязвимости, обнаруженной мной в процессе знакомства с программным комплексом для IP-камер MACROSCOP от резидента технопарка «Сколково» компании ООО «Сателлит» (г. Пермь). MACROSCOP является именно программным комплексом, так как в состав решения входит целый ряд приложений: серверная и «всё в одном» часть для операционных систем семейства Microsoft Windows (от развития Linux решения разработчики недавно отказались), клиентская часть для Windows, Android, iOS и Windows Phone, конфигуратор, программа подключения Web-камер, проигрыватель файлов собственного формата, программа локального просмотра и резервного копирования архива, программа мониторинга состояния системы, различные интеллектуальные модули, а также приложения для интеграции с некоторыми сторонними системами и широкие возможности по интеграции с любым программным обеспечением посредством SDK. В MACROSCOP много плюсов и, тем не менее, он не лишён недостатков, чему можно посвятить отдельную статью: ведь не всегда разработчики афишируют отрицательные стороны своего продукта.

Обнаруженная уязвимость заключается в использовании слабого имени пользователя и пароля для недокументированной учётной записи superuser, а также в возможности выполнения некоторых запросов к серверу с использованием этой записи. При тестировании MACROSCOP возникла необходимость проверить насколько надёжно хранятся учётные записи для камер и самой программы, и моё внимание в итоге привлёк конфигурационный файл «Current.CmnConf». Как оказалось, пароли к камерам хранятся в открытом виде, а пароли для учётных записей программы – в виде md5 хэша, а также, скорее всего, в обратимо-зашифрованном виде. При изучении конфигурационного файла я наткнулся на строки SuperUser и SuperPass, а также две подряд идущие строки, отдалённо напоминающие хэш. Попытка использования данной пары для авторизации при помощи клиентского приложения и конфигуратора не принесла должного результата, но меня не покидала мысль, что это для чего-то нужно и где-то должно работать. В пользовательской документации не было ни слова о данной учётной записи, поэтому я решил изучить документацию по использованию MACROSCOP SDK для разработки внешних модулей, где также не нашёл никакой информации, но меня заинтересовало описание использования HTTP-интерфейса для получения потоков данных из программы. Каково же было моё удивление, когда я попытался проверить использование данной пары для запроса вида:

server:8080/video?channel="Улица"&login=superuser&password=superpass

Проверка данного запроса оправдала мои ожидания: браузер предложил сохранить данные по указанной ссылке, а это ни что иное как видеопоток в режиме реального времени с канала под именем «Улица». Следующим по порядку у меня возник вопрос о том, как заполучить названия всех каналов видеосистемы. На этот вопрос дают ответ сами разработчики в своём SDK, где для получения названий каналов, их идентификаторов и настроек в MACROSCOP необходимо выполнить следующий запрос:

server:8080/configex?login=superuser&password=superpass

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

Я решил до конца разобраться каким образом формируется эта самая учётная запись. Так как программы и библиотеки MACROSCOP в большинстве своём написаны под программную платформу .NET, то для их исследования мне пришлось воспользоваться программой .NET Reflector. Поиск по ключевым словам не заставил долго ждать, и интересующий меня код был найден в библиотеке Common.dll в реализации класса CommonConfig:

Random random = new Random();
byte[] buffer = new byte[21];
byte[] buffer2 = new byte[21];
random.NextBytes(buffer);
random.NextBytes(buffer2);
this.SuperUser = SDKCommon.MD5Hash(Encoding.UTF8.GetString(buffer));
this.SuperPass = SDKCommon.MD5Hash(Encoding.UTF8.GetString(buffer2));

В MACROSCOP этот код используется при применении первой конфигурации, тогда создаётся учётная запись superuser, которая недоступна из настроек программы, обладает определёнными привилегиями и всегда остаётся неизменной. Из кода видно, что происходит инициализация экземпляра класса Random, затем получение двух массивов произвольных данных определённой длины, далее получение из них строк и в конечном счёте md5 хэша. Вроде бы никакого подвоха: использование произвольной последовательности данных и необратимые преобразования, но не было бы тогда уязвимости и этой статьи, если бы не использование класса Random, в сути которого и кроется вся проблема.

Первопричина уязвимости в MACROSCOP заключается именно в использовании стандартного класса Random среды .NET, что приводит к генерации учётной записи, которая может быть подобрана за разумное время. Дело в том, что этот класс для инициализации массива псевдослучайных чисел использует получаемое вызовом системной функции GetTickCount 32-разядное значение: количество миллисекунд, прошедшее с момента включения компьютера. Таким образом, на основании этого числа формируется пара имени пользователя и пароля. Эта пара может быть выявлена перебором всех возможных значений времени, прошедшего с момента включения компьютера до применения первой конфигурации. Проблема также усугубляется тем, что с момента включения компьютера до применения первой конфигурации в большинстве случаев может пройти очень мало времени. Например, если первая конфигурация была применена через час после включения компьютера, то потребуется проверить всего лишь 3,6 млн комбинаций (1 ч * 60 мин * 60 с * 1000 мс). Даже если компьютер был включён очень давно, то и это не сильно усложнит атаку перебором, т.к. класс Random использует для инициализации значение модуля 32-битного числа со знаком, то количество входных значений в итоге ограничивается 31-битным числом. Таким образом, максимальное количество комбинаций для перебора составляет 2^31 (2147483648) значений, что по времени с момента включения компьютера до применения первой конфигурации составляет около 25 суток, после чего отсчёт времени начинается с начала. Перебор осуществляется и с использованием ранее указанного запроса на получение названий каналов, их идентификаторов и настроек. В идеальных условиях (исходящая скорость канала сервера не менее 50 Мбит/с, многоядерный процессор, низкая нагрузка на процессор) скорость перебора может достигать порядка 5000 учётных записей в секунду. Значит, если первая конфигурация была применена через час после включения компьютера, то время перебора учётной записи составит не более 12 минут. Также возможно уменьшение времени перебора при учёте предполагаемого времени включения компьютера в рабочие часы, например, если компьютер мог быть включён в рабочие дни и часы, то время перебора можно сократить в 3,7 раза.

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

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

Разработчики были уведомлены об уязвимости в MACROSCOP, а через 2 недели (12 марта 2014 г.) они её закрыли выпуском версии программы 1.9.72. Теперь код генерации встроенной учётной записи выглядит следующим образом:

byte[] data = new byte[21];
byte[] buffer2 = new byte[21];
try
{
	RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider();
	provider.GetBytes(data);
	provider.GetBytes(buffer2);
}
catch (Exception exception)
{
	b1x.a(exception, "dsfimdfsmsdfdkfskfds");
	Random random = new Random(Guid.NewGuid().GetHashCode());
	random.NextBytes(data);
	random.NextBytes(buffer2);
}
Buffer.BlockCopy(Guid.NewGuid().ToByteArray(), 0, data, 0, 8);
Buffer.BlockCopy(Guid.NewGuid().ToByteArray(), 0, buffer2, 0, 8);
this.SuperUser = SDKCommon.MD5Hash(Encoding.UTF8.GetString(data));
this.SuperPass = SDKCommon.MD5Hash(Encoding.UTF8.GetString(buffer2));

В новой редакции кода используется криптостойкий класс генерации случайных данных вперемешку с Guid, что гарантирует практическую невозможность подбора учётной записи, к тому же разработчиками была закрыта возможность использования данной учётной записи в двух ранее указанных запросах к серверу. Тем не менее по-прежнему эта учётная запись используется при применении конфигурации, но скорость перебора в данном случае гораздо меньше: минимальный запрос к серверу составляет порядка 10 Кб, что в 10 раз больше по трафику ранее возможного способа, а подверженными риску с обновлением остаются только старые пользователи. Дело в том, что для существующей конфигурации пара хэшей не модифицируется при установке новой версии программы, так что эту процедуру остаётся проделать только самостоятельно. Самое главное, если используется многосерверная конфигурация, то пара хэшей и соответственно сама конфигурация должны совпадать на всех серверах. Иначе возникнет конфликт при применении новой конфигурации. Таким образом, для новоиспечённых пользователей MACROSCOP, кто только начинает пользоваться программой, с версии 1.9.72 уязвимость нестрашна, а вот для старых пользователей существует небольшой риск, который может быть устранён следующим образом:

– останавливаем службу MacroscopServer или завершаем работу standalone версии на компьютере;
– открываем в 16-ричном редакторе файл конфигурации «Current.CmnConf», расположенный в папке программы (предварительно лучше сделать резервную копию файла);
– находим в файле строку «Alarus.Config.SystemEditions», а именно второй результат вхождения;
– сразу чуть ниже результата поиска будут находиться две строки длиной в 32 символа – это и есть данные встроенной учётной записи;
– меняем на произвольные значения содержимое строк с учётом допустимых символов из набора «0123456789ABCDEF», не изменяя при этом длину строк;
– сохраняем конфигурацию;
– запускаем службу или standalone версию программы;
– в случае использования многосерверной конфигурации выполняем те же действия, только в качестве строк используем ранее отредактированные значения или просто заменяем конфигурацию на исправленную.

Подводя итоги, не могу не пожелать всем разработчикам не повторять ошибок с использованием стандартного класса Random, а использовать криптостойкие реализации алгоритма генерации случайных данных, и также оперативно реагировать на потенциальные угрозы в приложениях.
Tags:
Hubs:
Total votes 24: ↑22 and ↓2+20
Comments4

Articles