Костылим со всей силы в sql-запросах
📖 Пару лет назад был пост с кодревью, где числовой постфикс к имени файла находился брутфорсом, перебирая все доступные имена. Освежить в памяти можно тут: Новая папка(123). Сегодня получилось реализовать тоже самое только с базой данных. Сперва не планировал писать, но задачка получилась интересная и не стандартная – костыль, который вряд ли кому-то пригодится в том виде, как он есть, однако показывает не самые стандартные возможности SQL.
📌 Что имеем? Есть таблица в БД mysql, куда пишутся записи с некоторыми данными, а одно из полей хранит уникальный ключ такого вида: keyname_123, где 123 – это инкремент для уникальности. Нужно узнать самый большой постфикс для ключа и добавить запись с ключом keyname_(N+1).
Важное примечание. В силу некоторых обстоятельств, сделать по-человечески, и вынести индекс ключа в отдельный столбец, и по нему уже делать выборку, в данном случае нельзя. Можем работать только с такой строкой.
📌 Как реализовано? С помощью while цикла делались запросы к таблице для проверки существования записи с ключом keyname_i, где i – инкремент от 0 и до конца, с увеличением на единицу. Цикл крутится, пока запрос к БД не вернет пустой ответ, это сигнализирует о найденном индексе ключа, который можно использовать для новой записи. В данном случае индексов может быть не много, не более десятка, но что может стать с проектом в будущем никто не знает, и такой поиск индекса будет серьезной проблемой при увеличении объемов. Да и в целом, перебор значений — это уж совсем крайний случай.
📌 Как сделать получше? А теперь несколько вариантов, как еще можно решить эту задачу, не мучая БД лишними запросами.
1. Так же перебором, но гонять в цикле не запросы к БД, а данные. Сделать запрос вида:
Достаем все ключи и находим самый большой индекс. Такой вариант будет работать быстрее и меньше грузить БД на небольших объемах данных.
2. Для mysql 8.0+ версий можно написать запрос и регуляркой отрезать от ключа текстовую часть, оставив только числовой постфикс. И сразу же в запросе получить максимальное значение. То есть один запросом получаем сразу максимальный индекс. Запрос:
3. Для mysql ниже 8 версии, где нет поддержки REGEXP_SUBSTR, тоже можно реализовать запрос, как во втором примере, но через предварительный подсчет символов до числа. Запрос:
Если у кого есть еще идеи sql-запросов, кидайте в комментарии, может быть есть более простые или интересные варианты.
———
#️⃣ #sql #костыли
🐞 БАГодельня: Канал // Чат
📖 Пару лет назад был пост с кодревью, где числовой постфикс к имени файла находился брутфорсом, перебирая все доступные имена. Освежить в памяти можно тут: Новая папка(123). Сегодня получилось реализовать тоже самое только с базой данных. Сперва не планировал писать, но задачка получилась интересная и не стандартная – костыль, который вряд ли кому-то пригодится в том виде, как он есть, однако показывает не самые стандартные возможности SQL.
📌 Что имеем? Есть таблица в БД mysql, куда пишутся записи с некоторыми данными, а одно из полей хранит уникальный ключ такого вида: keyname_123, где 123 – это инкремент для уникальности. Нужно узнать самый большой постфикс для ключа и добавить запись с ключом keyname_(N+1).
Важное примечание. В силу некоторых обстоятельств, сделать по-человечески, и вынести индекс ключа в отдельный столбец, и по нему уже делать выборку, в данном случае нельзя. Можем работать только с такой строкой.
📌 Как реализовано? С помощью while цикла делались запросы к таблице для проверки существования записи с ключом keyname_i, где i – инкремент от 0 и до конца, с увеличением на единицу. Цикл крутится, пока запрос к БД не вернет пустой ответ, это сигнализирует о найденном индексе ключа, который можно использовать для новой записи. В данном случае индексов может быть не много, не более десятка, но что может стать с проектом в будущем никто не знает, и такой поиск индекса будет серьезной проблемой при увеличении объемов. Да и в целом, перебор значений — это уж совсем крайний случай.
📌 Как сделать получше? А теперь несколько вариантов, как еще можно решить эту задачу, не мучая БД лишними запросами.
1. Так же перебором, но гонять в цикле не запросы к БД, а данные. Сделать запрос вида:
SELECT key_column
FROM tbl_test
WHERE key_column LIKE 'kek_%';
Достаем все ключи и находим самый большой индекс. Такой вариант будет работать быстрее и меньше грузить БД на небольших объемах данных.
2. Для mysql 8.0+ версий можно написать запрос и регуляркой отрезать от ключа текстовую часть, оставив только числовой постфикс. И сразу же в запросе получить максимальное значение. То есть один запросом получаем сразу максимальный индекс. Запрос:
SELECT MAX(CONVERT(REGEXP_SUBSTR (key_column, '[0-9]+$'), INT)) AS max_prefix
FROM tbl_test
WHERE key_column like 'kek_%';
3. Для mysql ниже 8 версии, где нет поддержки REGEXP_SUBSTR, тоже можно реализовать запрос, как во втором примере, но через предварительный подсчет символов до числа. Запрос:
SELECT MAX(CAST(SUBSTRING(key_column, 5) AS UNSIGNED)) AS max_prefix
FROM tbl_test
WHERE key_column LIKE 'kek_%';
Если у кого есть еще идеи sql-запросов, кидайте в комментарии, может быть есть более простые или интересные варианты.
———
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥5👍2 1
Выборка WHERE txt_field = 0 для текстовых полей
📖 Сразу оговорюсь – я понимаю, что никому в здравом уме не придет идея делать подобные запросы умышлено. Но понимание таких нюансов может пригодиться для упрощения дебага, а также при каких-то нестандартных ситуациях, не связанных с разработкой для продакшена.
Как раз во время поиска проблемы с выборками из БД и был обнаружен подобный запрос. В коде был баг, который при определенных обстоятельствах превращал параметр строкового ключа в число ноль и в типе int использовался для запроса к базе данных MySql. Не сразу обнаружился ноль в запросе, и пришлось повозиться, прежде удалось понять, почему вместо выборки по строковому ключу, возвращаются вообще все данные из таблицы.
📌 Странные запросы и результаты
На скрине упрощенная таблица БД, которая состоит из двух полей –
В ответ получим три строки:
А такой запрос:
Вернет одну строку:
📌 Почему так происходит?
Странные выборки получаются и не очень очевидные. Но это нормальное поведение MySql. Когда в запросе нужно сравнить число и строку, MySql пытается сделать приведение к одному типу данных. Но приведение типов с MySql работает по своим правилам, вот таким:
– Читает строку слева направо до первого нечислового символа
– Если в начале строки нет цифр, результат преобразования будет равен нулю
– Если есть цифры, то берет только числовую часть и отбрасывает остатки
Поэтому все строки, которые начинаются с нечисловых символов, становятся равны нулю и удовлетворяют условиям выборки
📌 Примеры преобразований строк в число:
———
#⃣ #Костыли #sql #Типы
🐞 Канал // Чат // Задачи
📖 Сразу оговорюсь – я понимаю, что никому в здравом уме не придет идея делать подобные запросы умышлено. Но понимание таких нюансов может пригодиться для упрощения дебага, а также при каких-то нестандартных ситуациях, не связанных с разработкой для продакшена.
Как раз во время поиска проблемы с выборками из БД и был обнаружен подобный запрос. В коде был баг, который при определенных обстоятельствах превращал параметр строкового ключа в число ноль и в типе int использовался для запроса к базе данных MySql. Не сразу обнаружился ноль в запросе, и пришлось повозиться, прежде удалось понять, почему вместо выборки по строковому ключу, возвращаются вообще все данные из таблицы.
📌 Странные запросы и результаты
На скрине упрощенная таблица БД, которая состоит из двух полей –
id и txt_field. Поле txt_field имеет тип varchar и хранит строки. Если сделать такой sql запрос:SELECT * FROM `tbl_test` WHERE `txt_field` = 0;
В ответ получим три строки:
id txt_field
1 kek
2 kek_1
3 kek_2
А такой запрос:
SELECT * FROM `tbl_test` WHERE `txt_field` = 1;
Вернет одну строку:
id txt_field
4 1_kek
📌 Почему так происходит?
Странные выборки получаются и не очень очевидные. Но это нормальное поведение MySql. Когда в запросе нужно сравнить число и строку, MySql пытается сделать приведение к одному типу данных. Но приведение типов с MySql работает по своим правилам, вот таким:
– Читает строку слева направо до первого нечислового символа
– Если в начале строки нет цифр, результат преобразования будет равен нулю
– Если есть цифры, то берет только числовую часть и отбрасывает остатки
Поэтому все строки, которые начинаются с нечисловых символов, становятся равны нулю и удовлетворяют условиям выборки
WHERE txt_field = 0. Однако, если в начале строки есть число, то такая строка преобразуется в числовое значение, поэтому запрос с WHERE txt_field = 1, выдаст результат с «1_kek».📌 Примеры преобразований строк в число:
'123kek' → 123
'kek_1' → 0 (первый символ не цифра)
'1_kek' → 1
'1.23kek' → 1.23
'kek' → 0
'' (пустая строка) → 0
———
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8❤4👍2
Слепая SQL-инъекция. Часть 1
📖 Про sql-инъекции уже был пост, в том примере был понятен результат запросов – при добавлении инъекций, сайт отдавал результат выполнения запросов к базе данных. Это был описан пример UNION-инъекции.
Но такого «подарка» с удобным дебагом не всегда можно получить, чаще уязвимые эндпоинты ничего не отвечают или результат запроса можно определить только по косвенным данным. Когда есть хоть какой-то признак успешного выполнения запроса, то логика сводится к бинарной – успешно прошел запрос или нет. В таких случаях инъекции нужно строить с условиями. В случае вставки или удаления данных все понятно, а для получения значений, нужно немного помудрить. Целиком получить имя БД, таблиц и значения из них уже не получится, однако можно вытянуть нужную информацию по символу – разделяя результат посимвольно с помощью substr и перебором сравнивая с алфавитом.
📌 Пример инъекции:
Где
📌 Чтобы не делать полный брутфорс 95 печатных символов ASCII(от 32 до 126), из которых может состоять текст(имена таблиц, содержимое и тд), можно ускорить поиск в 13-14 раз с помощью бинарного поиска:
📌 Однако, если сервер совсем никак не реагирует на инъекции и всегда отвечает одинаково, такой подход не сработает, поскольку нет никаких признаков, которые бы сигнализировали об успешном нахождении правильного символа. Но и такую проблему можно решить – с помощью техники Time-based. При успешном выполнении условия, мы умышленно загружаем и/или делаем паузу на стороне сервера, чтобы по времени ответа можно было определить успешность запроса. В mysql такое легко сделать с помощью:
📌 Как защититься
Точно так же, как и с другими типами инъекций – экранировать все данные, которые используются в запросах. Вредоносные данные могут приходить на публичные эндпоинты и на приватные, через другие методы или прослойки. Любой запрос к базе данных должен быть экранирован, даже если он на прямую не использует публичные данные.
❗️Для тестирования подобных инъекций опубликовано две задачи на нашей площадке, на них можно потренироваться:
– Слепая инъекция
– Совсем слепая инъекция
👨💻 Не влезает все в один пост. Тут только теоретическая часть, следом выйдет второй пост со скриптами и описанием инструментов.
———
#⃣ #SQL #БазаЗнаний
🐞 Канал // Чат // Задачи
📖 Про sql-инъекции уже был пост, в том примере был понятен результат запросов – при добавлении инъекций, сайт отдавал результат выполнения запросов к базе данных. Это был описан пример UNION-инъекции.
Но такого «подарка» с удобным дебагом не всегда можно получить, чаще уязвимые эндпоинты ничего не отвечают или результат запроса можно определить только по косвенным данным. Когда есть хоть какой-то признак успешного выполнения запроса, то логика сводится к бинарной – успешно прошел запрос или нет. В таких случаях инъекции нужно строить с условиями. В случае вставки или удаления данных все понятно, а для получения значений, нужно немного помудрить. Целиком получить имя БД, таблиц и значения из них уже не получится, однако можно вытянуть нужную информацию по символу – разделяя результат посимвольно с помощью substr и перебором сравнивая с алфавитом.
📌 Пример инъекции:
1 AND (SELECT SUBSTR(flag_column,{position},1) FROM flag LIMIT 1) = '{char}'Где
{position} – это позиция символа, который пытаемся определить для записи из колонки flag_column в таблице flag. А {char} – это символ, с которым сверяемся. Если мы угадали первый символ, то запрос будет содержать какой-то ответ, поскольку условие вернет true. Так перебирая по одному символу и опираясь на статус ответа запроса, можно получить не только значения из таблицы, но и саму структуру таблиц. Например, в mysql можно сделать запрос к INFORMATION_SCHEMA, которая возвращает список и описание таблиц. 📌 Чтобы не делать полный брутфорс 95 печатных символов ASCII(от 32 до 126), из которых может состоять текст(имена таблиц, содержимое и тд), можно ускорить поиск в 13-14 раз с помощью бинарного поиска:
log₂(95) ≈ 7 запросов на один символ. В самой инъекции меняется только условие >= '{char}', вместо равенства стало неравенство. Так мы существенно оптимизируем поиск.📌 Однако, если сервер совсем никак не реагирует на инъекции и всегда отвечает одинаково, такой подход не сработает, поскольку нет никаких признаков, которые бы сигнализировали об успешном нахождении правильного символа. Но и такую проблему можно решить – с помощью техники Time-based. При успешном выполнении условия, мы умышленно загружаем и/или делаем паузу на стороне сервера, чтобы по времени ответа можно было определить успешность запроса. В mysql такое легко сделать с помощью:
SLEEP(3), где 3 – это количество секунд, на которые «задумается» mysql. Дальше, остается только изменить логику обработки – вместо самих ответом запросов, опираться на их время выполнения. В некоторых СУБД нет sleep или он может быть отключен в настройках. В подобных случаях можно самим сделать задержку – использовать в запросах сложные или рекурсивные расчеты, которые так же вызовут задержку ответа. К примеру, в sqlite нет sleep, но есть функция randomblob, которая генерирует рандомные байты, и если запросить большое количество, то запрос может подвисать на несколько секунд. 📌 Как защититься
Точно так же, как и с другими типами инъекций – экранировать все данные, которые используются в запросах. Вредоносные данные могут приходить на публичные эндпоинты и на приватные, через другие методы или прослойки. Любой запрос к базе данных должен быть экранирован, даже если он на прямую не использует публичные данные.
❗️Для тестирования подобных инъекций опубликовано две задачи на нашей площадке, на них можно потренироваться:
– Слепая инъекция
– Совсем слепая инъекция
👨💻 Не влезает все в один пост. Тут только теоретическая часть, следом выйдет второй пост со скриптами и описанием инструментов.
———
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7🔥5👍4
Слепая SQL-инъекция. Часть 2
Вторая часть, продолжение предыдущего поста «Слепая SQL-инъекция».
📖 Такие атаки, где нет явного ответа сервера о результате запроса, на БД сложно выполнять в «ручном режиме», нужно писать скрипты или пользоваться готовыми инструментами. Самый мощный инструмент для таких целей – sqlmap. Он умеет работать полностью автоматически, если передать нужный адрес уязвимости и правильный набор параметров. Для тестирования этого инструмента и подобных типов уязвимостей, опубликовано две задачки на нашей площадке. Первая уязвимость отвечает true/false, а вторая совсем ничего не подсказывает, и в добавок ограничена по ресурсам, чтобы потренироваться с настройками таймингов.
📌 Запуска sqlmap на примере второй задачи опишу, тут больше всего флагов:
И это только часть флагов, которые доступны в утилите sqlmap. Инструмент умеет автоматически определять СУБД, извлекать имена БД, имена и структуры таблиц, а так же собирать и выкачивать полный дамп базы данных.
📌 Инструменты – это хорошо, но в самых не стандартных ситуациях спасают только самодельные скрипты. К тому же написание скриптов это еще и гимнастика для мозгов, а самое главное – способ детальнее погрузиться в тему и разобраться в вопросе более детально. Хорошо пользоваться готовым инструментов, когда понимаешь как он устроен, действовать в нестандартных ситуациях будет проще и понятнее. Поэтому для примеров решения задачек прикладываю еще два скрипта, которые помогут более детально разобраться в способах применения слепой инъекции.
📌 Скрипты нахождения флагов из тестовых задачек на тему поста:
Первый скрипт – простой брутфорс флага из таблицы по одному символу: скрипт.
Второй скрипт, который использует бинарный поиск для оптимизации и ускорения: скрипт.
❗️ Потренировать можно тут:
– Слепая инъекция
– Совсем слепая инъекция
———
#⃣ #SQL #БазаЗнаний
🐞 Канал // Чат // Задачи
Вторая часть, продолжение предыдущего поста «Слепая SQL-инъекция».
📖 Такие атаки, где нет явного ответа сервера о результате запроса, на БД сложно выполнять в «ручном режиме», нужно писать скрипты или пользоваться готовыми инструментами. Самый мощный инструмент для таких целей – sqlmap. Он умеет работать полностью автоматически, если передать нужный адрес уязвимости и правильный набор параметров. Для тестирования этого инструмента и подобных типов уязвимостей, опубликовано две задачки на нашей площадке. Первая уязвимость отвечает true/false, а вторая совсем ничего не подсказывает, и в добавок ограничена по ресурсам, чтобы потренироваться с настройками таймингов.
📌 Запуска sqlmap на примере второй задачи опишу, тут больше всего флагов:
sqlmap -u "http://31.207.77.216:4005/check?number=1" --technique=T --time-sec=2 --delay=1 --timeout=3 --dbms=SQLite --hex --level=5 --risk=3 -T flag -C flag --dump -v 6
-u "http://31.207.77.216:4005/check?number=1" – адрес цели--technique=T – указываем тип техники для атаки Time-based--time-sec=2 – время задержки для проверки условий--delay=1 – интервалы задержек между запросами--timeout=3 – ожидание ответа сервера--dbms=SQLite – тип субд--hex – кодирование данных--level=5 – уровень тестирования(от 1 до 5, 5 максимальный набор)--risk=3 – уровень риска(1-3, на сколько заметный пейлоад в запросе)-T flag -C flag – имена целевой таблицы и колонки--dump – получение данных-v 6 – уровень дебага при работе программыИ это только часть флагов, которые доступны в утилите sqlmap. Инструмент умеет автоматически определять СУБД, извлекать имена БД, имена и структуры таблиц, а так же собирать и выкачивать полный дамп базы данных.
📌 Инструменты – это хорошо, но в самых не стандартных ситуациях спасают только самодельные скрипты. К тому же написание скриптов это еще и гимнастика для мозгов, а самое главное – способ детальнее погрузиться в тему и разобраться в вопросе более детально. Хорошо пользоваться готовым инструментов, когда понимаешь как он устроен, действовать в нестандартных ситуациях будет проще и понятнее. Поэтому для примеров решения задачек прикладываю еще два скрипта, которые помогут более детально разобраться в способах применения слепой инъекции.
📌 Скрипты нахождения флагов из тестовых задачек на тему поста:
Первый скрипт – простой брутфорс флага из таблицы по одному символу: скрипт.
Второй скрипт, который использует бинарный поиск для оптимизации и ускорения: скрипт.
❗️ Потренировать можно тут:
– Слепая инъекция
– Совсем слепая инъекция
———
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥7👍4 4❤2