Информационная безопасность

         

Безопасность ноутбука


Статья была опубликована в журнале "Мобильные Системы"



Быстрая блокировка компьютера


Проделав все эти операции, вы можете со спокойной совестью оставлять работающий ноутбук без присмотра, естественно нажав перед уходом "Alt-Ctrl-Del" и выбрав пункт "Блокировка системы". Система окажется заблокированной вплоть до ввода пароля, и злоумышленник, пускай он даже похитит ваш ноутбук, не сможет добраться до охраняемой информации. Правда вам придется отказаться от автоматического ввода пароля при старте системы, ибо это маленькое удобство сводит защищенность компьютера практически к нулю. Итак, "Панель управления" a

"Пользователи и пароли" a

"Требовать ввод имени пользователя и пароля".

Не лишним будет установить пароль и на включение компьютера (если, конечно, ваша BIOS это позволяет). Несмотря на то, что пароль снимается элементарным замыканием специальной перемычки на материнской плате, он все-таки представляет вполне надежную защиту, ведь далеко не во всех случаях злоумышленник имеет время, достаточное для вскрытия ноутбука. Правда, некоторые BIOS поддерживают, так называемый, мастер-пароль, наиболее известный из которых – AWARD_SW – в свое время наделал много шума. Не брезгуйте пройтись по хакерским сайтам, – очень много нового о своем кремниевом друге можете вычитать!

Также обязательно запретите BIOS'у грузиться с дискеты, иначе никакая Windows 2000 вам не поможет! Прочесть-то зашифрованную информацию злоумышленник не прочтет, но вот уничтожить сможет.



Некоторые тонкости шифрования


Кстати, о шифровании. В работе с зашифрованной папкой через "Проводника" есть одна тонкость. Файлы, "перетащенные" в зашифрованную папку, зашифрованы не будут! Microsoft честно об этом предупреждает и настоятельно рекомендует вместо "Drag & Drop" пользоваться командами "Вырезать/Копировать" и "Вставить". Неудобно, конечно, но…

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

Ах да, легально нам доступно лишь 56-битное шифрование, но контрафактные диски еще никто не отменял, и Windows 2000 с "крутым" шифрованием в России не редкость (невероятно, но Microsoft в файле помощи сама невольно подсказывает, как это сделать).



Шифрование папок и файлов


Как пользоваться шифрованием? Во-первых, поскольку в качестве ключа будет использоваться пароль, под которым вы входите в систему, со всем вниманием отнеситесь к его выбору. Пароль не должен представлять собой словарное слово, предсказуемую или слишком короткую последовательность.

Во-вторых, следует выбрать, какие папки вы будете шифровать. Не забывайте также про папку "TEMP"– очень многие приложения (тот же Word, например) не слишком-то аккуратно удаляют после себя временные файлы, а во временные файлы попадает все что угодно, – от рабочих данных до копий редактируемых файлов!



Папка с временными файлами может размещаться в различных каталогах, да к тому же она может быть и не одна. В "Командной строке" дайте команду "start %TEMP%", "start %TMP%", и указанные каталоги появятся на экране. (Обычно это что-то типа: "C:\Documents and Settings\Kris Kaspersky.KPNC\Local Settings\Temp"). Переходим на уровень вверх и, щелкнув правой клавишей мыша по папке, в контекстном меню выбираем "Свойства". Во вкладке "Общие" находим кнопочку "Дополнительно", которая открывает нам еще один диалог, содержащий помимо прочего пункт "Шифровать содержимое для защиты данных". Взводим галочку и дважды нажимаем "ОК". Система попросит уточнить: хотим ли мы шифровать вложенные папки или только эту папку? Конечно же, хотим шифровать вложенные! – "ОК". Если все сделано правильно, на экране появится "градусник", изображающий ход шифрования, и абстрактная анимационная картинка, с умным видом рисующая разноцветные крестики в нужных местах.

На первый взгляд может показаться, что ничего не произошло: работа с зашифрованными файлами происходит так же, как и раньше. Однако все изменится, если зайти в систему под другим именем. Будь вы хоть администратором, – в доступе вам будет отказано независимо от того, идентичен пароль или нет!

Теперь перейдем к "Корзине".
Вообще-то, от нее лучше сразу отказаться, указав в настройках "Удалять файлы сразу после удаления, не помещая их в корзину", но если уж очень хочется иметь возможность восстановления ранее удаленных файлов, найдите в корневых каталогах каждого из дисков скрытую папку "Recycle". Открыв ее, вы увидите несколько вложенных папок, каждая из которых хранит удаленные файлы "своего" пользователя. К сожалению, вместо имен здесь используются бессмысленные на первый взгляд идентификаторы. Впрочем, найти свою "Корзину" очень просто: лишь ее одну вы сможете открыть, а в остальные вас просто не пустят (если, конечно, вы не администратор системы, но постоянно заходить в систему с привилегиями администратора могут только самоубийцы). Шифруем "Корзину" и переходим к личной почте.

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

В заключение шифруем папку "Мои документы", равно, как и все папки, где вы храните секретные документы, предварительно убедившись, что ничего ценного в других папках нет. В первую очередь "к другим" относится папка "WINNT\Repair", открыто хранящая копию реестра, в том числе и базу паролей. Либо удалите ее совсем, либо зашифруйте.


в силу своей мобильности очень


Ноутбуки в силу своей мобильности очень плохо приспособлены к хранению конфиденциальной информации. Работая в "полевых условиях" (скажем, в гостиничном номере, купе поезда или самолета), вы ничем не застрахованы от любопытных глаз окружающих. К тому же ноутбук неизбежно приходится оставлять без присмотра, отлучаясь в кафе или по естественным надобностям.
Словом, существует вполне осязаемая угроза несанкционированного доступа к информации, а то и кражи ноутбука со всем его содержимым! Убытки же от раскрытия и/или модификации секретной информации зачастую сравнимы, а то и превосходят стоимость самого компьютера!
Право же, не стоит надеяться на "авось" и оправдывать халатное отношение к собственной безопасности нехваткой времени или какими бы то ни было другими причинами. Помните: беда не предупреждает о своем приходе!

Выбор файловой системы


При установке системы обязательно выберите тип файловой системы NTFS и без колебаний откажитесь от FAT. Мотивация такова: NTFS, в отличие от FAT, действительно надежная отказоустойчива система, разрушить которую можно только динамитом (шутка, конечно, но весьма недалекая от истины).

К тому же, в состав NTFS входит EFS – Encryption File System (Шифрованная Файловая Система), обеспечивающая "прозрачное" шифрование файлов и папок. Конечно, эту возможность никак не назовешь уникальной – подобное сегодня реализуют все кому не лень. Сеть буквально кишит шифровальными программами. Как говорится, выбирай на вкус! Но помимо проблемы выбора (у буриданова осла было всего две кучки сена, и то он окочурился с голоду, так и не решив с какой из них начать трапезничать), пользователь сталкивается с невозможностью проверки соответствия заявленных характеристик действительным.

Разработчик может уверять вас, что использует 1024-битное шифрование, а на самом деле не выполнять никакого шифрования вообще или реализовать примитивнейшую "ксорку". И даже честные разработчики ничем не застрахованы от ошибок! "Благодаря" этому стойкость шифра может оказаться значительно ниже ожидаемой или, что еще хуже, зашифрованный файл в некоторых случаях необратимо искажается и его вообще не удается расшифровать!

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

Словом, несмотря на то, что EFS обеспечивает всего лишь 56-битное шифрование (что при мощностях современных компьютеров назвать "шифрованием" даже язык не поворачивается), она – хороший выбор!



Выбор операционной системы


Воздвигать крепость защиты мы начнем с закладки фундамента. Фундамент– это надежная, отказоустойчивая, пуленепробиваемая и максимально жизнеспособная операционная система. Народная Windows 98, равно как и ее старшая сестра Windows Millennium, построена на латанном-перелатанном ядре Windows 3.0, и потому на эту роль категорически не подходит. Какими бы изощренными защитами вы ни пользовались, профессиональный взломщик без особых трудов сумеет их обойти, поскольку Windows 9x не позволяет гарантированно предотвратить модификацию кода защиты (т.е., попросту говоря, ее убиение).

Поэтому имеет смысл установить на всех своих компьютерах, включая ноутбук, одну из систем, базирующихся на ядре NT. К таковым принадлежат (в порядке роста требований к аппаратным ресурсам): Windows NT, Windows 2000, Windows XP. Защищенность всех их в той или иной степени одинакова, а функциональность увеличивается явно медленнее, чем "аппетит", который в отношении Windows XP иначе, как "обжорливостью", просто не назовешь.

Теоретически можно оснастить ноутбук какой-нибудь UNIX-подобной системой, например, LINUX. Достаточно непритязательные к мощности аппаратуры, они, тем не менее, обладают не сильно уступающей Windows функциональностью и обеспечивают очень высокий уровень защиты. (Некоторые UNIX'ы сертифицированы по мандату B, что значительно выше мандата C2, выданного в свое время NT). Единственное, что останавливает: крайне убогая – да не запинают меня юниксоиды – поддержка форматов Microsoft Office, ставших сегодня стандартом де-факто (Star Office многие документы не открывает вообще или делает это не вполне корректно) и отсутствие драйверов под многие, в том числе, и не экзотические "железки". Очень может сложиться так, что LINUX на ваш компьютер просто не "встанет".

Поэтому давайте остановимся на компромиссном варианте – Windows 2000.



Для создания защиты от рядового


Для создания защиты от рядового злоумышленника нет никакой необходимости покупать дорогостоящие аппаратные комплексы, неоправданно широко рекламируемые в последнее время. В конце концов, шпионов под кроватью нет, а ноутбуки воруют в первую очередь для того, чтобы их продать.
Штатные средства операционных систем Windows 2000/XP дают вполне удовлетворительные гарантии, что зашифрованная информация не будет вскрыта ни одиночкой, ни даже группой злоумышленников за разумное время. Исключение составляют лишь государство и корпорации, однако и тем, и другим вряд ли придет в голову атаковать пароль, когда под рукой всегда есть утюг (паяльник). А от утюга никакие, даже самые современные защиты, основанные на биометрических показаниях, не спасут.
Увы, замки (какие бы то ни было) защищают лишь от честных людей, поэтому, право же, не стоит вкладывать в них излишне большие деньги.

Таким образом, эффективная защита данных


Таким образом, эффективная защита данных подразумевает использование надежных средств шифрования (на основе технологий виртуальных дисков или покрытия всего диска целиком) и средств сильной аутентификации (токены и смарт-карты). Среди средств пофайлового шифрования, идеально подходящего для пересылки файлов по Интернету, стоит отметить известную программу PGP, которая может удовлетворить практически все запросы пользователя.
Довольно большое число российских производителей поставляют средства шифрования на основе виртуальных дисков. Например, компания Aladdin имеет продукт Secret Disk NG, компания «Физтехсофт» — StrongDisk, компания SecurIT — Zdisk, а компания «ЛанКрипто» — цифровой сейф «Индис». С точки зрения технологии, все эти продукты реализуют метод защиты на основе виртуальных дисков. Заметим, что на российском рынке не представлены продукты для шифрования всего диска целиком. Тем не менее заинтересованный читатель может ознакомиться с информацией о них в Интернете. Одним из таких разработчиков является фирма WinMagic.
Среди производителей средств шифрования данных на КПК стоит отметить «Лабораторию Касперского». В состав продукта Kaspersky Security для PDA помимо антивируса для портативных компьютеров входят и средства шифрования, позволяющие обеспечить полноценное шифрование чувствительных данных.

Особенности операционных систем


Остановимся на некоторых особенностях операционных систем, которые, несмотря на все свои положительные функции, подчас только мешают надежной защите конфиденциальной информации. Далее представлены наиболее распространенные системные механизмы, оставляющие для злоумышленника ряд «лазеек» и актуальные как для ноутбуков, так и для КПК.

Временные файлы. Многие программы (в том числе и операционная система) используют временные файлы для хранения промежуточных данных во время своей работы. Часто во временный файл заносится точная копия открытого программой файла, что позволяет обеспечить возможность полного восстановления данных в случае непредвиденных сбоев. Конечно, полезная нагрузка временных файлов велика, однако, будучи незашифрованными, такие файлы несут прямую угрозу корпоративным секретам.

Файлы подкачки (или swap-файлы). Очень популярной в современных операционных системах является технология swap-файлов, позволяющая предоставить любому приложению практически неограниченный объем оперативной памяти. Так, если операционной системе не хватает ресурсов памяти, она автоматически записывает данные из оперативной памяти на жесткий диск (в файл подкачки). Как только возникает потребность воспользоваться сохраненной информацией, операционная система извлекает данные из swap-файла и в случае необходимости помещает в это хранилище другую информацию. Точно так же, как и в предыдущем случае, в файл подкачки легко может попасть секретная информация в незашифрованном виде.

Выравнивание файлов. Файловая система Windows размещает данные в кластерах, которые могут занимать до 64 секторов. Даже если файл имеет длину в несколько байтов, он все равно займет целый кластер. Файл большого размера будет разбит на порции, каждая размером с кластер файловой системы. Остаток от разбиения (обычно последние несколько байтов) все равно будет занимать целый кластер. Таким образом, в последний сектор файла попадает случайная информация, которая находилась в оперативной памяти ПК в момент записи файла на диск.
Там могут оказаться пароли и ключи шифрования. Другими словами, последний кластер любого файла может содержать довольно чувствительную информацию, начиная от случайной информации из оперативной памяти и заканчивая данными из электронных сообщений и текстовых документов, которые раньше хранились на этом месте.

Корзина. Когда пользователь удаляет файл, Windows перемещает его в корзину. Пока корзина не очищена, файл можно легко восстановить. Тем не менее, даже если очистить корзину, данные все равно физически останутся на диске. Другими словами, удаленную информацию очень часто можно найти и восстановить (если поверх нее не было записано других данных). Для этого существует огромное количество прикладных программ, некоторые из них бесплатны и свободно распространяются через Интернет.

Реестр Windows. Сама система Windows, как и большое количество приложений, хранит свои определенные данные в системном реестре. Например, web-браузер сохраняет в реестре доменные имена тех страниц, которые посетил пользователь. Даже текстовый редактор Word сохраняет в реестре имя файла, открытого последним. При этом реестр используется ОС при загрузке. Соответственно, если какой-либо метод шифрования запускается после того, как загрузилась Windows, то результаты его работы могут быть скомпрометированы.

Файловая система Windows NT (NTFS). Считается, что файловая система со встроенным управлением доступом (как в Windows NT) является безопасной. Тот факт, что пользователь должен ввести пароль для получения доступа к своим персональным файлам, оставляет ложное ощущение, будто личные файлы и данные надежно защищены. Тем не менее даже файловая система со встроенными списками контроля доступа (Access Control List — ACL), например NTFS, не обеспечивает абсолютно никакой защиты против злоумышленника, имеющего физический доступ к жесткому диску или права администратора на данном компьютере. В обоих случаях преступник может получить доступ к секретным данным. Для этого ему понадобится недорогой (или вообще бесплатный) дисковый редактор, чтобы прочитать текстовую информацию на диске, к которому у него есть физический доступ.



Режим сна. Этот режим очень популярен на ноутбуках, так как позволяет сэкономить энергию батареи в тот момент, когда компьютер включен, но не используется. Когда лэптоп переходит в состояние сна, операционная система копирует на диск абсолютно все данные, находящиеся в оперативной памяти. Таким образом, когда компьютер «проснется», операционная система легко сможет восстановить свое прежнее состояние. Очевидно, что в этом случае на жесткий диск легко может попасть чувствительная информация.

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

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

Таким образом, чтобы эффективно защитить данные, недостаточно их просто зашифровать. Необходимо позаботиться о том, чтобы копии секретной информации не «утекли» во временные и swap-файлы, а также в другие «потайные места» операционной системы, где они уязвимы для злоумышленника.


Пригодность различных подходов к шифрованию данных


Рассмотрим, как различные подходы к шифрованию данных справляются с особенностями операционных систем.

Пофайловое шифрование (). Данный метод используется в основном для того, чтобы посылать зашифрованные файлы по e-mail или через Интернет. В этом случае пользователь шифрует конкретный файл, который необходимо защитить от третьих лиц, и отправляет его получателю. Такой подход страдает низкой скоростью работы, особенно когда дело касается больших объемов информации (ведь требуется шифровать каждый прикрепляемый к письму файл). Еще одной проблемой является то, что шифруется лишь файл-оригинал, а временные файлы и файл подкачки остаются полностью незащищенными, поэтому защита обеспечивается только от злоумышленника, пытающегося перехватить сообщение в Интернете, но не против преступника, укравшего ноутбук или КПК. Таким образом, можно сделать вывод: пофайловое шифрование не защищает временные файлы, его использование для защиты важной информации неприемлемо. Тем не менее данная концепция подходит для отправки небольших объемов информации через сеть от компьютера к компьютеру.

Шифрование папок. В отличие от пофайлового шифрования данный подход позволяет переносить файлы в папку, где они будут зашифрованы автоматически. Тем самым работать с защищенными данными намного удобнее. Поскольку в основе шифрования папок лежит пофайловое шифрование, оба метода не обеспечивают надежной защиты временных файлов, файлов подкачки, не удаляют физически данные с диска и т. д. Более того, шифрование каталогов очень неэкономично сказывается на ресурсах памяти и процессора. От процессора требуется время для постоянного зашифровывания/расшифровывания файлов, также для каждого защищенного файла на диске отводится дополнительное место (иногда более 2 кбайт). Все это делает шифрование каталогов очень ресурсоемким и медленным. Если подвести итог, то хотя данный метод довольно прозрачен, его нельзя рекомендовать для защиты важной информации. Особенно если злоумышленник может получить доступ к временным файлам или файлам подкачки.


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

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

Шифрование всего диска (). В основе данной концепции лежит не пофайловое, а посекторное шифрование. Другими словами, любой файл, записанный на диск, будет зашифрован. Криптографические программы шифруют данные прежде, чем операционная система поместит их на диск. Для этого криптографическая программа перехватывает все попытки операционной системы записать данные на физический диск (на уровне секторов) и производит операции шифрования на лету. Благодаря такому подходу зашифрованными окажутся еще и временные файлы, файл подкачки и все удаленные файлы. Логичным следствием данного метода должно стать существенное снижение общего уровня производительности ПК.


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

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

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


S3.shtml






Схема 3. Шифрование всего диска (включая загрузочные записи)



Шифрование с использованием сильной аутентификации


Для надежного сохранения данных требуются не только мощные и грамотно реализованные криптографические технологии, но и средства предоставления персонализированного доступа. В этой связи применение строгой двухфакторной аутентификации на основе аппаратных ключей или смарт-карт является самым эффективным способом хранения ключей шифрования, паролей, цифровых сертификатов и т. д. Чтобы успешно пройти процедуру сильной аутентификации, пользователю необходимо предъявить токен (USB-ключ или смарт-карту) операционной системе (например, вставить его в один из USB-портов компьютера или в устройство считывания смарт-карт), а потом доказать свое право владения этим электронным ключом (то есть ввести пароль). Таким образом, задача злоумышленника, пытающегося получить доступ к чувствительным данным, сильно осложняется: ему требуется не просто знать пароль, но и иметь физический носитель, которым обладают лишь легальные пользователи.

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



Технологии шифрования


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

Пофайловое шифрование. Пользователь сам выбирает файлы, которые следует зашифровать. Такой подход не требует глубокой интеграции средства шифрования в систему, а следовательно, позволяет производителям криптографических средств реализовать мультиплатформенное решение для Windows, Linux, MAC OS X и т. д.

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

Шифрование виртуальных дисков. Концепция виртуальных дисков реализована в некоторых утилитах компрессии, например Stacker или Microsoft DriveSpace. Шифрование виртуальных дисков подразумевает создание большого скрытого файла на жестком диске. Этот файл в дальнейшем доступен пользователю как отдельный диск (операционная система «видит» его как новый логический диск). Например, диск Х:\. Все сведения, хранящиеся на виртуальном диске, находятся в зашифрованном виде. Главное отличие от предыдущих подходов в том, что криптографическому программному обеспечению не требуется шифровать каждый файл по отдельности. Здесь данные шифруются автоматически только тогда, когда они записываются на виртуальный диск или считываются с него. При этом работа с данными ведется на уровне секторов (обычно размером 512 байт).

Шифрование всего диска. В этом случае шифруется абсолютно все: загрузочный сектор Windows, все системные файлы и любая другая информация на диске.

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

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



Защита конфиденциальных данных на ноутбуках и КПК


Алексей Доля

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

Одной из самых опасных угроз сегодня является несанкционированный доступ. Согласно исследованию Института компьютерной безопасности и ФБР (см. CSI/FBI Computer Crime and Security Survey 2005), в прошлом году 55% компаний зарегистрировали инциденты, связанные с неправомочным доступом к данным. Более того, вследствие неавторизованного доступа каждая фирма потеряла в 2005 году в среднем $303 тыс. Причем по сравнению с 2004 годом убытки увеличились в шесть раз. Таким образом, суммарные убытки, которые понесли свыше 600 опрошенных фирм, за год превысили $30 млн (см. ).

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

Проблемы, возникающие у предприятия в случае утечки информации, особенно показательны на примере кражи ноутбуков. Достаточно вспомнить недавние инциденты, когда у компании Ernst&Young в течение нескольких месяцев было похищено пять ноутбуков, содержащих приватные сведения клиентов фирмы: компаний Cisco, IBM, Sun Microsystems, BP, Nokia и т. д. Здесь в высшей мере проявился такой трудноизмеримый показатель нанесенного ущерба, как ухудшение имиджа и снижение доверия со стороны клиентов.
Между тем аналогичные трудности испытывает множество компаний.

Так, в марте 2006 года фирма Fidelity потеряла ноутбук с приватными данными 200 тыс. служащих HP, а в феврале аудиторская компания PricewaterhouseCoopers лишилась ноутбука с чувствительными сведениями 4 тыс. пациентов одного американского госпиталя. Если продолжать список, то в него попадут такие известные компании, как Bank of America, Kodak, Ameritrade, Ameriprise, Verizon, и другие.

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

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


Атака на Windows NT


Статья была опубликована в

В настоящей статье рассказывается о проблемах безопасности операционной системы Windows NT, в том числе и ее последней версии Windows 2000. Публикация рассчитана на системных администраторов и разработчиков прикладного программного обеспечения, предназначенного для работы на Windows NT.

Если первые кирпичи здания UNIX закладывались в ту далекую эпоху, когда никакой теории безопасности еще не существовало, то Windows NT изначально проектировалась как защищенная, отказоустойчивая система, стойкая ко всем антиамериканским настроениям.

Дейв Катлер, крестный отец Windows NT, ранее участвовавший в создании двух легенд семидесятых – RSX-11M и VMS, вложил в NT весь свой талант и опыт, но… похоже, потерпел неудачу. Да, Windows NT построена на передовых технологиях и основана на внутренне непротиворечивой модели безопасности, но теоретическую идиллию разрушают вездесущие ошибки реализации.

Кроме досадных багов – своеобразных программистских описок, исправляемых очередной заплаткой, – актуальны и проблемы стыковки различных компонентов операционной системы друг с другом. Несогласованная же работа способна значительно ослабить степень безопасности. Но ни один человек не в состоянии удержать в голове миллионы строк исходного кода операционной системы, а с ростом количества разработчиков, координировать их действия становится все сложнее и сложнее.

Неудивительно, что в Windows NT обнаруживаются серьезные бреши в защите и существуют способы несанкционированного повышения уровня своих привилегий с “гостя” до администратора. Часть ошибок устраняется правильным администрированием (читай – нечеловеческим ущемлением прав пользователей и отключением всего, что удается отключить), но в силу самой архитектуры Windows NT у злоумышленника всегда останется шанс проникнуть в систему.

Как и UNIX, операционная система Windows NT подвержена угрозе срыва стека, точно так же для нее актуальна возможность прорыва за пределы процесса, позволяющая пользователю получить доступ к данным и коду другого приложения (включая системные сервисы), наконец, реализация протоколов семейства TCP/IP оставляет желать лучшего и допускает возможность удаленной атаки.


Впрочем, ошибки в практике программистов – дело привычное, и встречаются они не только у Microsoft, но отличительная черта Microsoft – бег впереди прогресса – приводит к появлению новых версий задолго до того, как разработчики успевают выявить и устранить дефекты в старых.

Для проникновения в систему злоумышленнику вовсе не обязательно подбирать пароль: одна забавная ошибка позволяет быстро, незаметно и надежно похитить его у жертвы. Достаточно поместить на страничку ссылку типа “<IMG SRC=file:////my.own.smb.server/mypets.jpg>“ и дождаться, пока жертва не вздумает на нее зайти (или для ускорения развязки послать жертве письмо в HTML-формате). Когда это, наконец, произойдет, Internet Explorer или Netscape Navigators автоматически, не запрашивая подтверждения, передадут имя пользователя и хеш-значение пароля, под которым тот вошел в систему.

Впервые на эту ненормальность обратил внимание Аарон Спанглер, а за ним обнаружили и другие. Атаке оказались подвержены все версии Windows NT 3.5-4.0 вплоть до последних Service Pack, а так же Windows 95 и Windows for Workgroups.

Но это не единственный способ несанкционированного вторжения. В Windows NT наличествует, так называемый, гостевой вход (“Guest Account”) с пустым паролем. На сервере он по умолчанию заблокирован, а на рабочих станциях – открыт! Получить доступ к узлу сети, пускай на гостевых правах – это уже происшествие, а вход в систему с привилегиями администратора – катастрофа.

Разумеется, на рабочей станции пароль администратора не хранится. Собственно, в Windows NT пароли вообще нигде не хранятся. Вместо этого в базу данных SAM (Security Account Manager) заносятся хеш-значения паролей. Сама база хранится в файле “%SystemRoot%\SYSTEM32\CONFIG\sam”, доступ к которому закрыт системой. Файл “sam” представляет собой ветвь реестра “HKEY_LOCAL_MACHINE\SECURITY\SAM”, права чтения которого предоставляются только администратору (и то по умолчанию они заблокированы).


Функции API, манипулирующие с именами пользователя и хеш-значением, недоступны непривилегированным пользователям. Словом, защита выглядит как будто безупречной и неприступной.

Тем временем, резервная копия системы, хранящаяся в каталоге “%SystemRoot%\Repair”, в любое время доступна каждому члену группы Everyone! Резервная копия создается при установке (или переустановке) Windows NT, а также всякий раз при запуске утилиты rdisk с ключом “/s”. Распаковав добытый файл командой “expand sam._ sam”, злоумышленник сможет извлечь из него имена пользователей и хеш-значения паролей.

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

Но помимо гостевого входа, который элементарно отключить, в Windows NT, существует анонимный пользователь, обладающий правами на просмотр списка пользователей, разделенных ресурсов и некоторых (между прочим, достаточно многих) ветвей системного реестра. Анонимный пользователь необходим системе для организации нуль-сессий (NULL session), использующихся для выполнения действий, не требующих аутентификации (или в тех случаях, когда аутентификация невозможна). Например, пусть в сети находятся два домена Windows NT, условно обозначаемых “D1” и “D2”. Если “D1” доверяет “D2”, а сам “D2” не доверяет “D1”, то для получения списка пользователей и групп, расположенных на “недоверчивом” домене, приходится прибегать к анонимному подсоединению.

Анонимным пользователям доступен специальный ресурс IPC$ (inter-process communication), подключить который можно командой «net use “” /USER:””», где name – сетевое имя компьютера или его IP адрес.


Злоумышленник получает возможность запускать User Manager для просмотра пользователей и групп, Event Viewer для просмотра журнала событий, а также другие средства удаленного администрирования, основанные на протоколе SMB.

Ветвь реестра “HKLM\Software\Microsoft\Windows\CurrentVersion\Run”, содержащая имена программ, запускающихся при каждой локальной регистрации пользователя, доступна анонимному пользователю, как для чтения, так и для модификации. Изменяя ее по своему усмотрению, злоумышленник сможет выполнить не только одну из программ, хранящихся на сервере, но и любую из программ, находящихся на его компьютере! Для этого он должен записать нечто вроде “\\mycomputer\myprog.bat”, где mycomputer – имя компьютера злоумышленника или его IP-адрес. Командный файл выполняется с привилегиями локально зашедшего на сервер пользователя (а локально на сервер, как правило, заходят администраторы). А, получив права администратора, злоумышленник может сделать с сервером все, что угодно (например, узнать имена и хеш-значения всех остальных пользователей).

В 1997 году вышла программная реализация такой атаки, получившая название RedButton. Компания Microsoft выпустила горячую заплатку для Windows NT 3.51 и включила соответствующие исправления в Service Pack 3 для Windows NT 4.0. А в “базе знаний” Microsoft (Microsoft Knowledge Base) появилась достаточно подробная техническая заметка Q143474, развернуто объясняющая суть проблемы.

Но Service Pack не устранял возможность анонимного подключения, а только ограничивал права анонимного пользователя. Компания Microsoft открыто признавала (в технической заметке Q129457 базы знаний), что “…with RestrictAnonymous access enabled, anonymous connections are able to obtain the password policy from a Windows NT Server. The password policy defines the Windows NT domain policy with respect to the minimum password length, whether blank passwords are permitted, maximum password age, and password history”.

Технически регистрация в системе организована так, что проверка password policy осуществляется до аутентификации пользователя.


Например, заведомо короткий пароль не стоит и проверять. В Windows NT policy доступны всем, в том числе и анонимному пользователю (даже после установки Service Pack 3!). Злоумышленник сможет узнать минимальную длину пароля, как часто меняются пароли и какое количество неудачных попыток регистрации блокирует учетную запись (если блокировка включена). Полученная информация значительно облегчает проникновение в систему.

А еще в policy открытым текстом хранятся предыдущие используемые пароли, (так называемая история паролей). С точки зрения безопасности пароли необходимо периодически менять, – причем они не должны повторяться (во всяком случае, спустя короткое время). Например, в истории могут храниться пять последних паролей пользователя, и при смене пароля система проверяет, – не совпадает ли новый пароль с одним из них. Конечно, это старые пароли, недействительные на текущий момент, но их изучение позволяет понять, по какому принципу назначаются пароли: выбираются ли словарные слова, даты рождения родственников, имена любимых хомячков или абсолютно случайные последовательности. Кстати, не исключено, что рано или поздно пользователь вновь выберет один из старых паролей, возможно, несколько его видоизменив.

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

Компания Microsoft утверждает, что Windows NT позволяет ограничить рабочие станции, с которых пользователь может входить в систему. И это чистая правда, – администратор легко может контролировать легального пользователя (в чем каждый с легкостью имеет возможность убедиться), а как насчет злоумышленника?

Увы! Прикладной протокол SMB реализуется поверх транспортных протоколов, совместимых с интерфейсом NetBIOS. А при установлении соединения по протоколу NetBIOS-сервер проверяет имя, сообщенное ему клиентом, а не его IP-адрес! Злоумышленнику достаточно знать (или выяснить методом перебора) с каких рабочих станций разрешен вход на сервер, а подделать их имена – дело техники. Если быть совсем точным – NetBIOS-сервер вообще не проверяет имя, переданное клиентом – это забота SMB-сервера, а до начала SMB-сессии никакое протоколирование установленных соединений не ведется!
<


/td>


Другую полезную для себя информацию злоумышленник может получить с помощью протокола SNMP (Simple Network Management Protocol). Протокол SNMP обеспечивает мониторинг сети и обычно используется администраторами, которые с его помощью могут отслеживать и оперативно реагировать на возникшие проблемы, а также настраивать сеть на максимальную производительность.

Одна из задач, возлагаемых на SNMP, – поддержка распределенной информационной базы управления MIB (Management Information Base). В узлах сети, находятся агенты – программные модули, собирающие информацию об управляемых объектах и размещающие полученную информацию в своих локальных переменных. Протокол SNMP обеспечивает обмен контрольной информацией между элементами сети и доступ к базе MIB.

При обмене сообщениями агенты используют механизмы аутентификации (часто уязвимые для взлома), а для доступа к базе MIB достаточно знать, так называемое, имя сообщества (community name), по умолчанию – public. А в базе MIB Windows NT среди прочего содержится следующая информация:

Таблица сервисов, запущенных на сервере, включая название и состояние сервиса

Число парольных нарушений, зарегистрированных на сервере

Тип разграничения доступа (на уровне пользователей или на уровне ресурсов)

Перечень сессий, включая имена станций клиентов и состояние сессии

Перечень учетных записей сервера

Перечень разделяемых ресурсов сервера с указанием локальных путей

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



Все способы, описанные выше, в той или иной мере устраняются правильным администрированием сети и не гарантируют злоумышленнику проникновения в систему. Часто атакующий действует наугад, отыскивая наименее защищенный узел, а не пытается получить доступ к какой-то одной, конкретной машине.

Мусорные баки и корзины издавна служили источником ценной информации. И копания в “мусорной корзине” Windows NT также способны извлечь на свет документ, содержащий конфиденциальные данные.

Поэтому в Windows NT существует возможность предоставления каждому пользователю своей собственной корзины. При нормальном развитии событий никакой пользователь, не обладающий правами администратора, не может получить доступ к чужой корзине. Но друг от друга корзины отличаются всего лишь идентификатором пользователя SID, который злоумышленнику легко выяснить (существуют API-функции, выдающие идентификатор пользователя по его имени). Если злоумышленник изменит идентификатор свой корзины на идентификатор корзины жертвы, то файлы, удаляемые жертвой, попадут в руки злоумышленника.

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

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

Но если в коде ядра присутствуют ошибки, позволяющие пользователю вмешиваться в работу системных процессов, то он сможет получить любые привилегии, в том числе и администратора! Изучая работу модуля ntoskrnl.exe, Константин Соболев обратил внимание на то, что функция NtAddAtom не контролирует значение аргумента, указывающего адрес для записи результатов успешности своей работы. Поскольку функция NtAddAtom выполняется ядром и имеет привилегии System, она может писать, что ей вздумается и куда вздумается.


Но функция win32 API AddAtom содержит переходной код, который сохраняет результат работы NtAddAtom в локальной переменной, откуда и возвращает значение пользователю. Однако через прерывание 0x2E можно получить доступ непосредственно к функциям ядра без высокоуровневых оберток.

Реакция Microsoft в описании Соболева выглядит так: “30 июля 1997 я послал письмо в Microsoft, что так и так, есть такой баг. Через пару дней получил ответ от господина N, что я ошибся, и, вообще, моя программа не работает. Послав программу на www.ntsecurity.net и на news я убедился, что она все-таки работает. После публикации мне пришло письмо от господина NN из Microsoft (должностью повыше, чем N) с просьбой сообщить имя господина N”.

Вообще же, если у пользователя есть право отладки приложений, ему доступны функции WriteProcessMemory и CreateRemoteThread, позволяющие как угодно распоряжаться системой по своему усмотрению. Поскольку ни один здравомыслящий администратор потенциальному злоумышленнику такого права не даст, тому приходится присваивать его самостоятельно. К сожалению, описание алгоритма такой атаки выходит за рамки данной статьи, но существует утилита Sechole, написанная Prasad Dabak, Sandeep Phadke и Milind Borate, которая замещает код функции OpenProcess (проверяющий наличие прав отладки приложений перед открытием процесса) и затем, пользуясь отладочными функциями, помещает текущего пользователя в группу администраторов.

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

Именованные каналы представляют собой механизм межсетевой передачи данных по виртуальному каналу, гарантирующему доставку сообщений. (Почтовые ящики не гарантируют доставку сообщений и процесс-отправитель не получает уведомление получил ли адресат сообщение или нет). Каналы реализованы в виде псевдофайловой системы NPFS (Named Pips File System), которая хранит все сообщения в памяти и выдает их по запросу.


Имена сообщений представляются в виде “\pipe\pipaname” и работают с теми же функциями, что и обыкновенные файлы (например, CreateFile, ReadFile, WriteFile).

Создать именованный канал (или новый экземпляр существующего канала, если такой канал уже есть) позволяет функция CreateNamedPipe. Каждый экземпляр канала одновременно может работать лишь с одним клиентом. Поэтому при создании канала, сервер сразу же открывает несколько экземпляров канала. В документации Microsoft утверждается, что при запросе на подключение система соединяет клиента с любым незанятным экземпляром канала, но эксперименты показывают, – клиент всегда подключается к наиболее ранее созданному (или освобожденному) каналу.

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

Это дает возможность внедрять ложные объекты в вычислительную систему и перехватывать входящий трафик. Более того, существует возможность унаследовать права клиента! Процессу, породившему экземпляр канала, достаточно вызвать функцию ImpersonateNamedPipeClient, выполняющую олицетворение (Impersonate) клиента. Вообще-то эта функция задумывалась как раз для обратного – понижения привилегий потока, выполняющего олицетворение.

Разработчики, в стремлении усилить защищенность системы, предложили: потоку, обрабатывающему подключение, временно назначать права клиента, установившего соединение. Пока привилегии клиента не превышают привилегий сервера (а обычно это так и есть), не происходит ничего интересного. Но как только пользователь из группы guest (или Everyone) создаст подложный экземпляр потока, и дождется подключения привилегированного клиента (или администратора!) он увеличит свои права (иногда весьма значительно)!



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

Впрочем, существует одно существенное ограничение. Олицетворяется не пользователь, а поток, и по наследству полученные привилегии не передаются. Это происходит потому, что в Windows NT новому процессу назначается маркер доступа процесса-родителя, а не маркер доступа потока, вызывающего CreateProcess. Поэтому злоумышленник не сможет запустить ни одну программу, требующую прав администратора. Однако ему это и не нужно – достаточно воспользоваться соответствующими системными функциями (а они доступны, включая и те, что требуют для исполнения прав администратора).

Существует программная реализация такой атаки, созданная Вадимом Проскуриным, совместно с Петром Девяниным и Сергеем Заливакиным. Программа создает троянский экземпляр одного из системных каналов и ждет подключения клиента. Если получение прав администратора происходит успешно, в качестве демонстрации работоспособности программы создается новый пользователь в группе “Администраторы”, но для предотвращения несанкционированного доступа в систему, вновь созданная учетная запись тут же блокируется. Очевидно, разработчики не ставили перед собой цель вторжения в чужие системы, а стремились показать наличие такой уязвимости.

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


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

И такая возможность есть! Системные сервисы в Windows NT не ограничивают максимальное количество создаваемых экземпляров канала, а каждый канал, как правило, обрабатывается отдельным потоком (т.е. происходит классическое, популярное со времен UNIX расщепление процесса-обработчика при запросе на очередное подключение). Все потоки и каждый экземпляр канала требуют некоторого количества оперативной памяти, и если злоумышленник вздумает в бесконечном цикле устанавливать все новые и новые соединения, оперативной памяти может попросту не хватить!

На первый взгляд никакой опасности нет, – Windows NT поддерживает виртуальную память и при необходимости умеет выгружать наименее нужные страницы на диск. Злоумышленник физически не сможет работать со всеми установленными соединениями одновременно (памяти-то у него поменьше, чем у сервера будет) и неактивные потоки без ущерба для производительности могут быть скинуты в файл подкачки. Кажется, все определяется лишь количеством свободного места на диске.

Но при создании канала система размещает входящий и исходящий буфера в неоткачиваемой памяти (non-paged pool). Поэтому максимальное количество экземпляров канала определяется объемом неоткачиваемой памяти, выделенной процессу. Таким образом, существует возможность, как заблокировать создание новых экземпляров канала, так и замедлить работу системы, отобрав у системных процессов всю свободную оперативную память, заставляя их за каждой страницей обращаться к диску.

Вот как описывает Вадим Проскурин реакцию системы на создание бесчисленного количества экземпляров системных каналов:

“…загрузка процессора компьютера, на котором выполняется процесс-сервер, стабильно держится на уровне 100% (при этом около 90% времени процессор обслуживает процессы с базовым приоритетом High), а объем свободной оперативной памяти этого компьютера уменьшается со скоростью от 1 до 3 мегабайт в секунду.


Когда и физическая, и виртуальная памяти компьютера переполняются, и начинается рост файла виртуальной памяти, эта скорость несколько уменьшается. Уже через минуту атакованный компьютер становится практически неработоспособен (окно Explorer прорисовывается несколько минут), а через 5-10 минут перегруженность операционной системы достигает такой степени, что команда Shutdown выполняется 3-6 часов”

Идея подобной атаки, окрещенной PipeBomb, принадлежит Петру Девянину, а Сергеем Заливакиным создана ее программная реализация, которую можно получить, обратившись по адресу: .

По словам авторов, комбинированием AdminTrap со строго дозированным воздействием на систему PipeBomb им удалось перехватить два соединения: winreg, управляющее удаленным доступом к реестру, и spoolss, отвечающее за удаленное управление принтером. Однако не исключено, что удастся перехватить и другие соединения, в том числе служебные, выполняющиеся системой без непосредственного участия администратора. Например, каналы lsass и LANMAN используются для передачи по сети имени пользователя и хеш-значения пароля во время сеанса аутентификации, а механизм удаленного вызова процедур (RCP) использует канал lsarpc.

Обе атаки успешно функционирует в среде Windows NT 4.0 со всеми установленными Service Pack, одинаково хорошо “чувствуя” себя и на рабочей станции, и на сервере. Они осуществимы как из локальной сети, так из Internet, поскольку основаны на прикладном SMB-протоколе, который может быть реализован поверх транспортного протокола TCP. Административными средствами посильно перекрыть Internet-трафик, установив фильтр, отсекающий все пакеты, содержащие заголовки SMB, но такая мера бессильна против злоумышленников, находящихся внутри локальной сети.

Фирма Microsoft исправила эту проблему после выхода Windows 2000, выпустив 2 августа 2000 года заплатку “Service Control Manager Named Pipe Impersonation”, которую можно получить, обратившись по адресу: .

Оказались, что уязвимы все три платформы – и Microsoft Windows 2000 Professional, и Microsoft Windows 2000 Server, и Microsoft Windows 2000 Advanced Server, поэтому нерасторопные администраторы рискуют подвергнуться атаке.


Подробнее об этом можно прочитать в технической заметке Microsoft Security Bulletin (MS00-053).

Вообще же, отсутствие ограничений на количество создаваеммых объектов в NT повсеместны. Давно известен пример атакующей программы, создающей в бесконечном цикле огромное количество окон. Когда же лимит, отведенный системой, исчерпывается (все на свете рано или поздно кончается), никто, даже ядро системы, не может создать новое окно. Ни работать на компьютере, ни “прибить” процесс, ни, даже, завершить работу системы становится невозможно, потому что для этого необходимо вызвать либо Менеджер Задач, либо диалог “Завершение Работы”, а новые окна создать невозможно! Поэтому, остается утопить “заветную” клавишу Reset или выдернуть шнур из сети электропитания. Помнится, Microsoft решила проблему “методом страуса” – окно Менеджера Задач создавалось сразу же после старта системы, но не отображалось на экране, пока в нем не было необходимости, а вызов Менеджера Задач только менял атрибуты уже существующего окна, и оно становилось доступным в любой критической ситуации.

Спустя некоторое время появилась простая программа: вместо окон в бесконечном цикле, порождающая потоки (а количество потоков, принадлежащих процессу, независимо от его привилегий, не ограничено). Потоки же способны “съесть” все процессорное время, остальные процессы с равным (или низшим) приоритетом практически “замрут”. Впрочем, если у злоумышленника отсутствует право выполнять процессы с приоритетом выше среднего (Normal), то существует возможность “прибить” зловредную программу Менеджером Задач, но, увы, не автоматически. Если же это произойдет на сервере, то многие приложения окажутся парализованными до вмешательства администратора.

Поэтому ситуацию с каналами нельзя отнести в разряд непредвиденных, однако это первая реализация удаленного перехвата, которая не может быть устранена правильным администрированием. И никто не гарантирует, что завтра не обнаружатся новые серьезные дыры в системе безопасности.Скорее наоборот, обнаружатся, наверняка. Ну не может быть, чтобы не обнаружились! Но вот где, как и когда?

1 Кстати, если в слове "VMS" сдвинуть все буквы на одну позицию вправо, получится "WNT"    

2 А все что не удается отключить, выламывается с корнем    

3 В Windows 2000 это упущение уже исправлено    

4 Резервная копия хранится в упакованном виде    

5 Или их хэши    

6 Подробности в статье Q129457 базы знаний    

7 А по умолчанию они у него есть    


Доступ к чужому адресному пространству


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

Полноценной защиты от предумышленного доступа в чужое адресное пространство ни в UNIX, ни в NT на самом деле нет. Собственно, UNIX вообще не представляет никаких средств такого взаимодействия, кроме разве что разделяемых (т. е. совместно используемых) областей памяти, но это совсем не то. NT же обеспечивает весьма гибкий контроль доступа адресному пространству процессоров, но все-таки значительно проигрывает UNIX в отношении безопасности. И вот почему:

а) в NT доступ в чужое адресное пространство по умолчанию разрешен всем, даже гостю, и если какой-то процесс (точнее его владелец) не хочет, чтобы в него проникали, он должен заявить об этом явно;

б) в UNIX для отладки процессов необходимо, чтобы отлаживаемый процесс не только дал согласие на свою отладку, но и выполнил некоторые действия, причем, отладка уже запущенных процессов запрещена! NT же беспрепятственно позволяет отлаживать активные процессы и инициировать отладку новых, естественно, с наследованием всех привидений процесса-отладчика (то есть в общем случае, отладка более привилегированных процессов из менее привилегированных невозможна).

Короче говоря, - NT предоставляет весьма вольготные условия для существования Stealth-вирусов, клавиатурных и паролей шпионов и всех прочих тварей, нарушающих покой системы.



Философия и архитектура NT против UNIX с точки зрения безопасности


Существует мнение, что распространение электронно-вычислительных машин привнесло больше проблем, чем их решило. Человечество в своей массе ни морально, ни этически, ни психологически ко всему этому оказалось просто не готово и компьютерная техника попала в руки к людям, чей интеллект направлен лишь на разрушение. И, если до появления Интернета, вирусная угроза в основном сводилась к проблеме "грязных рук" и беспорядочного копирования ПО, то сейчас ситуация существенно изменилась.



Каждому хакеру - по системе!


.с другой стороны, степень опасности "дыры" зависит не сколько от ее "линейных размеров", столько от распространенности операционной системы, в которой она обнаружена. Огромное количество клонов UNIX ставит эту систему в весьма выигрышное (с точки зрения безопасности) положение. К тому же, постоянно переписываемые да и просто альтернативные ядра даже одну-единственную систему размножают до целого семейства, благодаря чему, уязвимость, найденная в одной версии ядра, зачастую недействительна для всех остальных.

В результате, могущество хакера, нашедшего дыру в UNIX, оказывается много ниже, чем если бы дыра аналогичных размеров была обнаружена в NT (в силу не многочисленности своих разновидностей, каждая, отдельно взятая версия NT, установлена на значительно большем количестве машин, нежели UNIX). Именно поэтому NT все-таки ломают или во всяком случае пытаются это сделать. Соблазн в самом деле настолько велик, что хакеров не останавливают ни отсутствие исходных текстов, ни трудоемкость анализа. К тому же, ядро NT не переписывается каждый день и практически все дыры, обнаруженные в NT 4.0 остаются актуальными и в Windows 2000, а то и в Windows XP. (Подробнее об этом рассказывается в книге Криса Касперски "Техника сетевых атак").

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

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

Неплохая идея: на передний план обороны водрузить какой-нибудь "редкоземельный" клон UNIX, а на второй - NT. Большинство хакеров, как показывает практика, в основном специализируются на одной операционной системе, и лишь в исключительных случаях - на двух сразу.



Комплектность штатной поставки


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

Операционные системы семейства NT, укомплектованные более чем скромным набором утилит, в этом отношении выглядят более защищенными. Впрочем, это непринципиальное различие: грамотный администратор и так удалит из UNIX все лишнее.



Механизмы аутентификации


Механизмы аутентификации пользователей (то есть, попросту говоря алгоритмы проверки правильности пароля) и в UNIX, и в NT построены на практически идентичных принципах. А именно: эталонный пароль вообще нигде не хранится, - вместо этого используется его хэш (грубо говоря: контрольная сумма). Пользователь вводит пароль, операционная система хэширует его по тому или иному алгоритму и сравнивает полученный результат с хэш-суммой эталонного пароля, хранящейся в специальной базе паролей. Если они совпадают, то все ОК и, соответственно, наоборот. Такая схема (при отсутствии ошибок реализации, конечно) гарантирует, что даже если злоумышленник и получит доступ к базе паролей, он все равно не сможет проникнуть в систему иначе, чем методом перебора. Впрочем, если спуститься с небес идеализированных математических концепций на грешную землю, можно обнаружить, что "нормальные герои всегда идут в обход". В частности, в большинстве UNIX'ов вводимый пароль открытым текстом передается по сети и при наличии хотя бы одного уязвимого узла в цепочке передачи, может быть перехвачен хакером. В NT же открытый пароль никогда не передается (ну, разве что администратор не настроит ее соответствующим образом) и используемая в ней схема аутентификации устойчива к перехвату трафика.

С другой стороны, NT крайне небрежно относится к охране парольной базы от посягательств хакеров. На первый взгляд кажется, что никакой проблемы вообще нет, т. к. доступ к базе имеется лишь у системы, администраторов и ограниченного количества специально назначенных администратором пользователей (например, операторов архива, периодически сохраняющих базу на резервных носителях). А вот в некоторых, правда, довольно немногочисленных UNIX'ах файл паролей свободно доступен всем пользователям системы и зачастую даже "виден" по сети! Ну и что с того? - спросите вы. - Ведь паролей в парольном файле все равно нет, а "обращение" хеша методом перебора занимает слишком много времени, пускай хакер перебирает, если ему это занятие так нравится. Хорошо, тогда такой вопрос: возможно ли в одном единственном переборе взломать все машины в сети? Не спешите отвечать "нет", ибо правильный ответ: "да"! Объем жестких дисков сегодня возрос настолько, что хакер может сохранить хеши всех перебираемых паролей. Неважно сколько это займет времени: месяц или даже несколько лет, - ведь теперь у взломщика появится возможность практически мгновенно восстановить пароль по его хешу - была бы только парольная база в руках! Мало того, что в NT резервные копии парольной базы по умолчанию хранятся в общедоступных каталогах, так алгоритм аутентификации не использует привязки (salt), в результате чего хеши одинаковых паролей в NT всегда будет совпадать, значительно упрощая тем самым взлом! Впрочем, от атак данного типа привязка все равно не спасает, разве что немного продляет "мучения" системы.



Межпроцессорные коммуникации


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

а) самостоятельно решать с кем ему взаимодействовать, а с кем нет;

б) уметь определять подлинность процессов отправителей и процессов получателей;

в) контролировать целостность передаваемых/принимаемый данных;

г) создавать защищенный канал связи, устойчивый к перехвату трафика.

Многообразие средств межпроцессорного взаимодействия, поддерживаемых современными операционными системами, чрезвычайно затрудняет ответ на вопрос: а выполняются ли перечисленные выше требования на практике? Ограниченные объемом журнальной статьи мы рассмотрим лишь два наиболее популярных средства межпроцессорного взаимодействия: каналы,сокеты и сообщения.

Неименованные каналы позволяют связывать лишь родственные процессы и потому полностью отвечают условию пункта а). Даже если посторонний процесс каким-либо образом ухитриться получить дескриптор неименованного канала не родственного ему процесса, то он (дескриптор) вне контекста своего процесса потеряет всякий смыл и ничего пакостного с ним злоумышленник не сможет сделать. Если же злоумышленник проникнет в родственный процесс и попытается, скажем, облить своего соседа толстой струей информационного мусора, то. ничего не произойдет. Если процесс-читатель не будет успевать "заглатывать" посылаемые ему данные, система автоматически приостановит процесс передачи, не давая атакуемому процессу "захлебнуться". Причем, жертва вольна сама решать - выносить ли ей такие издевательства дальше или же просто закрыть канал и послать невоспитанного хакера куда подальше.


Именованные каналы доступны всем процессам в системе, а в NT и процессам, исполняющимся на остальных узлах сети. Естественно, для открытия именованного канала необходимо иметь соответствующие привилегии, но вот для создания нового именованного канала такие привилегии необязательны, причем под NT не существует легальных способов определения "авторства" создателя того или иного канала! Учитывая, что именованные каналы активно используются системой для передачи зашифрованных паролей и удаленного управления реестром, угроза внедрения подложных каналов уже не покажется незначительной. Частично эта проблема решается установкой соответствующего пакета обновления (в частности для Windows 2000 это Service Pack 2), который предотвращает создание подложного экземпляра уже существующего именованного канала, между тем возможность создать подложный канал "с нуля" по прежнему остается, а механизмов идентификации создателей канала в win32 API как не было, так до сих пор и нет. Локальность именованных каналов в UNIX оказывается одновременно и сильной, и слабой ее стороной. Тем не менее, отсутствие удаленного доступа к каналам еще не дает повода расслабляться, - ведь создать подложный канал может даже гостевой пользователь, что в ряде случаев позволяет ему успешно атаковать более привилегированные процессы.

Именованные каналы имеют еще один серьезный недостаток: обработка каждого нового подключения требует какого-то количества системных ресурсов, а максимальное количество создаваемых экземпляров канала обычно не ограничено. Создавая все новые и новые экземпляры злоумышленник "сожрет" все ресурсы и система рано или поздно "встанет". Даже если максимальное количество экземпляров было заранее ограничено, получим те же самые яйца, только в профиль. Захватив все свободные каналы, злоумышленник нарушит нормальную работу всех остальных легальных процессов. Система, правда, не рухнет но пользы от этого будет немного. Решение проблемы состоит в введении квот с клиентской (а не серверной!) стороны, но во-первых, не совсем ясно как такое реализовать в сетевой среде, а, во-вторых, клиентскую защиту всегда легко обойти.



Сокеты, использующиеся в основном в межузловых межпроцессорных взаимодействиях (хотя в UNIX они широко применяются и для локального обмена данными), так же катастрофически незащищены перед попыткой захвата всех свободных ресурсов и огромное количество постоянно совершающихся flooding-атак - лучшее тому подтверждение. Кстати, наличие "сырых" (RAW) сокетов в UNIX делает ее платформой номер один для любой мало-мальски серьезной TCP/IP-атаки. Системы семейства NT долгое время вообще не позволяли "вручную" формировать сетевые пакеты и потому атаки типа Land, Teardrop и Bonk осуществить с их помощью было невозможно (правда, это еще не означает, что NT устойчива к таким атакам). Не этим ли обстоятельством вызвана патологическая любовь большинства хакеров к UNIX? Правда, сегодня только ленивый не найдет NDIS-драйвер к NT, позволяющий работать с TCP/IP пакетами на низком уровне, так что репутация UNIX как чисто хакерской платформы в скором будущем обещает пошатнуться.

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

Нашумевшая дыра, связанная с передачей shell-кода в строку редактирования привилегированного процесса с последующей установкой таймера, выполняющего этот код в адресном пространстве и с привилегиями атакуемого процесса, в настоящее время по заверениям Microsoft уже устранена.


Подробности рецепта "лечения" в момент написания этих строк еще не известны, но по всей видимости они сводятся к проверке адреса таймерной процедуры - она не должна находится в буфера какого бы то ни было окна. Ну, еще быть может, запретили передавать сообщение WM_TIMER более привилегированным процессам. Полностью же запретить (или защитить) межпроцессорную рассылку сообщений невозможно, поскольку она является частью философии оконной подсистемы Windows и любые попытки внесения каких бы то ни было ограничений не замедлят столкнуться с проблемами совместимости и приведут к неработоспособности большого количества прикладных программ.

Оконная подсистема UNIX хороша тем, что, не является неотъемлемой частью системы и при желании от нее можно отказаться, ограничившись надежным и безопасным текстовым режимом. К тому же, обмен сообщениями в графических оболочках UNIX обычно осуществляется по протоколам TCP/IP, которые защищают окна и элементы управления одного процесса от посягательств всех остальных (если, конечно, сам процесс-владелец этого не захочет).

Итак: межпроцессорный обмен в и UNIX, и в NT выполнен очень плохо и потому не безопасен, причем, адекватных средств защиты от рассмотренных выше атак, ни в близком, ни в отдаленном будущем по видимому не появится, т. к. "собака зарыта" на уровне базовых концепций и философии той и другой системы. А философию очередной заплатой не поменяешь.


Open Source vs дизассемблер


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

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

Действительно, защитный механизм, принцип действия которого неизвестен, может быть взломан только грубой силой, то есть имеет вполне предсказуемую степень защищенности. Поэтому, любая мало-мальски серьезная акция начинается с изучения атакуемого объекта (целенаправленный взлом). Отсюда: при прочих равных условиях степень защищенности системы обратно пропорционально легкости анализа ее кода. А легкость самого анализа в первую очередь определяется доступностью исходных текстов защитного механизма!

Большинство UNIX'ов поставляются вместе с исходными текстами, в то время как исходные тексты NT недоступны, а анализ дизассемблерных листингов не только чрезвычайно трудоемок и утомителен сам по себе, но еще и требует изрядной профессиональной подготовки, которая есть далеко не у всех. К тому же подсистема защиты NT много сложнее аналогичной подсистемы большинства UNIX'ов и весьма поверхностно документирована, чем и отпугивает многих потенциальных злоумышленников.

Как следствие: количество дыр, обнаруженных в NT за все время ее существования, можно свободно пересчитать по пальцам одной руки (причем, большая часть из них была обнаружена практически случайно). В UNIX же, напротив, дыры обнаруживаются постоянно. С другой стороны..



Повышение своих привилегий


Модель привилегий пользователей и механизмы контроля прав доступа, - ключевое и вместе с тем наиболее уязвимое (по статистике) звено подсистемы безопасности любой многопользовательской ОС. В общем случае к ней предъявляются следующие требования:

а) модель пользователей должна быть достаточно гибкой, удобной и интуитивно понятной, в противном же случае ошибки администрирования - неизбежны;

б) механизмы контроля прав доступа должны не только гарантировать невозможность не санкционирования повышения уровня своих привилегий, но и быть максимально устойчивыми к программистским ошибкам;

в) и сама система, и работающие в ней пользователи должны обходится минимально необходимым уровнем привилегий.

Анализ показывает, что перечисленные выше требования не выполняются ни в одной ОС массового назначения, а потому все они в той или иной степени заведомо уязвимы. Между тем, степень защищенности UNIX и NT различна.

Модель привилегий пользователей, применяемая в большинстве UNIX, является одноуровневой и допускает существование только двух типов пользователей: обычные пользователи и суперпользователь (он же root или администратор). В NT же, напротив, используется иерархическая схема, причем, помимо root'а в ней имеется еще один суперпользователь, - система. Что это означает? А то, что в NT, в отличии от UNIX, каждый пользователь получает минимум необходимых ему прав и никогда не повышает уровень своих привилегий без особой необходимости. Широко распространенное заблуждение гласит, что правильное администрирование UNIX позволяет добиться такого же точно распределения прав доступа, как и в NT, пускай и ценой большего времени и усилий. На самом же деле это не так.

Отсутствие системного пользователя в UNIX приводит к невозможности выполнения целого ряда действий иначе, чем временным повышением привилегий запущенной программы до root'a. Взять хотя бы классическую задачу смены пароля. Пользователи могут (и должны!) периодически менять свои пароли. Но ведь в UNIX (как впрочем и в NT) пароли всех пользователей хранятся в одном файле, причем, используемая модель привилегий не позволяет назначать различным частям файла различные права доступа.
Но ведь должен пользователь как- то изменять свой пароль, верно? В UNIX эта задача решается так: утилите, ответственной за смену пароля, присваивается специальный атрибут, позволяющий ей при необходимости получать права root'а, что она, собственно, и делает. Если бы этот механизм использовался только при операциях с паролями большой беды и не было бы. На самом же деле, такой атрибут необходим очень большому количеству приложений, в частности WEB и e-mail серверам. Задумайтесь, что произойдет, если в одной из программ, исполняющихся с наивысшими привилегиями, обнаружится ошибка, так или иначе приводящая к возможности передачи управления хакерскому коду? А ведь такие ошибки сыплются из UNIX'ых программ как из рога изобилия!

Совершенно иная ситуация складывается в среде NT. Непривилегированные пользователи только в исключительных случаях вынуждены повышать свои права до уровня администратора, а все остальное время они пользуются API-функциями операционной системы, выполняющими потенциально опасные действия "руками" самой ОС. Даже если в одном из таких приложений будет допущена ошибка и хакер захватит управление, - он унаследует минимум прав и причинит система минимум вреда.

Таким образом, NT устойчива к программистским ошибкам, а UNIX чрезвычайно чувствительна к ним.


Сводная таблица


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

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



Удаленный доступ: оружие пролетариата?


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

Никто не спорит - удаленно управлять сервером очень удобно, но давайте задумаемся - насколько это безопасно? Увы, никакое удобство не проходит даром! Что комфортно администрировать, то комфортно и атаковать! Этому, кстати, будут способность и продвинутые командные интерпретаторы, поддерживающие полноценные языки программирования, разительно отличающие от того уродства, что переваривает примитивная оболочка NT. Вообще же, в NT удаленным доступом очень мало что можно сделать (правда, начиная с Windows 2000 в ней все-таки появилось более или менее совершенные механизмы удаленного управления).

Тем не менее не стоит впадать в крайности и полностью отказываться от возможности удаленного администрирования. Конечно, полностью запретив удаленный доступ вы в значительной степени усилите защищенность своего сервера, но. при этом будете вынуждены постоянно находится непосредственно рядом с сервером. Спрашиваете: зачем? А кто хакеров будет гонять?! Ведь проникнуть на атакуемую машину можно через любой, установленный на ней сервис (скажем, WEB) и потому крайне нежелательно лишать себя всех средств дистанционного мониторинга и управления сервером.

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



Угроза переполнения буфера


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

а) другие буфера и переменные программы;

б) служебные данные - в частности, адрес возврата из функции;

в) исполняемый код;

г) незанятая или д) отсутствующая страница памяти.

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

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

Все системы: и UNIX, и NT потенциально допускают существование пунктов а), б), г) и д), исключая лишь единственный из них - пункт в). Следовательно, они в равной мере подвержены угрозе переполнения буфера. Кроме того, и UNIX, и NT имеют исполняемый стек (то есть разрешают выполнение кода в стеке) и запрещают его выполнение в сегменте данных. А это значит, что переполнение буферов, содержащихся в автоматических (т.е. стековых) переменных несет в себе угрозу полного захвата управления над уязвимой программой. Правда, для некоторых UNIX существуют заплаты, отнимающие у стека право выполнения, но сфера их применения весьма ограничена (исполняемый стек необходим множеству вполне легальных программ, в частности, компиляторов).

Самое забавное, что и UNIX, и NT написаны на Си - языке программирования, не поддерживающим автоматический контроль границ массива и потому подверженному ошибкам переполнения. Старожилы говорят, что в некоторых версиях UNIX ошибка переполнения присутствовала даже на вводе имени пользователя при регистрации в системе.



UNIX

качество и полнота документирования

документирована поверхностно

документирована весьма обстоятельно

доступность исходных текстов

исходные тексты недоступны

исходные тексты доступны

сложность анализа

высокая

умеренная

распространенность

существует весьма ограниченное количество представителей NT, причем наблюдается ярко выраженная преемственность дыр от одних версий системы к другим

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

сложность кода

код излишне сложен

код предельно прост

поддержка удаленного администрирования

частично поддерживает

поддерживает

комплектность штатной поставки

содержит минимум необходимых приложений

содержит огромное количество приложений, в том числе и не протестированных

механизмы аутентификации

устойчив к перехвату паролей

передает открытый пароль

использование привязки

не использует

использует

выполнение привилегированных операций

выполняется операционной системой

выполняется самим приложением со временным повышением привилегий

модель пользователей

иерархическая

одноуровневая

защита от переполнения буфера

отсутствует, причем сама ОС написана на языке провоцирующим такие ошибки

отсутствует, причем сама ОС написана на языке провоцирующим такие ошибки

возможность доступа в адресное пространство чужого процесса

имеется, разрешена по умолчанию

отсутствует

возможность отладки процессов

имеется, разрешена по умолчанию

имеется, но связана с рядом ограничений

возможность отладки активных процессов

имеется, но требует наличия соответствующих привилегий

отсутствует

удаленный доступ к именованным каналам

есть

нет

создание подложных именованных каналов

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

есть, можно создать лишь подложный канал

защита именованных каналов от нежелательных подключений

отсутствует

отсутствует

защита сокетов от нежелательных подключений

отсутствует

отсутствует

возможность эмуляции ввода в более привилегированный процесс

имеется

отсутствует



UNIX - это просто!


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

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

Между тем, ошибки крайне неоднородны по своей природе: одни лежат, что называется на поверхности, и обнаруживаются даже автоматизированными средствами контроля качества кода; другие же, напротив, зарыты так глубоко, что найти их можно только случайно. Фундаментальная проблема отладки заключается в том, что любая, даже самая незначительная модификация программного кода, чревата появлением каскада ошибок, возникающих в самых неожиданных местах. И потому, внесение каких бы то ни было изменений во внутренности операционной системы и/или сопутствующих ей приложений должно сопровождаться полным циклом повторного тестирования. Но ведь полное тестирование, как уже было показало выше, выполнить просто невозможно!

Чрезмерная сложность NT вкупе с огромным количеством изменений, вносимых в код каждой новой версии, собственно и объясняют скверное качество ее тестирования. Несмотря на все усилия, предпринимаемые Microsoft, уязвимость NT заложена уже в самой политике ее развития, а потому является принципиально неустранимой, т.е. фундаментальной.

Большинство UNIX'ов напротив, довольно компактны и содержат минимум необходимых для функционирования системы компонентов (или, во всяком случае, позволяют урезать себя до такого состояния). К тому же их медленное, эволюционное (а не революционное как у NT) развитие отнюдь не способствует появлению грубых, легко обнаруживаемых ошибок, которыми так славится NT.



Степень защищенности вашего компьютера во


Степень защищенности вашего компьютера во многом зависит от совершенства установленной на нем операционной системы. Несколько утрируя можно сказать: что максимально достижимая защищенность узла никогда не превосходит степени защищенности самой ОС (разумеется, при условии, что узел не оснащен никакими внешними защитами, такими например, как брандмаузер).
Представляется логичным протестировать несколько популярных систем, отобрать из них наиболее защищенную и. Тут-то и выясняется, что:
а) такого тестирования еще никто не проводил, во всяком случае, материал найденный по этой теме в Сети, носит субъективный и поверхностный характер, сильно завязанный на непринципиальных недостатках конкретных реализаций ОС, большая часть из которых давным-давно исправлена очередной заплатой;
б) если семейство NT представлено всего тремя операционными системами: самой NT, Windows 2000 и Windows XP с практически идентичными архитектурами, то пестрота UNIX-подобных систем вообще не поддается описанию;
в) очень трудно выбрать адекватные критерии защищенности: количество зафиксированных взломов данной ОС - это не совсем тот показатель, который нам нужен: во-первых, точной статистики у нас нет и не может быть в принципе (по настоящему успешные взломы как правило не регистрируются), а, во-вторых, статистика такого рода отражает не защищенность, а распространенность тех или иных систем и в значительной степени искажена преобладающим интересом хакеров (попросту говоря модой); количество обнаруженных дыр - само по себе еще ни о чем не говорит (уже хотя бы по указанным выше причинам).
Поэтому мы решили абстрагироваться от особенностей конкретных реализаций, и сравнить потенциальную концептуальную уязвимость операционных систем семейств NT и UNIX. Что такое "потенциальная уязвимость"? Это такое свойство архитекторы системы, которое при определенных обстоятельствах с той или иной вероятностью может привести к снижению степени ее защищенности. В частности, сложность считается одной из потенциальных концептуальных уязвимостей и при прочих равных условиях менее сложная система объявляется более защищенной и, соответственно, наоборот. Кончено, помимо сложности (кстати, уровень сложности измеряется не объемом программного кода, а количеством взаимосвязей между отдельными компонентами программы), большую роль играет профессионализм разработчиков, качество тестирования и т. д. Однако, поскольку все эти факторы практически не поддаются объективному учету (только не надо пожалуйста говорить, что LINUX тестируют миллионы людей по всему миру, - знаем-знаем мы как они ее тестируют), лучше их вообще учитывать, чем учитывать неправильно.
Так же, мы будет рассматривать лишь концептуальные уязвимости, - т. е. такие, которые настолько глубоко зарыты в системе, что без серьезного хирургического вмешательства в архитектуру ядра их не удалить. (Да и не получим ли мы после такой операции совершенно другую операционную систему?).

приведенная выше таблица неопровержима доказывает


Не правда ли, забавно, - NT защищена намного слабее ( приведенная выше таблица неопровержима доказывает это), но ломают чаще всего все-таки UNIX, а не NT. Парадокс? Или все-таки отсутствие исходных текстов дает о себе знать? Во всяком случае, других причин мы просто не видим. Единственное, что можно предположить: NT ломают, но в силу успешности взлома (и уязвимости самой системы) эти взломы просто не удается зафиксировать. В общем, здесь есть пища для размышлений!
Во избежание многословия под "NT" если только явно не оговорено обратное здесь и далее будет подразумеваться все NT-подобные системы: сама Windows NT, Windows 2000 и Windows XP.

Алгоритмы процесса обфускации


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

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

Алгоритм Колберга ("Collberg`s algorithm").

Данный алгоритм оперирует следующими входными значениями:

программа "А" состоящая из исходных или объектных (двоичных) файлов "{С1,С2}". стандартные библиотеки, используемые программой "{L1,L2}". набор трансформирующих процессов "Т{Т1,Т2}". определенный фрагмент кода "S", который извлекается из программы "А", и который непосредственно будет подвержен трансформации. набор функций "Е{Е1,Е2}" которые будут определять эффективность применения определенных трансформирующих процессов "{Т1,Т2}" к фрагменту кода "S". набор функций "I{I1,I2}" которые будут определять важность фрагмента кода "S", и в зависимости от этого будут задавать определенное значение переменной "RequireObfuscation" (чем "S" важнее тем эта переменная будет хранить большее значение). две числовые переменные "AcceptCost" > 0, "RequireObfuscation" > 0, где первое хранит информацию о доступном максимальном увеличении системных ресурсов по требующихся программе "А" после того как она подвергнется обфускации, а вторая переменная будет хранить значение требуемого уровня осуществления обфускации (чем важнее фрагмент кода "S", тем это значение должно быть больше).


Алгоритм Колберга имеет такую последовательность операций:
Загрузка элементов "{С1,С2}" программы "А". Загрузка библиотек "{L1,L2}". Осуществление обфускации над программой "А", путем выделения фрагмента кода "S" и определения наиболее эффективного процесса трансформации для него. Этот этап повторяется до тех пор, пока не будет, достигнут требуемый уровень обфускации "RequireObfuscation" или допустимое увеличение ресурсов "AcceptCost". Генерация трансформируемой программы "А`".
Алгоритм Колберга считается общим алгоритмом осуществления !процесса обфускации (то есть он не определяет, как именно должен осуществляться, тот или иной !метод обфускации), ниже будет рассмотрен более специализированный алгоритм, так как он описывает последовательность осуществления одного из методов обфускации, а именно обфускации управления.
Chenxi Wang`s алгоритм.
В качестве входных данных алгоритм принимает типичную процедуру, написанную на языке высокого уровня. Процесс обфускации каждой такой процедуры состоит из трех этапов:
создание графа потока управления этой процедуры (граф задаётся множеством блоков и множеством связей соединяющих их), после чего граф разбивается, путем замены циклических конструкций в нем на конструкции типа "if (условие) goto", ().
нумерация всех блоков в графе, и добавление в код процедуры переменной (например "swVar") хранящей номер следующего выполняемого блока приведение графа к однородному ("плоскому") виду ()
Выше описанный вариант алгоритма обфускации ("Chenxi Wang`s algorithm") является не сильно устойчивым, так как определить следующий выполняемый блок, нетрудно (он в нашем случае будет храниться в переменной "swVar"). Поэтому для повышения его устойчивости вводят массив (например "@gg"), содержащий помимо номеров блоков, не нужную информацию, в результате запись "$swVar = S6", можно заменить на нечто подобное "$swVar = $gg[$gg[1] + $gg[3]]".

DOWN THE RABBIT HOLE.


Быстрое развитие мультимедиа и Интернет технологий в последние годы вызывает потребность в защите такой интеллектуальной собственности, как программные продукты (ПП).

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

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

Существуют два основных способа защиты интеллектуальной собственности, и следовательно, самих программных продуктов:

1) Юридический (законный). Данный способ защиты заключается в создании определенных актов, в соответствии с законом, которые будут охранять интеллектуальную собственность (в нашем случае программные продукты) от нелегального использования. Данный способ включает в себя такие методы как патентование, оформление авторских прав на интеллектуальную собственность и т.д. Также он предусматривает возможность лицензирования ПП, так, например большинство ПП поставляются вместе с лицензией, которая подтверждает право пользователя использовать этот ПП, то есть, покупая лицензионную копию программы, пользователь в некой мере производит покупку лицензии на право работы с ее копией. Можно выделить два основных вида лицензий на программные продукты:

Временная. Позволяет использовать ПП неограниченному числу пользователей в течение ограниченного периода времени. Оптимальная. Позволяет использовать ПП ограниченному числу пользователей в течение неограниченного периода времени.

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

Ниже приводится поверхностное описание наиболее распространенных на данный момент методов защиты ПП.



Лексическая обфускация


Наиболее простая, заключается в форматировании кода программы, изменении его структуры, таким образом, чтобы он стал нечитабельным, менее информативным, и трудным для изучения.

Обфускация такого вида включает в себя:

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

Изменение глобальных имён идентификаторов следует производить в каждой единице трансляции (один файл исходного кода), так чтобы они имели одинаковые имена (в противном случае защищаемая программа может стать не функциональной). Также следует учитывать специфические идентификаторы, принятые в том языке программирования, на котором написана защищаемая программа, имена таких идентификаторов, лучше не изменять, например, в PERL-е к таким идентификаторам можно отнести "@ARGV", "$_", "$^O" и т.д.

Ниже представлен пример фрагмента исходного кода программы (написанной на Perl), до и после прохождения лексической обфускации.

До лексической обфускации:

my $filter;

if (@pod) { my ($buffd, $buffer) = File::Temp::tempfile(UNLINK => 1); print $buffd ""; print $buffd @pod or die ""; print $buffd close $buffd or die ""; @found = $buffer; $filter = 1; } exit;

sub is_tainted { my $arg = shift; my $nada = substr($arg, 0, 0); # zero-length local $@; # preserve caller's version eval { eval "#" }; return length($@) != 0; }

sub am_taint_checking { my($k,$v) = each %ENV; return is_tainted($v); }

После лексической обфускации:

sub z109276e1f2 { ( my $z4fe8df46b1 = shift ( @_ ) ) ; ( my $zf6f94df7a7 = substr ( $z4fe8df46b1 , (0x1eb9+ 765-0x21b6) , (0x0849+ 1465-0x0e02) ) ) ; local $@ ; eval { eval ( ( "" ) ) ; } ; return ( ( length ( $@ ) != (0x26d2+ 59-0x270d) ) ) ; } my ( $z9e5935eea4 ) ; if ( @z6a703c020a ) { ( my ( $z5a5fa8125d , $zcc158ad3e0 ) = File::Temp::tempfile ( "" , (0x196a+ 130-0x19eb) ) ) ; print ( $z5a5fa8125d "" ) ; ( print ( $z5a5fa8125d @z6a703c020a ) or die ( ( ( ( "" . $zcc158ad3e0 ) . "\x3a\x20" ) . $! ) ) ) ; print ( $z5a5fa8125d "" ) ; ( close ( $z5a5fa8125d ) or die ( ( ( ( "" ) ) ) ; ( @z8374cc586e = $zcc158ad3e0 ) ; ( $z9e5935eea4 = (0x1209+ 1039-0x1617) ) ; } exit ; sub z021c43d5f3 { ( my ( $z0f1649f7b5 , $z9e1f91fa38 ) = each ( %ENV ) ) ; return ( z109276e1f2 ( $z9e1f91fa38 ) ) ; }

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



Обфускация данных


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

Обфускация хранения. Заключается в трансформации хранилищ данных, а также самих типов данных (например, создание и использование необычных типов данных, изменение представления существующих и т.д.). Ниже приведены основные методы, позволяющие осуществить такую обфускацию:

изменение интерпретации данных определенного типа. Как известно сохранение, каких либо данных в хранилищах (переменных, массивах и т.д.) определенного типа (целое число, символ) в процессе работы программы, очень распространенное явление. Например, для перемещения по элементам массива очень часто используют переменную типа "целое число", которая выступает в роли индекса. Использование в данном случае переменных иного типа возможно, но это будет не тривиально и может быть менее эффективно. Интерпретация комбинаций разрядов содержащихся в хранилище данных осуществляется в зависимости от его типа. Так, например, можно сказать, что 16-разрядная переменная целого типа содержащая комбинации разрядов 0000000000001100 представляет целое число 12, но это простое соглашение, данные в такой переменной можно интерпретировать по-разному (не обязательно как 12, а, например как 1100 и т.д.).

изменение срока использования хранилищ данных, например переход от локального их использования к глобальному и наоборот. В качестве примера можно привести две различные функции (язык PERL): sub func1 { ... $a ... ; } sub func2 { ... $b ... ; }

если эти две функции не могут выполняться в процессе программы одновременно, значит, для них может быть создана одна глобальная переменная, которая будет замещать переменные $a,$b, например: $AB = 0 ; sub func1 { ... $AB ... ; } sub func2 { ... $AB ... ; }

преобразование статических (неменяющихся) данных в процедурные. Большинство программ, в процессе работы, выводят различную информацию, которая чаще всего в коде программы представляется в виде статических данных таких как строки, которые позволяют визуально ориентироваться в ее коде и определять выполняемые операции.
Такие строки также желательно предать обфускации, это можно сделать, просто записывая каждый символ строки, используя его ASCII код, например символ "A" можно записать как 16-ричное число "0х41", но такой метод банален. Наиболее эффективный метод, это когда в код программы в процессе осуществления обфусации добавляется функция, генерирующая требуемую строку в соответствии с переданными ей аргументами, после этого строки в этом коде удаляются, и на их место записывается вызов этой функции с соответствующими аргументами. Например, фрагмент кода (написанный на PERL): print "LOL\n" ; $var = "101" ; после обфускации, будет похож на что-то вроде: sub string { my ($i) = @_ ; my $k = 0 ; $str = "" ; while (1) { l1: if ($i == 1) {$str .= "L";$k = 0;goto l7;} l2: if ($i == 4) {$str .= "S";$k = 0;goto l7;} l3: if ($i == 3) {$str .= "1";$k = -1;goto l7;} l4: if ($i == 4) {$str .= "m";$k = 3;goto l7;} l5: return $str; l6: if ($k == 0) {$str .= "1";$k += 2;goto l5;} else {$str .= "L";$k -= 1;goto l5;} l7: if ($k < 1) {$str .= "0";$k++;goto l6;} } } ...

print string(1)."\n" ; $var = string(3) ;

Также к статическим данным относятся числовые константы, которые могут быть также трансформированы, например число 1 можно представить как: (a + 1 - b), где a = b;

разделение переменных. Переменные фиксированного диапазона могут быть разделены на две и более переменных. Для этого переменную "V" имеющую тип "x" разделяют на "k" переменных "v1,...,vk" типа "y" то есть "V == v1,...,vk". Потом создается набор функций позволяющих извлекать переменную типа "x" из переменных типа "y" и записывать переменную типа "x" в переменные типа "y". В качестве примера разделения переменных, можно рассмотреть способ представления одной переменной "B" логического типа (boolean) двумя переменными "b1, b2" типа короткого целого (short), значение которых будет интерпретироваться таким образом:



B | b1 | b2 ---------------- false | 0 | 0 true | 0 | 1 true | 1 | 0 false | 1 | 1

Тогда такой фрагмент кода (написан на С++):

bool B ; B = false ; if (B) {...}

будет представлен так:

short b1, b2 ; b1 = b2 = 1 ; // или b1 = b2 = 0 if (!(b1 & b2)) {...}

изменение представления (или кодирование). Например, целочисленную переменную "i", в ниже представленном фрагменте кода (написанном на С):

... int i = 1; ... while (i < 1000) { ... A[i] ... i++ ; }

можно заменить, выражением "i` = c1*i + c2" где "c1,c2" являются константами, в результате, фрагмент выше приведенного кода измениться и будет сложен для восприятия:

... int i = 11; int c1 = 8, c2 = 3 ; ... while (i < 8003) { ... A[(i - 3)/8] ... i += 8 ; }

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

объединение переменных. Две или более переменных "v1,...,vk" могут быть объединены в одну переменную "V", если их общий размер ("v1,...,vk") не превышает размер переменной "V". Например, рассмотрим простой пример объединения двух коротких целочисленных переменных "X","Y" (размером 16 бит) в одну целочисленную переменную "Z" (размером 32 бита). Для этого воспользуемся формулой Z(X,Y) = 2^16 * Y + X

которая позволит, пренебрегая сложением, определять значение Y, т.е. пусть X = = 12, Y = 4 => Z = 65536 * 4 + 12 = 262156, теперь зная "Z" для нахождения "Y" можно 262156 / 65536 = 4.000183105 или приблизительно 4. При осуществлении арифметических операций над значениями переменных "X", "Y" хранящихся в "Z" нужно учитывать выше приведенную формулу, т.е.: Z(X+n,Y) = 2^16 * Y + (X + n) = Z(X,Y) + n ; Z(X,Y-n) = 2^16 * (Y - n) + X = 2^16 * Y - 2^16 * n + X = = Z(X,Y) - 2^16 * n ; и т.д.


В результате код до обфускации (язык Си):

short X = 12, Y = 4 ; X += 5 ;

трансформируется в:

int Z = 262156 ; Z += 5 ;

реструктурирование массивов, заключается в запутывании структуры массивов, путем разделения одного массива на несколько подмассивов, объединения нескольких массивов в один, сворачивания массива (увеличивая его размерность) и наоборот, разворачивая (уменьшая его размерность). Например, один массив "@A" можно разделить на несколько подмассивов "@A1, @A2", при этом один массив "@A1" будет содержать четные позиции элементов, а второй "@A2" нечетные позиции элементов массива "@A". Поэтому такой фрагмент кода (PERL):

@A = qw{a b c d e f} ; $i = 3 ; $A[$i] = ... ;

можно заменить на:

@A1 = qw{2 4 0} ; @A2 = qw{1 3 5} ; $i = 3 ; if (($i % 2) == 0) { $A1[$i / 2] = ... ; } else { $A2[$i / 2] = ... ; }

Под сворачиванием массива понимается создание из одномерного массива, двумерного. Например, одномерный массив "A" из предыдущего примера, имеющий размер 5 можно заменить двумерным массивом "B" размером 2, после чего код (язык С++):

int A[] = {1, 2, 3, 4, 5, 6} ; for (int i = 0 ; i < 6 ; i++) { A[i] = A[i] + 1 ; printf("%d\n", A[i]) ; }

можно изменить на:

int A[2][3] = {{1,2,3}, {4,5,6}} ; for (int i = 0 ; i < 2 ; i++) { for (int ii = 0 ; ii < 3 ; ii++) { A[i][ii] = A[i][ii] + 1 ; printf("%d\n", A[i][ii]) ; } }

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

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


Обфускация и защита программных продуктов.



/close your eyes & dream with me/


07.10.2004

Содержание:


5.1

   5.2

   5.3

   5.4





- When _I_ use a word, - Humpty Dumpty said in
rather a scornful tone, - it means just what I

choose it to mean - neither more nor less.



Обфускация, как один из методов защиты программ


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

Обфускация ("obfuscation" - запутывание), это один из методов защиты программного кода, который позволяет усложнить процесс реверсивной инженерии кода защищаемого программного продукта.

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

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

Из этого следует, что обфускация одна не предназначена для обеспечения наиболее полной и эффективной защиты программных продуктов, так как она не предоставляет возможности предотвращения нелегального использования программного продукта. Поэтому обфускацию обычно используют вместе с одним из существующих методов защиты (шифрование программного кода и т.д.), это позволяет значительно повысить уровень защиты ПП в целом (, "Т1,Т2,...,Tn" - процессы обфускации).

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

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



Обфускация управления


Обфускация такого вида осуществляет запутывание потока управления, то есть последовательности выполнения программного кода.

Большинство ее реализаций основывается на использовании непрозрачных предикат, в качестве, которых выступают, последовательности операций, результат работы которых сложно определить (само понятие "предикат" выражает свойство одного объекта (аргумента), или отношения между несколькими объектами).

Определение. Предикат "Р" считается непрозрачным предикатом, если его результат известен только в процессе обфускации, то есть после осуществления процесса обфускации, определение значения такого предиката, становится трудным.

Обозначим непрозрачный предикат, возвращающий всегда значение TRUE как "Р(t)", а возвращающий значение FALSE, как "Р(f)", тогда непрозрачный предикат, который может возвратить любое из этих двух значений (то есть или TRUE, или FALSE, что нам неизвестно) как "Р(t,f)". Эти обозначения, будут использоваться дальше в контексте описания обфускации управления. Непрозрачные предикаты могут быть:

локальными - вычисления содержаться внутри одиночного выражения (условия), например (запись "(f)" после условия проверки, указывает, что это предикат типа "P(f)"):

if (($a * $b) == (101-303))(f) {...} глобальными - вычисления содержаться внутри одной процедуры (функции), например (PERL): sub func { $ab=$a*$b ; ... $val=101-303 ; ... if ($ab == $val)(f) {...} }

межпроцедурными - вычисления содержаться внутри различных процедур (функций): ... $ab ... ; ... $val ... ; sub func1 { $ab=$a*$b; ... } sub func2 { $val=101-303; ... } ... if ($ab == $val)(f) {...} ...

Рассмотрим простые примеры трансформации фрагмента кода программы с помощью непрозрачных предикатов,

На рисунке 0110(1) один блок программы "(A)", разбит (трансформирован) на несколько независимых блоков "(A1; A2)", которые соединены по средствам непрозрачного предиката возвращающего всегда значение TRUE "Р(t)".
В результате трансформации такого рода возникает представление того, что блок "А2" выполняется не всегда, поэтому для того чтобы определить условия выполнения блока "А2", злоумышленнику прежде придется узнать значение, которое возвращает используемый непрозрачный предикат "Р(t)".

На рисунке 0110(2) помимо блока "А2", используется еще один блок "А2" над которым был произведен процесс обфускации (обозначим его как "А2`"), то есть эти два блока ("А2" и "А2`") имеют различный код, но выполняют одинаковые функции, следовательно, можно утверждать, что "А2 = А2`", и поэтому неважно какой из этих блоков будет выполнен в процессе работы программы, из этого следует, что для соединения блока "А1" с "А2" и "А2`" эффективно будет использовать непрозрачный предикат, который может возвратить любое из значений, а именно TRUE или FALSE "Р(t,f)".

И на рисунке 0110(3) используется новый блок "А3", который содержит произвольный набор, каких либо операций (недостижимый код), это может позволить сбить с толку злоумышленника, так как сами блоки "А1" и "А2" соединены по средствам непрозрачного предиката возвращающего всегда значение FALSE "Р(f)".



Рисунок 0110. Использование простых непрозрачных предикатов

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



Основная идея устойчивых непрозрачных предикатов состоит в том, что в программу, в процессе обфускации добавляется код, который создает набор динамических структур, а также глобальных указателей, которые будут ссылаться на различные элементы внутри этих структур. Помимо этого, данный код должен иногда обновлять эти структуры (добавлять новые элементы в них, объединять или разделять некоторые их них, изменять значения глобальных указателей, и т.д.), но таким образом, чтобы при этом были сохранены некоторые условия, например "указатель p и q никогда не будут указывать на один и тот же элемент" или "указатель p может ссылаться (указывать) на указатель q" и т.д. Эти условия в последствии позволяют создавать требуемые непрозрачные предикаты.

На рисунке 0111, представлен пример использования устойчивых непрозрачных предикатов. На начальном этапе работы программы, код который был в нее добавлен в процессе обфускации, создает динамическую структуру "struct", и два глобальных указателя "p, q" которые указывают на произвольные элементы, внутри этой структуры, "Рисунок 0111(1)", поэтому для этих указателей справедливо, что условие:

if (p==q) { ... }

соответствует предикату "Р(t,f)".

На следующих этапах процедура "Insert()" добавляет в эту структуру новый элемент, "Рисунок 0111(2)", и изменяет значение указателя "q", "Рисунок 0111(3)", при этом условие для указателей "p, q" продолжает оставаться неизменным.

После выполнения следующей процедуры, происходит разделение динамической структуры, на две отдельные, таким образом, что указатели "p, q" теперь указывают на элементы, которые находятся в различных структурах, "Рисунок 0111(4)", и поэтому для них теперь справедливо иное условие:

if (p==q) { ... }

Которое соответствует предикату "Р(f)".



Рисунок 0111. Использование устойчивых непрозрачных предикатов

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


При этом существующие алгоритмы статического анализа становятся не эффективны.

Методы позволяющие осуществить обфускацию управления, классифицируются на три основных группы:

Обфускация вычислительная. Изменение касающиеся главной структуры потока управления. К ним можно отнести: расширения условий циклов. Для этого обычно используют непрозрачные предикаты, таким образом, чтобы они не коим образом не влияли на количество выполнений циклического кода. Например, фрагмент кода (PERL):

$i = 1 ; while ($i < 101) { ... $i++ ; }

после расширения условия цикла, станет:

$i = 1 ; $j = 100 ; while (($i < 101) && ($j * $j * ($j + 1) * ($j + 1)%4 == 0)(t)) { ... $i++ ; $j = $j * $i + 3 ; }

добавления недостижимого кода, (который не будет выполняться в процессе работы программы) (рисунок 0110(3)). устранение библиотечных вызовов. Большинство программ, используют функции, которые определены в стандартных библиотеках исходного языка, на котором писалась программа (например, в Си это библиотека "libc"), работа таких функции хорошо документирована и часто известна злоумышленникам, следовательно, их присутствие в коде программы, может помочь в процессе ее реверсивной инженерии. Поэтому имена функций из стандартных библиотек, также желательно придать обфускации, т.е. изменить на наиболее бессмысленные, которые потом будут фигурировать в коде защищаемой программы. Один из способов решения такой проблемы, заключается в использовании в программе собственных версии стандартных библиотек (которые получаются в результате переименовывания всех функций в оригинальной стандартной библиотеке), это не изменит существенно время выполнения программы. Но для того, чтобы такая программа была переносимой, и могла использоваться многими пользователями, ее нужно будет поставлять вместе с измененной версией стандартной библиотеки, что значительно увеличит размер программы. Поэтому такой способ решения проблемы неэффективный. При осуществлении такой обфускации следует в первую очередь основываться на особенностях стандартной библиотеки исходного языка (то, как в ней взаимосвязаны имена функций с ихними кодами и т.д.).



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

$X = $X + $Y ;

может быть представлена:

$X = $X + $Y * $p - $r ;

где "$r == 0", "$p == 1".

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

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

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

... func1() ; ... func2() ; ...


sub func1 { # код func1 } sub func2 { # код func2 } ... можно получить:

... $V = $V*31337 / 13 ; # $V == 0 ... func12() ; ... $V += 7 ; # $V == 7 ... func12() ; ... sub func12 { if ($V) { # код func2 } else { # код func1 } } ...

клонирование, данный метод позволяет усложнить анализ контекста использования функций, и объектов используемых в коде исходной программы. Процесс клонирования функций состоит в выделении определенной функции "F", часто используемой в коде программы, после чего над кодом этой функции осуществляется трансформация, и создается ее клон "F`", который также будет добавлен в код исходной программы, при этом часть вызовов функции "F" в коде исходной программы, будет замещена на вызов функции "F`". В результате этого у злоумышленника создастся представление о том, что функции "F", и "F`" различны. Клонирование объектов осуществляется аналогичным способом.

трансформация циклов. Циклы встречаются в коде различных программ, и их также можно придать трансформации. Блокирование циклов, заключается в добавлении вложенных циклов в существующие, в результате работа существующих циклов будет заблокирована, на какой-то диапазон значений. Например, имея 2 цикла (PERL):

for ($i = 1 ; $i =< n ; $i++) { for ($ii = 1 ; $ii =< n ; $ii++) { $a[$i, $ii] = $b[$i, $ii] ; } } можно создать 4 цикла (функция "min" должна возвращать минимальное значение, одного из своих аргументов):

for ($I = 1 ; $I =< n ; $I += 64) { for ($II = 1 ; $II =< n ; $II += 64) { # первые два цикла будут заблокированы до тех пор, # пока не будут перебраны все значения "n" или # пока не будут перебраны все значения # из промежутка ($I,63) и ($II,63) for ($i = I ; $i =< min($I + 63, n) ; $I += 64) { for ($ii = II ; $ii =< min($II + 63, n) ; $ii++) { $a[$i, $ii] = $b[$i, $ii] ; } } } }

Развертка циклов, повторение тела цикла один или более раз (если количество выполняемых циклов известно в процессе осуществления обфускации (например, равно "N"), то цикл, может быть, развернут полностью, в результате повторения его тела в коде N раз):



for ($i = 1 ; $i =< n - 1 ; $i++) #PERL { # тело цикла }

после простой развертки:

for ($i = 1 ; $i < n - 1 ; $i++) { # тело цикла } # тело цикла

Разделение циклов, цикл состоящий из более чем одной независимой операции можно разбить на несколько циклов (которые должны выполняться одинаковое количество раз), предварительно разбив на несколько частей, его тело. Например, следующий цикл (PERL):

for ($i = 1 ; $i < n ; $i++) { $a[$i] += $c ; $x[$i+$i]=$d+$x[$i+1] * $a[$i] ; }

после разделения, может быть представлен: for ($i = 1 ; $i < n ; $i++) { $a[$i] += $c ; } for ($i = 1 ; $i < n ; $i++) { $x[$i+$i]=$d+$x[$i+1] * $a[$i] ; }

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

Обфускация последовательности. Заключается в переупорядочивании блоков (инструкций переходов), циклов, выражений.


Оценка процесса обфускации


Существует много методов определения эффективности применения того или иного процесса обфускации, к конкретному программному коду.

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

Устойчивость - указывает на степень сложности осуществления реверсивной инженерии над кодом прошедшим процесс обфускации. Эластичность - указывает на то насколько хорошо данный процесс обфускации, защитит программный код от применения деобфускаторов. Стоимость преобразования - позволяет оценить, насколько больше требуется системных ресурсов для выполнения кода прошедшего процесс обфускации, чем для выполнения оригинального кода программы.

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

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

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



Превентивная (prevent) обфускация


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

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



Процесс деобфускации


Когда мы говорим о процессе обфускации, появляется вопрос: есть ли процесс обратный ему, который позволил бы злоумышленнику вернуть наиболее похожий первоначальный код программы, то есть код до обфускации? На этот вопрос трудно дать однозначный ответ, но такой процесс существует и носит он название деобфускация. Но другой не менее важный вопрос, это как его можно реализовать.

С одной стороны к процессу деобфускации можно отнести процесс оптимизации программного кода, так как они оба, в той или иной степени, противоположны процессу обфускации. В процессе обфускации в программный код часто производиться добавление лишних операций, они обычно не коим образом не влияют на результаты работы самой программы, и предназначены для сбития с толку и усложнения процесса изучения кода программы потусторонними (BEYOND:) лицами.

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

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

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

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


Ниже представлен простой образец классификации методов процесса деобфускации:

нахождение и оценка непрозрачных конструкций (предикатов), статический анализ, которых очень сложен. сопоставление с образцом. Осуществляется различными способами, наиболее распространенны два из них. Первый, это когда берется несколько одних и тех же программ, прошедших процесс обфускации (так как процесс обфускации в большинстве случаев уникален, то их код также будет разный, хотя они и будут выполнять идентичные действия), и производиться сравнение фрагментов их кода, для выявления вставленного в процессе осуществления обфускации лишнего кода, который в последствии просто убирается. Второй способ сопоставления с образцом, осуществляется путем поиска в коде программы наиболее распространенных конструкций, применяемых в процессе обфускации. Такие конструкции могут, например, храниться и обновляться в соответствующей базе данных, или быть получены путем изучения работы самого обфускатора. выделение в программе фрагментов кода, которые никоим образом не связанны с основными задачами, которые должна выполнять программа, то есть обнаружение ненужных (лишних) участков кода. статистический анализ, заключается в динамическом анализе кода программы. Например, нахождение непрозрачных предикат может осуществляться путем выделения и дальнейшего изучения в анализируемом коде программы тех предикат, которые в процессе его выполнения возвращают всегда одно и тоже значение. Статистический анализ также может быть использован для оценки корректности осуществленного процесса деобфускации, для этого параллельно запускается программа "А" и программа, полученная в результате деобфускации "А`", им передаются эквивалентные входные данные, и происходит сравнение выходных. Если выходные данные одинаковы, то можно предположить, что процесс деобфускации был осуществлен правильно. анализ потока данных, основывается на изучении того, как в процессе работы программы изменяются в ней данные (переменные, массивы).



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

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

В свою очередь динамический анализ заключается в анализе/тестировании программы во время ее выполнения. Он считается точным, так как он исследует фактическое поведение программы, во время ее работы.

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

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


Процесс обфускации


Существуют различные определения процесса обфускации. Рассматривая данный процесс с точки зрения защиты ПП, и трансформации кода программы без возможности в последствии вернуться к его первоначальному виду (трансформация "в одну сторону"), можно дать такое определение:

Определение. Пусть "TR" будет трансформирующим процессом, тогда при "PR1 =TR=> PR2" программа "PR2" будет представлять собой трансформированный код программы "PR1". Процесс трансформации "TR" будет считаться процессом обфускации если, будут удовлетворены такие требования:

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

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

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


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

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

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

Также на сегодняшний день процесс низкоуровневой обфускации исследован мало (наверно потому что не успел получить широкой популярности).

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

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

Далее в тексте употребляются такие понятия: Исходная программа - защищаемая программа, подвергающаяся процессу обфускации. Злоумышленник - личность, занимающаяся изучением алгоритма работы исходной программы (реверсивной инженерией), для каких либо своих корыстных целей. Объект - имя какого-то хранилища данных, например переменной, массива и т.д. Деобфускация - процесс, который позволяет обойти обфускацию, используется злоумышленниками (деобфускация описана в отдельном разделе данного материала).


Шифрование программного кода.


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

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

Сам ключ обычно представляет собой последовательность байт (символов), который генерируется в результате определенных (математических) операций.

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

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

Электронный ключ представляет собой небольшое устройство, которое подсоединяется к одному из портов компьютера (COM,LPT,USB).

Но все же существует возможности обхода защиты программ зашифрованных с использованием электронных ключей, некоторые из них перечислены ниже:

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

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



Установка подлинности кода (tamper-proofing).


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

Это позволяет защитить программный продукт, от изменений со стороны злоумышленника (применения им крэков). Работа этой процедуры должна быть неприметной для тех, кто будет работать с программой, это позволит сбить с толку неопытных взломщиков. Также ее программная реализация не должна, иметь вид "if (programm_code_original()) { i = 1} else { i = 0}", так как такую процедуру проверки будет легко обойти, например для этого достаточно будет определить место, где она вызывается, и изменить само условие проверки. Процедура проверки должна быть разбита на как можно большее количество этапов, которые будут выполняться в разное время работы самой программы. Если все этапы проверки будут успешно пройдены, тогда можно будет предположить, что программа оригинальна, и не содержит дефектов (изменений). Существуют такие пути проверки целостности программы:

проверка идентичности оригинальной и запускаемой программы. Обычно для этого определяется контрольная сумма запущенной программы, которая потом сверяется с записанной в процедуру проверки, контрольной суммой оригинальной программы. Для осуществления быстрой проверки, используют такие алгоритмы: CRC или MD4/5 (алгоритмы резюмирования сообщений). проверка результатов работы программы. То есть осуществляется проверка выходных значений функций, которые очень чувствительны, к каким либо возможным изменениям в программном коде. создание запускаемой программы на лету, в соответствии с ее оригинальным образом. Это позволяет избежать возможности выполнения изменений внесенных в программу, так как они не будут учитываться при ее создании.



Виды обфускации


Процессы обфускации можно классифицировать по видам, в зависимости от способа модификации кода программы.



Водяной знак (software watermark) и отпечаток пальца.


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

Такая скрытая информация, обозначим ее "W" (которая и называется водяным знаком), должна быть записана в программу "Р", таким образом, чтобы:

"W" было надежно расположено (запрятано) в "Р", и могло быть впоследствии извлечено, без каких либо изменений (повреждений). "W" не влияло на работу "Р". "W" несло какую-то определенную информацию, которая позволит доказать, то что ее присутствие в "Р" неслучайное, то есть является результатом преднамеренных действий.

Также для увеличения эффективности водяного знака, его можно записать более чем один раз, в разных местах программы.

Отпечаток пальца (software fingerprint) эта иная технология, так как она кроме записи информации, позволяющей доказать интеллектуальное право собственности на программу, требует записи в каждую копию программы уникального идентификационного кода, присваиваемого каждому покупателю программы, что позволяет в последствии быстро отследить нарушителя авторского права, который, например, будет нелегально перепродавать программу (search and destroy them :).

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



Выполнение на стороне сервера.


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

Рисунок 0000. Выполнение на стороне сервера

Клиентскую часть можно распространять бесплатно, это позволит пользователям платить только за использование серверной части.

Часто данный метод защиты используется в различных программах-сценариях, которые располагаются на WEB серверах, и выполняют общие операции, например, контролируют работу других программ (front-end), а также передают им, какие либо данные для обработки.

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

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

Данный метод не позволяет защитить программу от нелегального копирования, поэтому после того как ее копия попадет к злоумышленнику, он сможет делать с ней что захочет (whatever you want :).



WHICH DREAMED IT?


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

Если Вы обнаружили какие-то недочеты, допущенные мной при создании данного материала, то Вы можете уведомить меня об этом (email: ), и я постараюсь их исправить.

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

P.S. Все ручейки пройдены. Удачи! (Удача не решающий фактор, но важный :)

/\ /\ @ @ ... `why your cat grins like that?' ... | ... `It's a Cheshire cat,' said the Duchess ... \___/

Список используемой литературы:

"A taxonomy of Obfuscating Transformations" , авторы Christian Collberg, Clark Thomborson, Douglas Low.

"General Method of Program Code Obfuscation", автор Gregory Wroblewski.

"Static and dynamic analysis: synergy and duality", автор Michael D. Ernst

"Анализ запутывающих преобразований программ", автор Чернов А. В.

"Software protection", авторы Christian S. Collberg, Clark Thomborson.

"ALICE'S ADVENTURES IN WONDERLAND", автор Lewis Carroll.
"Through the looking glass", автор Lewis Carroll.