Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: аутентификация приложения  (Прочитано 8776 раз)
0 Пользователей и 2 Гостей смотрят эту тему.
Storage Device
Гость
« : 02-12-2005 09:03 » 

Есть драйвер в котором реализовано несколько значимых функций доступа к данным. Функции предоставляются посредством вызова DeviceIoControl с указанием номера требуемой функции. Необходимо ограничить использование этих функций, чтобы только доверенные приложения могли ими пользоваться. Аутентификационными данными могут служить лишь код приложения, обратившегося к драйверу (а точнее его контрольная сумма).
Есть два варинта:

1. контроль в памяти. Драйвер вычисляет контрольные суммы заголовка PE и секций кода. Например, ставится обработчик на IRP_MJ_CREATE. А дальше надо как-то узнать, кто послал это IRP. Например PsGetCurrentProcessId() Но это только ID, а надо получить его базу в памяти (IMAGE_BASE). Можно, конечно, и сразу читать по 0х400000, поставив обработчик исключения. в общем хочется услышать ваши рекомендации...

2. контроль на диске. Все как и в предыдущем варианте, только необходимо получить не базу модуля в памяти, а полный путь к исполняемому файлу. Путь именно к тому файлу, который обратился к драйверу. В WIN32 я бы использовал  GetModuleFileName. А дальше открыть этот файл, читать, закрыть... Только вот я такого еще не делал, поэтому первый вариант для меня предпочтительней.

Напишите plz, свои соображения по этому поводу.
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 02-12-2005 09:42 » new

инетерсно... а вот SECURITY_ATTRIBUTES поиграться как-нибудь неполучится? или это вообще не о том....

по идее, можно попробовать через стек посмотреть - кто вызывает... получить адрес стека, там eip вызывающего процеса вытащить и считать уже CRC на +/-сколькото  от eip. вариант наверное... 
но что то мне в таком варианте напрягает...
PS
да... глянь в обсуждении "Доступ к User mode памяти"  мож поможет?
« Последнее редактирование: 02-12-2005 10:16 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 02-12-2005 11:33 » 

Может быть, ввести нормальный протокол аутентификации через цифровую подпись?
Например, в каждый блок пользовательских данных, передаваемых через DeviceIoControl, ввести два поля: номер запроса и поле цифровой подписи?

Идея заключается в следующем.  Пусть в незащищённом режиме пользовательские данные передаются структурой struct UserData.  Тогда защиту можно ввести так:
Код:
struct AuthenticatedData {
    unsigned long messageLength;
    unsigned long sessionId;              // идентификатор сессии, создаётся при предварительном установлении соединения
    unsigned long sequenceNumber;  // номер сообщения в последовательности
    struct UserData data;
    struct Signature signature;
};
Поле messageLength задаёт полную длину данных вместе с цифровой подписью и служебными полями.  Поле sequenceNumber необходимо для того, чтобы защититься от атаки "воспроизведение перехваченных сообщений" (replay attack), в которой противник перехватывает сообщение и затем посылает его, чтобы заставить драйвер выполнить команду, которая как-будто исходит от правильного приложения.  Пример использования такой атаки см. на этом форуме в топике про отключение файервола https://forum.shelek.ru/index.php/topic,7737.0 .  После каждого вызова DeviceIoControl приложение увеличивает номер, а драйвер отбрасывает все сообщения, номер которых не больше номера последнего полученного сообщения.  То есть каждое сообщение обрабатывается не более одного раза, и перехват команд не поможет противнику. 
Цифровая подпись необходима для того, чтобы обеспечить целостность сообщения -- если противник изменит хотя бы один бит в данных или номере последовательнсти, то цифровая подпись не сойдётся.  В частности, это поможет защититься от увеличения номера в перехваченном сообщении. Сообщения с неверной подписью драйвер должен отбрасывать (не обрабатывать) и, возможно, помещать сообщение в лог о попытке подделать сообщение.

Ответы драйвера необходимо защищать аналогичным образом, чтобы быть уверенным, что противник не подделывает данные от драйвера.

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

Для цифровой подписи есть много надёжных алгоритмов с известной и проверенной реализацией, например HMAC-MD5, HMAC-SHA1, HMAC-SHA2.

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

На фазе генерации ключа приложение предъявляет аутентифицирующие данные, например сертификат.  Предполагается, что сертификатом может пользоваться только приложение, которому сертификат выдали разработчики драйвера. Если сертификат неверен, то драйвер отказывается устнавливать сеанс с приложением, и приложение не знает, какой sessionId и с каким ключём использовать, то есть не может формировать правильные сообщения.

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

Вот такая минимальная схема аутентификации.
« Последнее редактирование: 02-12-2005 11:55 от npak » Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
Storage Device
Гость
« Ответ #3 : 02-12-2005 11:38 » 

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

Пример: все помнят aspi и какую дыру он имеет? Там можно писать диск на секторном уровне (хоть mbr) из под пользователя. Т.о. уранить все и вся нафик можно проще простого.

Под довереным приложением я здесь понимаю оригинальное приложение для работы с драйвером, код которого не был изменен. Это важно. Ибо считается, что приложение это будет подвержено атакам. Выход здесь - ЭЦП (ну а на ранних стадиях не ЭЦП а контрольная сумма). Атаки на драйвер пока не рассматриваются.

Драйвер мой выполняется в контексте вызвавшего процесса. Идея мне твоя определенно нравится и м.б. дополнительно я её и реализую (типа приложение цело, но код был вызван не из него, а из какой-то внедренной в процесс хрени). Я могу юзер-память читать по виртуальным адресам без всяких заморочек (уже только что попробовал). Только вроде обработчик EXCEPTION_EXECUTE_HANDLER надо поставить чтобы на ошибках не умирать вроде бы. Что-то типа

Код:
PUCHAR memPtr = (PUCHAR) 0x0400000; // Стандартная база MZ Header для exe
__try
{
... memPtr[i] ... // Обращение к памяти (пробовал - катит  :-D )
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DPRINT("Exception");
}

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

PS: Есть PsGetCurrentProcessId() возвращает ID процесса. Как его можно дальше применить? На какие-нибудь структуры описания процесса выйти? Тока не говорите, что его можно на глобус натянуть  Ага Уже пробовал...  Отлично
Записан
Storage Device
Гость
« Ответ #4 : 02-12-2005 12:22 » 

npack - молодец. Я почему-то зациклился на аутентификации посредством кода проложения. Беру и такой способ себе в копилку. Я уже сейчас пишу проверку по памяти приложения. Ибо все равно это первое, в чем необходимо убедиться. А вот следущим этапом будет как-раз предложеная тобой схема.

Придется криптографию вспоминать. Дифи-Хелмана помню вроде, а остальное забывать начал. В принципе на локальной тачке проблем с синхронизацией времени нет, т.ч. вместо sequenceNumber можно отметку времени заюзать. И уж если мне совсем заморочится захочется, то я за ГОСТ Р 34.10-94 возьмуся Улыбаюсь У-ух раззудись плечо... Улыбаюсь

А еще немного подумав (оказывается мне вредно в некоторых случаях этим заниматься) я пришел к выводу, что тогда уж мне лучше использовать не подпись, а шифрование. Типа конфиденциальность блюсти. Этак я до самой смерти прогу не напишу  Жаль
« Последнее редактирование: 02-12-2005 12:48 от Storage Device » Записан
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 02-12-2005 17:13 » 

Реализацию криптографических примитивов можно взять у openssl.org.  Они утверждают, что их лицензия разрешает бесплатное использование кода для любых целей, в том числе коммерческих.  Проблема не столько в криптографии, сколько в том, какого рода защиту надо организовать, от каких атак защищаться, и как проводить аутентификацию приложения.
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
Storage Device
Гость
« Ответ #6 : 03-12-2005 10:59 » 

Пока сделал такой вариант:
При получении IRP_MJ_CREATE читается MZ заголовок по адресу 0x400000 от туда извлекается смещение PE заголовка, а от туда получаются поля размера всего заголовка (MZ + PE + ObjectTable). Далее обрабатывается таблица объектов и ищется секция .check (в ней пока лежат просто CRC32)Если секции такой нет, то все - обломс. Затем вычисляется CRC32 от всего заголовка и сравнивается с тем, что в .check. Если и тут все совпало, то в цикле перебираются все секции. Если установлен флаг наличия исполняемого кода, то эта секция проверяется целиком. в общем success будет только тогда, когда не искажен заголовок и все секции кода.
Криптографию пока, считаю, рано писать. Неизвестно где еще тут грабли тазложены. Да и надо-ли ее особо стойкую делать? Эт вроде не для защиты ГТ. Так... скорее ДСП. Т.ч. довереными алгоритмами и сертифицированными средствами загоняться не стоит. Так прикинем во сколько это начальству обойдется Улыбаюсь) Риски распишем. А руководство за эти деньги лучше в заборе все дырки заколотит Улыбаюсь)
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines