дані це основа всього. це і номери кредитних карт і особисту інформацію користувачів, і відомостях про викрадених машинах. вміст чатів і форумів теж зберігається в БД. проникнення в корпоративну (військову, урядову) базу даних — найгірше, що тільки може трапитися з компанією. вражаюче, але навіть критичні сервера часто виявляються ніяк не захищені і зламуються навіть 12-літні любителями командного рядка без особливих зусиль.
введення
Сервера баз даних відносяться до найбільш критичних інформаційних ресурсів і тому вони повинні розміщуватися на виділеному сервері, розташованим у внутрішній корпоративній мережі, огородженій маршрутизатором або брандмауер. Взаємодію з базами даних зазвичай здійснюється через WEB-сервер, що знаходиться всередині DMZ-зони (див. статтю про брандмауери).
Розміщувати сервер бази даних на одному вузлі з WEB-сервером категорично неприпустимо не тільки технічним, але і юридичним міркувань (законодавства багатьох країн диктують свою політику поводження з конфіденційними даними, особливо якщо ці дані зберігають інформацію про клієнтів компанії). Тим не менш, суміщення сервера БД з WEB-сервером — звичайна справа, яким сьогодні нікого не здивуєш. Економія мати її так! Захопивши управління WEB-сервером (а практично ні одного WEB-сервера не вдалося уникнути помилок переповнення буфера і інших дірок), атакуючий отримає доступ до всіх даних, що зберігаються в базі!
Сервер БД, як і будь-який інший сервер, схильний до помилок проектування серед яких домінують переполняющиеся буфера, багато з яких дозволяють атакуючому захоплювати керування віддаленою машиною з успадкуванням адміністраторських привілеїв. Яскравий приклад тому — уразливість, знайдена на сервері MS SQL і стала причиною великої вірусної епідемії. Не уникнув цієї долі і MySQL. Версія 3.23.31 падала на запити типу select a.AAAAAAAAAAAAA.b, а на відповідним чином підготовлених рядках — передавала управління на shell-код, причому атаку можна було здійснити і через браузер, передавши в URL щось типу: script.php?index=a.(shell-code).b.
Однак, навіть захищений брандмауером SQL-сервер, може бути атакований через уразливий скрипт або нестійкий механізм аутентифікації. Зрозуміло, ми не можемо розповісти про всіх існуючих атаках, але продемонструвати пару-трійку улюблених хакерських прийомів — цілком у наших силах.
нестійкість шифрування паролів
Паролі, що регламентують доступ до бази даних, ні за яких обставин не повинні передаватися відкритим текстом по мережі. Замість пароля, передається його хеш, зашифрований випадково згенерованої послідовністю байт, і званий перевірочної рядком (check-string). Коротше кажучи, реалізується класична схема аутентифікації, стійка до перехоплення інформації і при цьому не допускає ні підбору пароля, ні його декодування (принаймні в теорії).
На практиці ж у багатьох серверах БД виявляються жорстокі помилки проектування. Взяти хоча б MySQL версії 3.x. Хеш-функція, використовувана для «згортання» пароля повертає 64-розрядну кодовану послідовність, у той час як довжина випадково генерується рядка (random string) становить лише 40 біт. Як наслідок, шифрування не повністю видаляє всю надлишкову інформацію і аналіз великої кількості перехоплених check-string/random-string дозволяє відновити вихідний хеш пароль відновлювати не потрібно, тому що для аутентифікації він на фіг не потрібний).
В дещо спрощеному вигляді процедура шифрування виглядає так:

// P1/P2 — 4 лівих/правий байт парольного хеша відповідно
// C1/C2 — 4 лівих/правий байт random-string відповідно
seed1 = P1 ^ C1;
seed2 = P2 ^ C2 ;
for(i = 1; i >>> врізка розтин скрипта
Нормально працює WEB-сервер ніколи не видає вихідний код скрипта, а лише результат його роботи. Між тим, всюдисущі помилки реалізації призводять до того, що код скрипта в деяких випадках все ж таки стає доступним, причому винуватцем може бути як сервер, так і оброблюваний їм скрипт. Природно, в скриптах помилки зустрічаються набагато частіше, оскільки їх пишуть всі кому не лінь, часом не маючи ніякого уявлення про безпеку. Сервера ж проходять більш або менш ретельне тестування і основні дірки виявляються ще на стадії бета-тестування.
Детальніше про це можна прочитати у моїй статті «Безпечне програмування на мові Perl» (kpnc.opennet.ru/safe.perl.zip), тут же ми зосередимося безпосередньо на зломі самої БД. Досліджуючи тіло скрипта, можна нарити чимало цікавого. Наприклад, імена полів, назви таблиць, майстер-паролі, що зберігаються відкритим текстом і т. д.

if ($filename eq «passwd») #перевірка на коректність імені

Лістинг 2 майстер-пароль до БД, що зберігається в тілі скрпита відкритим текстом
нав’язування запиту або SQL-injecting
Типовий сценарій взаємодії з базою даних виглядає так: користувач вводить деяку інформацію в поля запиту. Звідти її отримує спеціальний скрипт і перетворює в рядок запиту до бази даних, передаючи сервера її на виконання:

$result = mysql_db_query(«database», «select * from userTable
where login = ‘$userLogin’ and password = ‘$userPassword’ „);
Лістинг 3 типова схема формування запиту до БД
Тут: $userlogin — змінна, що містить ім’я користувача, а $userPassword — його пароль. Зверніть увагу, що обидві змінні розміщені всередині текстового рядка, облямованої лапками. Це незвично для Сі, але типово для інтерпретованих мов на кшталт Perl ‘ a і PHP. Подібний механізм називається інтерполяцією рядків і дозволяє автоматично підставляти замість змінної її фактичне значення.
Припустимо, користувач введе KPNC/passwd, тоді рядок запиту буде виглядати так: “select * from userTable where login = ‘KPNC’ and password = ‘passwd’». (користувальницький введення виділено напівжирним шрифтом). Якщо такий логиг/пароль дійсно присутні в базі, функція повідомляє ідентифікатор результату, в іншому випадку повертається значення FALSE.
Хочете увійти в систему під іменем іншого користувача, знаючи його логін, але не знаючи пароль? Скористається тим, що механізм інтерполяції дозволяє атакуючому впливати на рядок запиту, видозмінюючи її на свій розсуд. Подивимося, що станеться, якщо замість пароля ввести послідовність «fuck’ or ‘1’= ‘1» (без лапок): «select * from userTable where login = ‘KPNC’ and password = ‘fuck’ or ‘1’ = ‘1’». Дивіться, лапки, що стоїть після fuck’a, замкнула пароль, а весь наступний введення потрапив в логічний вираз, нав’язане базі даних атакуючим. Оскільки один завжди дорівнює одному, запит буде вважатися виконаним при будь-якому введеному паролі і SQL-сервер поверне всі-всі-всі записи з таблиці (в тому числі і не пов’язані з логіном KPNC)!
Розглянемо інший приклад: «SELECT * FROM userTable WHERE msg=’$msg’ AND ID=669». Тут: msg — номер повідомлення, що витягається з бази, а ID — ідентифікатор користувача, автоматично підставляється скриптом в рядок запиту і безпосередньо не пов’язаний з користувальницьким введенням (електронний змінна використана з міркувань наочності, в кінцевому скрипті буде швидше за все використана конструкція типу: ID=’$userID’). Щоб отримати доступ до решти полів бази (а не тільки тим, чий ID дорівнює 669) необхідно відсікти останнім логічна умова. Це можна зробити, запровадивши в рядок користувальницького введення символів коментаря (“–“”/*” для MS SQL і MySQL відповідно). Текст, розташований лівіше символів коментаря, ігнорується. Якщо замість номера ввести повідомлення «1′ AND ID=666 –», рядок запиту прийме наступний вигляд: «SELECT * FROM userTable WHERE msg=’1′ and ID= 666 –‘ AND ID=669» (сірим кольором виділений текст коментаря). Як наслідок, атакуючий отримає можливість самостійно формувати ID, читаючи повідомлення, призначені зовсім для інших користувачів.
Причому, одним лише видозміною полів SELECT’а справа не огранивается і існує загроза прориву за його межі. Деякі SQL-сервера підтримують можливість завдання декількох команд в одному рядку, розділяючи їх знаком “;”, що дозволяє атакуючому виконати будь-які SQL-команди, які йому тільки заманеться. Наприклад, послідовність ” ‘; DROP TABLE ‘userTable’ –“, введена в якості імені користувача або пароля, видаляє всю userTable на хрін!
Ще атакуючий може зберігати частину таблиці у файл, підсовуючи базі даних запит типу «SELECT * FROM userTable INTO OUTFILE ‘FileName’». Відповідний йому URL уразливого скрипта може виглядати наприклад так: www.victim.com/admin.php?op=login&pwd=123&aid=Admin’%20INTO%20OUTFILE%20’/path_to_file/pwd.txt, де path_to_file — шлях до файлу pwd.txt, який буде записаний админивский пароль. Зручний засіб для викрадення даних, чи не так? Головне — розмістити файл у такому місці, звідки його потім можна буде безперешкодно тягнути, наприклад, в одному з публічних WWW-каталогах. Тоді повний шлях до файлу повинен виглядати приблизно так: “../../../../WWW/myfile.txt”. (точна форма запиту залежить від конфігурації сервера). Але це ще тільки квіточки! Можливість створення файлів на сервері, дозволяє засилати на атакуемую машину власні скрипти (наприклад, скрипт, який дає віддалений shell — “”). Природно, максимальний розмір скрипта обмежений гранично припустимою довжиною форми користувальницького введення, але це обмеження часто вдається обійти ручним формуванням запиту в URL, або використанням SQL-команди INSERT INTO, додає нові записи в таблицю.
Скоригований URL-запит може виглядати наприклад так: www.victim.com/index.php?id=12′ або так: www.victim.com/index.php?id=12+union+select+null,null,null+from+table1 /*. Останній запит працює тільки на MySQL версії 4.х і вище, підтримує union (об’єднання декількох запитів в одному рядку). Тут table1 — ім’я таблиці, вміст якої необхідно вивести на екран.
Атаки подібного типу називаються SQL-ін’єкцій (SQL-injection) і є окремим випадком більш загальних атак, заснованих на помилках фільтрації та інтерполяції рядків. Ми немов «впорскують» у форму запиту до бази даних власну команду, проколюючи хакерської голкою тіло уразливого скрипта (звідси і «ін’єкції» ). Це не помилка SQL-сервера як часто прийнято вважати). Це — помилка розробників скрипта. Грамотно спроектований скрпит повинен перевіряти користувальницький введення на предмет присутності потенційно небезпечних символів (як-то: одиночна лапки, крапка з комою, подвійне тире, а для MySQL ще і символ зірочки), включаючи і їх шістнадцяткові еквіваленти, що задаються через префікс “%”, а саме: %27, %2A і %3B. (Код символу подвійного тире фільтрувати не потрібно, оскільки він не входить в число метасимволів, що підтримуються браузером). Якщо хоча б одна з умов фільтрації не перевіряється чи перевіряється не всюди (наприклад, залишаються не відфільтрованими рядка URL або cookie) в скрипті утворюється дірка, через яку його можна атакувати.
Втім, зробити це буде не так вже й просто. Необхідно мати досвід програмування на Perl/PHP і знати як може виглядати та чи інша форма запиту і як найчастіше іменуються поля таблиці, в іншому випадку інтерполяція ні до чого не призведе. Безпосередній можливості визначення імен полів і таблиць у хакера немає і йому доводиться діяти методом сліпого перебору (blinding).
На щастя для атакуючого, більшість адміністраторів і WEB-майстрів занадто ліниві, щоб розробляти всі необхідні їм скрипти самостійно і частіше вони використовують готові рішення, вихідні тексти яких вільно доступні в мережі. Причому, більшість цих скриптів дырявы як відро без дна. Взяти, наприклад, той же PHP Nuke, в якому постійно виявляються все нові і нові уразливості.
Приблизна стратегія пошуку дірок виглядає так. Викачуємо вихідні тексти PHP Nuk’а (або будь-який інший портальної системи), встановлюємо їх на свій локальний комп’ютер, проходимся глобальним пошуком по всіх файлів, відкладаючи вбік всі ті, що звертаються до бази даних (виклик типу mysql_query/mysql_db_query або типу того). Прокручуємо курсор верх і дивимося — десь поблизу має бути розташована рядок запиту до бази (наприклад: $query = «SELECT user_email, user_id FROM ${prefix}_users WHERE user_id = ‘$cookie[0]’»). Визначаємо імена змінних, подставляемых в базу, знаходимо код, відповідальний за передачу параметрів користувача введення і аналізуємо умови фільтрації.

Малюнок 2 фрагмент PHP Nuke, відповідальний за формування запиту до бази
В якості прикладу розглянемо одну з вразливостей PHP Nuke 7.3, пов’язану з обробкою новин. Відповідний їй URL виглядає так: modules.php?name=News&file=categories&op=newindex&catid=1. По його зовнішньому вигляду можна припустити, що значення catid передається безпосередньо в рядку запиту до БД і якщо розробник скрипта забув про фільтрації, у нас з’являється можливість модифікувати запит на свій розсуд. Для перевірки цього припущення замінимо catid з 1 на, припустимо, 669. Сервер негайного відобразить у відповідь порожній екран. Тепер додамо до нашого URL наступну конструкцію “‘or’1’1=’1” (повністю він буде виглядати так: modules.php?name=News&file=categories&op=newindex&catid=669’or’1’=’1). Сервер слухняно відобразить всі новинні повідомлення розділу, підтверджуючи, що SQL-ін’єкція спрацювала!

Малюнок 3 SQL-ін’єкції через рядок URL
Ще можна спробувати викликати помилку SQL, підсунувши їй завідомо неправильний запит (наприклад, символ одиночної лапок) і тоді вона може повідомити багато цікавого. Відсутність помилок ще не означає, що скрипт фільтрує користувальницький введення — бути може він просто перехоплює повідомлення про помилки, що є нормальною практикою мережевого програмування. Також можлива ситуація, коли при виникненні помилки повертається код відповіді 500, або відбувається переадресація на головну сторінку. Подібна двозначність ситуації істотно ускладнює пошук уразливих серверів, але аж ніяк не робить його неможливим!
Аналіз показує, що помилки фільтрації зустрічаються у великій кількості скриптів (включаючи комерційні), часто залишаючись невиправленими роками. Природно, дірки в основних полях введення давним-давно заткнуті і тому розраховувати на швидкий успіх вже не доводиться. Запити, що передаються методом POST, протестовані значно гірше, оскільки, передаються приховано від користувача і не можуть бути модифіковані безпосередньо з браузера, відсікаючи армаду початківців «хакерів». Між тим взаємодіяти з WEB-сервером можна і за допомогою netcat’а (telnet’а), формуючи POST-запити вручну.

команда призначення
CREATE TABLE створення нової таблиці
DROP TABLE видалення існуючої таблиці
INSERT INTO додавання в таблицю поля із заданим значенням
DELETE FROM WHERE видалення з таблиці всіх записів, що відповідають умові WHERE
SELECT * FROM WHERE вибірка з бази всіх записів, що відповідають умові WHERE
UPDATE… SET… WHERE оновлення всіх полів бази, що відповідають умові WHERE
Таблиця 1 основні команди SQL
>>>> визначити наявність SQL
Перш ніж розпочинати атаку на SQL-сервер, непогано б визначити його присутність, а в ідеалі — ще й розпізнати тип. Якщо сервер розташований всередині DMZ (де йому перебувати ні в якому разі не можна), то атакуючому досить просканувати порти (див. таблицю 2).

порт сервер
1433 Microsoft SQL Server
1434 Microsoft SQL Monitor
1498 Watcom-SQL
1525 ORACLE
1527 ORACLE
1571 Oracle Remote Data Base
3306 MySQL
Таблиця 2 порти, відкриті різними серверами БД

Малюнок 4 сервер MySQL, прослуховування 3306-порт
>>>> врізка протидія вторгнення
Коли ручний пошук дірок набридає, хакери, в серцях обклавши всіх WEB-програмістів смачним матом, запускають свою будь засоби автоматичного пошуку вразливостей і йдуть на перекур.
Одним з таких засобів є Security Scanner, розроблений компанією Application Security і офіційно призначений для тестування MySQL на стійкість до злому. Ну, хакерам офіціоз не загрожує. Як і всяка зброя, Security Scanner може використовуватися і на шкоду, і во благо.
Він дозволяє шукати дірки в самому сервері БД, так і в web-скриптах. При цьому, БД перевірятися на предмет уразливості до атак типу Denial of Service, наявності слабких паролів, невірно сконфігурованих прав доступу і т. д. В скриптах сканер дозволяє виявити помилки фільтрації вводу, що дозволяють здійснювати SQL-ін’єкції, що значно спрощує атаку.
висновок
SQL-ін’єкції в черговий раз продемонстрували світу, що програм без помилок не буває. Однак, не варто переоцінювати їх значимість. Мавр зробив свою справу і може піти. Адміністратори і девелопери про небезпеку і кількість уразливих сайтів невпинно тане з кожним днем. Реальну владу нас системою дають лише принципово нові методики атак, невідомі широкій громадськості. Знайти їх наша з тобою завдання. Звільни свій розум, перешагни межу невідомого, і зайди на сервер з тієї сторони, з якої на нього ще ніхто не заходив.