Дэвид Лебланк - 19 смертных грехов, угрожающих безопасности программ
Рис. 12.1 . «Сокрытие» пароля в приложении, написанном на языке С или С++
Для приложений, написанных на .NET–совместимом языке, например VB.NET, ]# или С#, можете воспользоваться программой ildasm.exe, поставляемой в составе .NET Framework SDK. Она позволяет выполнить тщательный анализ кода. Если вызвать ее, как показано ниже, то она выведет все строки. Посмотрите, нет ли среди встроенных паролей.
...ildasm /adv /metadata /text myapp.exe | findstr ldstr
На рис. 12.2 непристойное проявление греха бросается в глаза!
Вторая строка очень напоминает случайный ключ, но это еще не все. В третьей строке мы видим строку соединения с SQL Server от имени пользователя sa, содержащую встроенный пароль. Но и этим дело не заканчивается. Последняя строка – это, скорее всего, часть SQL–запроса, который во время исполнения будет с чем–то конкатенирован. Возможно, вы нашли приложение, в которое не только «зашита» секретная информация, но еще и подверженное греху 4 – внедрению SQL–команд.
Рис. 12.2. Отыскание «зашитых» секретов в .NET–приложениях
Еще один инструмент, полезный для анализа .NET–приложений, – это программа Reflector Лутца Редера (Lutz Roeder), которую можно загрузить со страницы www.aisto.com/roeder/dotnet.
Наконец, для Java можно воспользоваться дизассемблером dis (www.es. princeton.edu/~benjasik/dis). На рис. 12.3 показан пример его работы для Linux.
Как и в примере .NET–приложения, мы видим некоторые интересные данные. Константа в строке #15 – это, очевидно, строка соединения с базой данных, а в строках 17 и 19 мы, по–видимому, имеем имя и пароль пользователя.
Рис. 12.3. Отыскание «зашитых» секретов в программах на языке Java
Наконец, в строке 21 находится SQL–запрос, который будет конкатенирован с какой–то строкой во время выполнения. Похоже, что эксплойт для этой программы будет иметь катастрофические последствия. Взгляните на SQL–запрос, он же извлекает информацию о кредитных карточках! Еще один популярный дизассемблер для Java называется Jad, для него существует графический интерфейс под названием FrontEndPlus.
Примеры из реальной жизни
Следующие примеры взяты из базы данных CVE (http://cve.mitre.org).
CVE–2000–0100
Цитата из бюллетеня CVE: «Программа SMS Remote Control устанавливается с небезопасными правами, позволяющими локальному пользователю расширить свои привилегии путем модификации или замены исполняемого файла».
Исполняемая программа, которую запускает сервис Short Message Service (SMS) Remote Control, помещается в каталог, право на запись в который есть у любого локального пользователя. Если дистанционное управление разрешено, то любой пользователь может запустить произвольную программу от имени учетной записи LocalSystem. (См. www.microsoft.com/technet/security/Bulletin/MSOO–012.mspx.)
CAN–2002–1590
Цитата из бюллетеня CVE: «Система управления предприятием из Web (Web Based Enterprise Management – WBEM) для Solaris 8 с обновлением 1/01 или более поздним инсталлирует пакеты SUNWwbdoc, SUNWwbcou, SUNWwbdev и SUNWmgapp с правом записи для группы и мира. Это позволяет локальному пользователю вызвать отказ от обслуживания или расширить свои привилегии».
Более подробную информацию об этой проблеме можно найти на странице http://cve.mitre.org/cgi–bin/cvename.cgi?name=CAN–2002–1590 или по адресу www.securityfocus.com/bid/6061/.
CVE–1999–0886
Цитата из бюллетеня CVE: «Дескриптор защиты для RASMAN позволяет пользователю указать на другое место с помощью Windows NT Service Control Manager ».
Дополнительную информацию об этой проблеме можно найти на странице www.microsoft.com/technet/security/Bulletin/MS99–041.mspx. ACL сервиса RAS Manager предназначался для того, чтобы любой пользователь мог запустить и остановить сервис, но заодно он позволяет изменить конфигурацию, в том числе и путь к исполняемому файлу, который работает от имени учетной записи LocalSystem.
CAN–2004–0311
Программа Web/SNMP Management для управления устройством SmartSlot Card AP9606 AOS компании American Power Conversion версий 3.2.1 и 3.0.3 поставляется с зашитым паролем по умолчанию. Локальный или удаленный противник, имеющий возможность установить Telnet–соединение с устройством, может указать произвольное имя пользователя и пароль «TENmanUFactOryPOWER» и получить неавторизованный доступ к устройству.
CAN–2004–0391
Согласно бюллетеню безопасности Cisco на странице www.cisco.com/warp/ public/707cisco–sa–20040407–username.shtml:
Стандартная пара «имя/пароль» зашита во всех версиях программ Wireless LAN Solution Engine (WLSE) и Hosting Solution Engine (HSE). Пользователь, зашедший под этим именем, получает полный контроль над устройством. Это имя нельзя деактивировать. Способов обойти проблему не существует.
Искупление греха
Слабый контроль доступа – это, по большей части, проблема уровня проектирования. А лучшим способом решения проектных проблем является построение модели угроз. Тщательно рассмотрите все объекты, создаваемые вашим приложением на этапе инсталляции и во время работы. Один из лучших специалистов по анализу кода в Microsoft говорит, что большую часть ошибок он находит «с помощью notepad.exe и собственных мозгов». Поэтому работайте головой!
Следующий по сложности шаг к искуплению греха – изучить платформу, для которой вы пишете, и понять, как на ней работают подсистемы защиты. Вы должны (повторяем – должны!) разбираться в механизме управления доступом на целевой платформе.
Один из способов не попасть в беду заключается в том, чтобы провести различие между данными уровня системы и отдельного пользователя. Если вы это сделаете, то установить правильные ограничения доступа будет совсем несложно, обычно можно будет принять предлагаемые системой умолчания.
А теперь перейдем к самой важной теме – устранению «зашитых» секретов. Изжить этот грех не всегда бывает просто; если бы это было легко, то никто бы и не грешил! Существует два потенциальных лекарства:
□ использовать методы защиты данных, предоставляемые операционной системой;
□ переместить секретные данные туда, где они не принесут вреда.
Мы рассмотрим оба способа подробно, но прежде приведем одно очень важное изречение:
Программа не может защитить сама себя.
Злонамеренный пользователь с неограниченным доступом к компьютеру, обладающий достаточно обширными знаниями, может раскрыть любые секреты, особенно если он является администратором.
Поэтому вы обязательно должны решить, от кого защищаете систему, а затем оценить, достаточно ли прочна защита с учетом важности той информации, которую вы желаете сохранить в секрете. Защитить закрытый ключ, используемый для подписания документов, которые могут существовать 20 лет, сложнее и важнее, чем пароль, открывающий доступ к разделу «Для членов» на каком–нибудь сайте.
Сначала посмотрим, как нам может помочь ОС.
Использование технологий защиты, предоставляемых операционной системой
Во время работы над этой книгой только Windows и Mac OS X обладали развитыми средствами для хранения секретных данных. Именно ОС решает критически важную (и трудную) задачу управления ключами. В Windows для этой цели служит Data Protection API (DPAPI), а в Mac OS X – технология KeyChain.
Воспользоваться DPAPI очень просто из любого языка, имеющего средства для доступа к внутренним структурам Windows. Полное объяснение принципов работы этого механизма можно найти на сайте http://msdn.microsoft.com (точная ссылка приведена в разделе «Другие ресурсы»).
Ниже показано, как обратиться к низкоуровневому API из программы на C/C++, а также – на примере С# – из управляемого кода на платформе .NET Framework 2.0.
Примечание. В .NET 1.x нет классов для обращения к DPAPI, но существует много оберток. См. пример в книге Майкла Ховарда, Дэвида Леб–ланка «Защищенный код», 2–ое издание (Русская редакция, 2004).
В Windows имеется также интерфейс Crypto API (CAPI) для доступа к ключам шифрования. Вместо того чтобы использовать ключ непосредственно, вы передаете описатель скрытого внутри системы ключа. Эта методика также рассмотрена в книге «Защищенный код», 2–ое издание.
Искупление греха в C/C++для Windows 2000 и последующих версий
Приведенный ниже код иллюстрирует, как обращаться к DPAPI из программ на языках C/C++ для Windows 2000 и более поздних версий. В этом коде есть две функции, которые вы должны реализовать сами: одна возвращает статический указатель типа BYTE* на секретные данные, а другая – статический указатель типа BYTE* на данные, вносящие дополнительную энтропию. В самом конце программа вызывает функцию SecureZeroMemory, чтобы стереть данные из памяти. Используется именно эта функция, а не memset или Zer oMemory, так как последние могут быть устранены из двоичного кода компилятором в ходе оптимизации....// Защищаемые данные
DATA_BLOB blobIn;
blobIn.pbData = GetSecretData();
blobIn.cbData = lstrlen(reinterpret_cast<char *>(blobIn.pbData)) + 1;
// Дополнительная энтропия, которую возвращает внешняя функция
DATA_BLOB blobEntropy;
blobEntropy.pbData = GetOptionalEntropy();
blobEntropy.cbData = lstrlen(reinterpret_cast<char *>(blobIn.pbData));
// Зашифровать данные
DATA_BLOB blobOut;
if(CryptProtectData(
&blobIn,
L"Sin#12 Example", // необязательный комментарий
&blobEntropy,