Идеи о механизме защиты в Windows на основе самоограничения

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

    А как было бы хорошо, если бы программа сама знала какие действия ей не нужны и на всякий случай отключала их.



    Антивирусы и прочие подобные системы пытаются брать на себя роль защитников, но вся защита сводится к набору правил, которые для многих одинаковы и не учитывают специфики защищаемых программ. Такой подход иногда приводит к неприятных ситуациям. Вот несколько примеров:
    • Внедренный вредоносный код в браузер — получает беспрепятственный доступ к сетевым функциям.
    • Внедренный вредоносный код в почтовую программу — беспрепятственно получит доступ к файлам почтовой базы, несмотря на то, что антивирус будет защищать эти файлы.
    • Эксплуатация уязвимости в сетевых программах — иногда позволяет получить доступ к системе или повышение прав, несмотря на то, что пользователь может иметь минимальные права.


    Но как уже выше говорилось — автор программы лучше всего знает, что должна делать его программа. Так почему ему не дать возможности самому поставить ограничения на определенные действия? Причем не для всей программы, а для конкретных потоков.

    Продуктивность идеи

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


    Если говорить с более реалистичной точки, то можно было бы:
    • Браузер сам себе мог бы запретить запускать сторонние программы.
    • Почтовая программа могла бы иметь доступ к файлам базы, а внедренный в ней код — нет.
    • Любая программа смогла бы узнать о своей аномальной активности.


    Особенности реализации и использования идеи

    Для реализации идеи необходимо в ядре Windows:
    • Сделать правки в двух системных структурах.
    • Добавить один системный вызов.
    • Написать кода на 50-100 строк.


    В kernel32.dll добавить одну функцию управляющую защитой. Которая тоже не будет особо большой.

    Данные действия под силу любому программисту (причем за один день). Но самая большая трудность в том, что Microsoft сама должна это сделать. Именно по этому такой механизм защиты остаётся пока в мечтах.

    Теоретическое отступление

    Так как любые ограничения в пользовательском режиме (user mode) легко обходятся или снимаются, то необходимо всю защиту реализовывать в ядре.

    Основной принцип вызова системных функций в Windows можно представить в виде следующей схемы:



    После вызова sysenter / syscall / int 0x2E или call dword ptr fs:[0xC0] (в зависимости от версии windows) далее управление попадет в ядро, где функция KiSystemService просматривает таблицу адресов системных сервисов (SDT) и по номеру сервиса (передаваемого в регистре eax) находит адрес нужной функции и далее передаёт на неё управление. Таким образом происходит вызов нужной функции.

    В системе используется два таблицы — одна отвечает непосредственно за работу систему и обрабатывается ядром, а вторая отвечает за работу GUI и обрабатывается драйвером win32.sys. Нас интересует именно первая таблица.

    Благодаря такой архитектуре возможно поставить ограничение доступа на вызов любой системной функции. Для этого достаточно вставить простую проверку в функцию KiSystemService.

    Место проверки мы уже обнаружили, теперь необходимо найти философский камень место под хранение матрицы доступа.

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

    Всё бы то хорошо, но есть еще и сеть, работа с которой организована через специальные драйвера. Но и тут проблема решается в обработке некоторых IRP запросов к устройствам \\Device\Tcp, \\Device\Udp, \\Device\Raw что позволит также прозрачно проверять возможность доступа к сети из определенных потоков.

    Как будем реализовывать защиту

    Реализация защиты видится следующим образом:
    • В структуре описания каждого потока есть таблица запретов состоящая из битов. В Windows 7 в SDT находится 360 функций, по этому массива на 512 бит(64 байта) хватит выше крыши.
    • По умолчанию все биты сброшены (т.е. запретов нет)
    • Также есть 64 битное поле ключа, о котором речь пойдет чуть позже.
    • Также есть 32/64 битное поле хранящее адрес callback функции
    • Итого имеем данных на 76/80 байта
    • В ядро добавлен еще один системный вызов, который заполняет структуру по следующим правилам:
      • Биты можно устанавливать всегда.
      • Сбрасывать биты можно только указав спец ключ защиты.
      • Спец ключ можно получить только один раз.
      • Callback функцию можно установить только один раз или неограниченное кол-во, используя ключ.

    • В kernel32.dll и ntdll.dll добавлена интерфейсная функция к системному вызову организующего управление защитой.


    Ход работы защиты:
    • В KiSystemService или обработчике IRP запросов сетевого драйвера получаем указатель на структуру PTHREAD
    • Проверяем границы индекса (в случае с номером в SDT)
    • Проверяем установлен бит или нет. Если установлен то вернуть STATUS_ACCESS_DENIED
    • Если установлен бит и указана callback функция, то вызвать её. Тем самым уведомив процесс о том, что какой-либо поток попытался выполнить запрещенные действия.


    Отдельное внимание хотелось бы уделить функции установки защиты. Ей прототип видится как:
    DWORD QuerySystemSecurity(HANDLE hThread, DWORD Flag, QWORD* Key, VOID* Data);
    • hThread — дескриптор потока для которого устанавливается защита. Или 0xFFFFFFFF в случае текущего потока.
    • Flag — параметры передаваемые или запрашиваемые:
      • Получить ключ.
      • Установить запрет на функцию.
      • Установить запрет на список функций.
      • Установить запрет на группу функций. — к примеру работа с файлами или с процессами.
      • Установить callback функцию.
      • Снять запрет на функцию.
      • Наследовать таблицу защиты или нет.
      • Запретить снимать защиту даже если задан ключ.
      • Запретить получение ключа.
    • Key — адрес ключа или NULL.
    • Data — данные в зависимости от Flag.


    Так же в QuerySystemSecurity должна находиться таблица соответствия номеру запрещаемой функции и её номеру из SDT т.к. последний меняется от версии к версии.

    Заключение

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

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

    Но как всегда это лишь собственные мечты о существовании защиты, которые вряд ли будут воплощены Microsoft.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 12

      +5
      Вы придумали apparmor для windows?
        0
        Скорее seccomp with filters.
          0
          Можно сказать что apparmor, но в отличии от него безопасностью заведует само приложение и это вкладывается в него еще на стадии разработки.
          0
          Вы придумали CAS :-)
            0
            CAS для .net действует, а тут глобально для всех Windows UserMode приложений с ограничением не по коду, а по отдельным потокам.
            0
            Вот я придумывал похожее: habrahabr.ru/post/89588/
              +1
              Нет, если Вы хотите решить все проблемы сразу не особо задумываясь о дизайне, то Вам в Линукс. Правда потом придется эти опять решать эти же проблемы. Все и сразу.

              Restricted token-ы появились в винде почти 15 лет назад. Есть статьи о сендбоксинге в винде от самих разработчиков MS, которым уже 5 лет.

              Давайте теперь на секундочку остановимся и помоделируем угрозы. Прежде всего Вы предлагаете хранить настройки в KTHREAD-е, то есть сделать так чтобы разные потоки в одном адресном пространстве имели разный уровень доверия? Уже одного этого достаточно, чтобы отмести всю идею целиком, как не заслуживающую внимания (да-да, в Линуксе именно так и сделано). Impersonation token-ы, которые хранятся для каждого потока предназначены не для ограничения недоверенного кода, а как раз таки для того, чтобы исполнять ДОВЕРЕННЫЙ код с правами клиента.

              Далее, для всех «родных» NT-шных объектов (те, которые в \ObjectTypes) — restricted token-ов более чем достаточно. Более того, они одновременно обеспечивают и большую гибкость и лучшую целостность решения, по сравнению с тем, что предлагаете Вы. Что же до «тяжкого наследия» — USER/GDI объектов, то здесь все довольно печально. Вряд ли можно сделать что либо реально безопаснее (а не просто дающее ложное чувство безопасности), чем существующий UIPI в пределах одной сессии (разные сессии и так отлично изолированы друг от друга) без довольно кардинального «перепиливания» кучи подсистем. Любой «поток», которому Вы разрешите NtGdiBitBlt сотоварищи сможет читать информацию из любого окна в приложении. Не стоит этим пренебрегать: подумайте о переписке в чате/почте, секретных вопросах от банкинга и прочих онлайн аккаунтов и т.п. — ведь мы же хотим РЕШИТЬ вопрос, а не просто сделать вид, что мы типа теперь «стали более лучше» обеспечивать сохранность данных, да?

              Хорошие новости: насколько я знаю каждый AppContainer в Win8 имеют собственный набор USER/GDI объектов и таким образом они полностью изолированы друг от друга и от остальной системы. Все Metro приложения (включая Metro IE), а также десктопный IE со включенным Enhanced Protected Mode используют AppContainer-ы для изоляции кода с разным уровнем доверия. Подготовительная работа как ни странно была сделана еще в Висте: композитинг это не только стекляшки и анимашки, это еще и «виртуализация» (перенаправление) GDI ресурсов, а раз они уже виртуализованы, то им можно перестать быть глобальными в пределах десктопа.
                0
                Можно глупый вопрос? А с отключенным DWM вся эта виртуализация GDI ресурсов остается? Вроде как Mirror Video Display Driver как раз нечто такое делает при активации и получает всю картинку.
                  +1
                  Ну, вопрос не такой уж глупый на самом деле. GDI redirection включается только если включен DWM. Более того, сам DWM его явно и включает вызовом DwmStartRedirection. На безопасность это мало влияет, потому что хоть GDI и редиректится, но все объекты все так же доступны всем процессам (кроме случаев, когда «гайки подтянуты» с помощью JOBOBJECT_BASIC_UI_RESTRICTIONS, но надо полагать с этими ограничениями есть проблемы совместимости, потому что сам MS не использует их в Protected Mode IE песочницах). Mirror Driver-ы несовместимы с WDDM и сразу выбивают Windows в Basic Mode (с отключением композитинга и перенаправления). Только что проверил, Basic Mode в Win8 использует композитинг — просто рисует все «классически».

                  Ну а в Win8 была введена новая модель для приложений — они изначально изолированы от всех остальных и могут общаться только через ограниченный (и полностью контроллируемый системой) набор контрактов — и MS с радостью решили все проблемы безопасности, вызванные требованием обратной совместимости. Повторюсь, в новой модели работают только Metro приложения (ну по-крайней мере большинство из них) и песочницы десктопного IE в режиме EPM. Об AppContainer-ах пока известно довольно мало, так что расспрашивать меня о подробностях бесполезно.

                  В общем резюмируя, хочется самоограничений? На Win7 и ниже следует использовать job object-ы, restricted token-ы (может быть одним из ограничений job object-а), low integrity (MIC) и (опционально) отдельный десктоп/сессию. На Win8 и выше можно использовать все то же самое, но лучше воспользоваться инфраструктурой AppContainer-ов
                    0
                    Basic Mode в Win8 использует композитинг — просто рисует все «классически».

                    Всё верно, это уже не тот базовый режим как в сапоге или висле, механизм реализован благодаря WDDM 1.2, и как я понимаю, DWM в бесконечности не отключаем в принципе. Поддержка же XPDM драйверов в Win8 полностью отсутствует. В итоге это даёт множество плюшек, как с точки зрения изоляции процессов, что ведёт к повышению безопасности, ну и даёт приличное ускорение в работе в сравнении с семёркой, да и с точки зрения производительности вообще сплошные плюсы, ведь весь интерфейс ускоряется видео-картой даже в базовом режиме.
                0
                Автор, а не будут ли обламываться дрова, которые работают в ап юзермодного процесса (device drivers, к примеру) — ведь tib останется прежним, а при таких проверках может возникнуть ситуация, когда дров не сможет вызвать какую-нибудь функцию. Если ошибаюсь, исправьте.
                  0
                  Всё будет ок — в fs другое значение загружается.

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое