РИТ++ 2017, секция ML + IoT + ИБ
Зал Белу-Оризонти, 5 июня, 15:00
Тезисы:
http://ritfest.ru/2017/abstracts/2765.html
Современные языки, библиотеки, фреймворки становятся все умнее и умнее, упрощая жизнь разработчика и автоматизируя различные процессы. Но у этого есть и обратная сторона в том, что происходящие внутри процессы не всегда ясны и понятны, и незнание какой-то специфики использования может приводить к различным проблемам в безопасности, вплоть до полной компрометации системы. Как раз такие ситуации и будут отражены в данном докладе, на примере нескольких языков и различных видов сериализации.
Теория. Прочитать.
Сериализация - это процесс сохранения состояния объекта в последовательность байт.
Десериализация - это процесс восстановления объекта, из этих байт. Обратный процесс сериализация(!)
Сериализация объекта это способность объекта сохранять полную копию его и любых других объектов на которые он ссылается, используя поток вывода(например, во внешний файл). Таким образом, объект может быть воссоздан из сериализованной(сохраненной) копии немного позже, когда это потребуется.
В сегодняшнем мире типичное промышленное приложение будет иметь множество компонентов и будет распространено через различные системы и сети. Если двум компонентам Java необходимо общаться друг с другом, то им необходим механизм для обмена данными. Есть несколько способов реализовать этот механизм. Первый способ это разработать собственный протокол и передать объект. В Java всё представлено в виде объектов; Это означает, что получатель должен знать протокол, используемый отправителем для воссоздания объекта, что усложняет разработку сторонних компонентов. Следовательно, должен быть универсальный и эффективный протокол передачи объектов между компонентами. Сериализация создана для этого, и компоненты Java используют этот протокол для передачи объектов.
Процесс десиреализации начинается с момента когда объект считывается с ObjectInputStream, в который поступает данные, которые пришли от атакующего. Процесс начинает считывать сериализоанные данные и начинает цикличный процесс, в котором имя класса, который будет десиарилизован передается в метод ObjectInputStream.resolveClass(). Это необходимо для того, чтобы получить информацию и метаданные о классе. Это важный этап, поскольку на нем проверяется, что существует данный класс в classpath или нет. Стоит отметить, что уже на этом этапе, можно проверять класс, который будет сериализован с точки зрения безопасносити и можно еще все остановить.
После того, как класс загружен ObjectInputStream, проверяет, содержит-ли он такие функции как readObject() и/или readResolve – если да, то вызывает их. readObject служит для того , чтобы устновить значения полей класса. В некоторых случаях могут вызываться и другие функции, такие как validateObject и другие.
Этот процесс будет повторяться до самого конца, когда сам объект и все вложенные в него объекты не будут полностью десеарилизованны.
Важно отметить, что перед тем , как быть скастованным до определенного объекта, некоторые методы будут вызваны, такие как readObject, readObjectNoData, readResolve и validateObject у десиарилизрованного класса. То есть если атакующий, сможешь каким-либо образом проэксплуатировать эти функции, то он сможет получить возможность выполнения произврольного кода.
Иными словами, те действия, которые будут произходить в этим функциях с данными атакующего и крайне важны
Пытаясь найти необходимые функции и классы, атакующий может быть не только ограничен данным методами. Он может использовать перехват вызовов, и с одной стороны метод readobject может передать управление на c.
JDK и другие библиотеки, позволяет разработчикам писать проки классы , которые реализуют или расширяют определенный набор классов или интерфейсов. Любой метод который вызывается в этих проксях перехватывается и передается в invocation handler для выполнения дополнительного кода.
И класс invocation handler. Как видно, если бы мы попытались его сериализовать стырм путем, то него нет методов и необходимы параметоров, которые можно было бы перезаписать
Сначала атакующий создает экземпляр класса Handler0
Создает прокси на объект map, где в качестве F pfntv