БАГодельня
رفتن به کانال در Telegram
Канал про разработку и безопасность: код, костыли, разбор задач, ревью и размышления. Вещает руководитель отдела разработки: @ipatove Сайт: https://bug-makers.ru Поддержать проект: https://boosty.to/bugctf/donate
نمایش بیشتر2 608
مشترکین
-124 ساعت
-57 روز
+2230 روز
آرشیو پست ها
2 608
Опубликованы новые задания
Пять новых задач доступны на площадке!
📌 Rev / Стружка-код
📌 Misc / Учебная граната
📌 Web / Десериализатор
📌 OSINT / Абрикос-персик
📌 OSINT / Лёха и кожа
Как объявлял ранее, задания теперь будут выходить по субботам в одно и тоже время – в 12:00 по МСК. Следующий релиз через неделю.
Отбивки о первых трех самых быстрых решениях на каждую задачу приходят в наш чат. Так же там можно пообщаться и обсудить сложности, если они возникают в процессе решения.
Кто первый решит, тот молодец. Поехали!
———
#⃣ #Задачи #CTF
🐞 Канал // Чат // Задачи
2 608
Новостной дайджест #2
Доброго здравия всем! Вот и наступило воскресенье, а значит — пора выпускать новости из мира ИБ и IT.
📌 Японцы временно остались без пива
Японская компания Asahi Group (что-то вроде нашей пивоваренной компании «Балтика») объявила о «сбое систем из-за кибератаки». Были остановлены приём заказов, отгрузки и работа колл-центров. В результате компании пришлось перейти на ручные операции, в приоритете у которых — еда и безалкогольные напитки. Утечки персональных данных не подтверждены, но, по сообщениям медиа, пива на всех желающих уже не хватает. Остаётся лишь ждать восстановления инфраструктуры — официальных сроков пока нет. Моё мнение: это полная катастрофа.
🌐 Источник
📌 Утечка данных авиокомпании WestJet
Канадская авиакомпания WestJet подтвердила утечку данных почти 1,2 миллионов пассажиров: имена, даты рождения, документы и детали поездок. Кредитные карты затронуты не были. Детали атаки: 13 июня была зафиксирована «подозрительная активность», после чего компания ограничила работу приложения и сайта и начала форензику. Злоумышленников описали как «сложную криминальную третью сторону», проникшую в систему. Глубоких публичных деталей — что именно затронули и кто стоит за атакой — пока нет. Остаётся загадкой.
🌐 Источник
📌 Взлом медицинского центра Shamir Medical Center
Что ж, предыдущая новость оказалась с налётом мистики, но следующая — ещё интереснее.
Группировка Qilin (растущая в масштабах атак) заявила о взломе Израильского Shamir Medical Center, выдвинув ультиматум: 700 тысяч долларов за 72 часа. Они утверждают, что похитили до 8 ТБ данных пациентов и внутренних документов. Послание было адресовано «Биби (и Бобе) и Саре». Как часто бывает в государственных интригах, здесь две версии: Qilin заявляет о полном доступе к системе, а власти пишут, что атака была обнаружена на ранней стадии и остановлена (при этом подтвердили утечку части электронных писем с медицинской информацией). Масштабы и типы украденных данных на сегодняшний день ещё уточняются. Публичного дампа данных пока нет.
🌐 Источник
📌 Новости из РФ
Хотелось бы завершить наш дайджест новостями из России за эту неделю, но их, по сути, и нет — в этот раз всё спокойно. Зато вот вам факт из отчёта за 3 октября:
Глобально DDoS-активность за полугодие выросла на 83%; Россия вошла в топ-10 по числу атак (6-е место) в мире. На первом — США, на втором — Индия, на третьем — Китай.
В России больше всего DDoS-атак пришлось на онлайн-ритейл, телекомы и образовательные организации.
🌐 Источник и больше статистики
И на этом у меня пока всё. Встретимся в следующий раз! Пишите комментарии и делитесь этими новостями с друзьями. Пока-пока!
———
#⃣ #Новости
🐞 Канал // Чат // Задачи
2 608
Площадка с CTF-задачами
📖 Как-то случайно и само собой получилось, что мы запустили сайт с тренировочными задачками. Заниматься подобным совсем не было цели, все задачи планировались как примеры к постам с разборами и пояснениями различных проблем в коде. Но как-то завертелось, ребята подключились, которые решают и которые помогают делать задачи. И теперь уже некуда отступать, нужно продолжать. Тем более, что новые участники постоянно приходят и пытаются решать.
Будем и дальше поддерживать, и развивать площадку. Только немного систематизируем подход, чтобы выходы задач были предсказуемыми и можно было честно соревноваться в скорости решения – релизы в конкретное время и день недели. Первая тройка решивших автоматически объявляется ботом в нашем чате. Чатик, кстати, тоже оживился и постоянно пополняется. Кроме статистики, там можно пообщаться про задачи, разработку и вообще на любую другую отвлеченную тему – кому интересно, заходите.
📌 Ближайшее время на площадке добавится короткие подсказки-разборы в задачах, которые имеют мало решений, чтобы можно было подсмотреть, как решать и в будущем подобную задачу уже было понятнее с какой стороны можно одолеть. Такие подсказки будут снимать часть очков за решение, чтобы было справедливое табло с рейтингом участников.
Пока плотно занимаюсь площадкой, посты по разработке и разборы выходят пореже, но они вернуться, как только появится больше свободного времени.
📌 Немного статистики по площадке:
– Сайт запущен ровно 1 месяц назад
– Опубликовано 35 заданий
– Зарегистрировалось 124 человека
– 58 человек смогли что-то решить и попасть на Scoreboard
– Сдали верных флагов: 480 штук
– Ошибочных флагов: 1156 штук
📌 Если у вас тоже есть идеи задач, не стесняйтесь и присылайте мне в личку – будем публиковать. Сейчас почти половина заданий, это те, что присылают ребята. Спасибо им за это, сам бы я точно не справился в одиночку. Авторство есть в описаниях задач, можете ознакомиться с этими героями на сайте.
❗️Важный анонс. Теперь задачи будут публиковаться по субботам в 12:00 по Московскому времени. Это может быть как одна, так и сразу несколько задач, смотря сколько успеем подготовить. Отбивки о публикациях новых задач буду выкладывать сюда в группу.
❗️И напоследок – опубликована новая задача «Мозаика внутри PNG» в категории Stegano.
———
#⃣ #Задачи #CTF
🐞 Канал // Чат // Задачи
2 608
Локальный домен devilbox показывает казино
📖 Devilbox – это локальный веб-сервер на основе Docker. Простой и удобный инструмент с кучей предустановленных версий php и приложений, нужных для веб-разработки: MySql, Redis, Elasticsearch и тд. Когда много разных проектов на php, то довольно удобно использовать и быстро переключаться.
При запуске локального веб-сервера создается локальный хост. Его можно сделать какой угодно, но по умолчанию запускается dvl.to. И уже к этому домену можно быстро создавать любые поддомены для разных локальных проектов, например, test.dvl.to или back-1.dvl.to и так далее.
Devilbox автоматически резолвит имена этих виртуальных хостов и на локальном компьютере в браузере открывается локальный проект.
📌 Но сегодня у Devilbox начались проблемы. Сперва не разобрались в чем дело – аякс-запросы из фронта к бекенду на свой же хост стали выдавать ошибки CORS, которые случаются только при запросах между разными хостами. А потом в запаре разработчик скинул в чат ссылку на свою локалку, вместо тестового хоста и тут все встало на свои места. При переходе по ссылке открылся не рабочий тестовый сайт, а сайт с казино. При повторном переходе сайт с вебкамщицами, а потом и совсем порнуха.
Оказалось, что кто-то купил домен dvl.to и настроил его dns-ы так, что сам домен и его поддомены выполняют редирект на рекламу чернухи. Проверить DNS-ы домена можно тут: https://mxtoolbox.com/SuperTool.aspx
📌 Исправляется проблема просто – нужно или изменить основной локальный домен для Devilbox или в хостах прописать ip своей локалки. Но сама ситуация интересная и очень комичная: кто-то выкупил дефолтный домен локального веб-сервера и делает редиректы на чернушную рекламу.
❗️ И анонс, который в сториз от канала уже был сегодня – в 21:00 по МСК выйдут две новые задачи на площадке с ctf-задачами.
———
#⃣ #Юмор #Devilbox
🐞 Канал // Чат // Задачи
2 608
Новостной дайджест #1
⚡️ Подборка самых интересных событий из мира информационной безопасности за эту неделю. Сбором и обработкой данных занимался Дмитрий Кустовский из команды БАГодельня.
📌 Интерлюдия
Я – Евгений Ипатов, автор канала, перестал успевать во всех направлениях, в которые стала расти БАГодельня. Как-то само собой получилось, что мы запустили площадку с задачами (там их уже 30 шт.) – туда нужно готовить таски и следить за их корректной работой. Также параллельно занимаемся разработкой полноценного сайта. Ну и основная работа у меня есть.
Однако во всей этой суете не хочется забывать про главное в БАГодельне – посты на канал. Авторские заметки с разборами задач, алгоритмами и прочими разработческими штуками никуда не денутся, просто их будет чуточку меньше, как вы уже, наверняка, заметили.
Чтобы материалов на канале не стало меньше и немного разбавить посты про задачи, добавим новую рубрику – новостной дайджест, который будет выходить раз в неделю по воскресеньям. В этом мне помогут ребята из команды, которые увлекаются OSINT-ом, это как раз их стезя.
А теперь передаю слово Диме, он приготовил классную подборку со своими комментариями.
📌 Новости из мира ИБ
📖 Привет всем! Меня зовут Дмитрий Кустовский (или же 3T0T_FL4G_1MB4). Я — молодой участник команды БАГодельня с апреля, буду вести нашу новую рубрику новостей из сферы цифровой безопасности на канале 😁
Давайте же перейдём сразу к теме.
⚡️ Открывает рубрику у нас новость из Америки, где подросток взломал казино. Ему не пришлось как-то ломать подсеть или в целом прибегать к манипуляциям с кодом. Он просто... прикинулся айтишником компании и через LinkedIn убедил техподдержку сбросить пароль. Ну и дальше по классике: появился доступ к внутренним сервисам, а после этого — сбои в работе самого казино. Итог такой деятельности — ущерб в 100 МИЛЛИОНОВ долларов.
Более подробно в источнике.
⚡️ Идём дальше, и КРУЧЕ. В Иране буквально рухнул крупнейший банк Sepah — клиенты лишились доступа как к онлайн-сервису, так и к банкоматам. И здесь без преуменьшения, ведь при попытке переключиться на резервные площадки было также невозможно — хакеры и тут постарались, всё повреждено. Даже есть информация о том, что был не только удалённый взлом, но и физический.
Можно сказать, банк какой-то невезучий. Всё потому, что на ЭТОТ ЖЕ банк ранее совершила атаку другая хакерская группа. Они украли 12 ТБ данных (около 42 миллионов клиентов). В них вошли пароли, совершённые транзакции и аккаунты. Группировка требовала выкуп в размере 42 миллионов долларов в биткоинах взамен на то, что они не сольют данные в сеть. Банк старался успокоить народ и отрицал взлом, на что хакеры выпустили в сеть часть данных.
Подробнее про невезучий банк: тут.
⚡️ И напоследок — ближе к нашим краям. 22 августа на наш портал «Госуслуги» была совершена массовая DDoS-атака из-за рубежа. Всего за час, по данным Downdetector, было зафиксировано 122 жалобы на работу портала, а за сутки — 1271 жалоба. В тот же период велись крупные атаки на другие государственные сервисы. По информации — ничего не пострадало, кроме нервов людей, кому понадобились Госуслуги в тот момент. Все отбились, всё хорошо.
Подробнее в источнике.
👨💻 И на этой ноте завершаю нашу сводку новостей. Буду и дальше сёрфить интернет в поисках интересной информации для вас! Встретимся в следующее воскресенье!
❗️Ждем ваши комментарии по этим новостям и в целом по новому формату – пишите под постом или сразу в наш чат.
———
#⃣ #Новости
🐞 Канал // Чат // Задачи
2 608
Призовая задача «Двери»
❗️ Эта задача анонсировалась заранее и за ее решение первая тройка решивших получит небольшие призы: 3 месяца премиум в телеграм. Решения в призовой зачет принимаются до 4 октября 12:00 по МСК.
📌 В этот раз задание разбито на две части.
Первая в категории Stegano – «Дверь», ее решение помимо флага, дает подсказку и доступ ко второй части челенджа – задача из категории Misc «Двери».
Для получения приза необходимо решить обе задач, успеть сделать это за неделю, и стать одним из трех самых быстрых.
📌 Ответы в зачет принимаются до 4 октября 12:00 МСК, есть ровно неделя на решение. Потом будет пост с полным разбором этой задачи и объявлением победителей.
Кто первый, тот молодец. Поехали!
❗️ Ссылки на задачи:
– Первую часть: Дверь
– Вторая часть: Двери
———
#⃣ #Задачи #CTF #Misc
🐞 Канал // Чат // Задачи
2 608
Задача «Практикующий жонглер» от DUCKERZ
📖 Ребята из DUCKERZ – команда CTF-еров, у которых тоже есть площадка с задачами, прислали нам челендж из категории web. Он уже опубликован на сайте – «Практикующий жонглер».
Давайте пробовать решать :) И как всегда, если будут сложности – заходите в чат, там можем обсудить и помочь друг другу! А кто первый справится, тот молодец. Поехали!
Решать задачу: Практикующий жонглер.
❗️P.S. Прошлую неделю пропустили, но в эту субботу в 12:00 по МСК выйдет призовая задача на скорость, символические призы получит первая тройка самых быстрых.
———
#⃣ #Задачи #CTF #Web
🐞 Канал // Чат // Задачи
2 608
Слепая SQL-инъекция. Часть 2
Вторая часть, продолжение предыдущего поста «Слепая 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. Инструмент умеет автоматически определять СУБД, извлекать имена БД, имена и структуры таблиц, а так же собирать и выкачивать полный дамп базы данных.
📌 Инструменты – это хорошо, но в самых не стандартных ситуациях спасают только самодельные скрипты. К тому же написание скриптов это еще и гимнастика для мозгов, а самое главное – способ детальнее погрузиться в тему и разобраться в вопросе более детально. Хорошо пользоваться готовым инструментов, когда понимаешь как он устроен. Поэтому для примеров решения задачек прикладываю еще два скрипта, которые помогут более детально разобраться в способах применения слепой инъекции.
📌 Скрипты нахождения флагов из тестовых задачек на тему поста:
Первый скрипт – простой брутфорс флага из таблицы по одному символу: скрипт.
Второй скрипт, который использует бинарный поиск для оптимизации и ускорения: скрипт.
❗️ Потренировать можно тут:
– Слепая инъекция
– Совсем слепая инъекция
———
#⃣ #SQL #БазаЗнаний
🐞 Канал // Чат // Задачи2 608
Слепая SQL-инъекция. Часть 1
📖 Про 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, которая генерирует рандомные байты, и если запросить большое количество, то запрос может подвисать на несколько секунд.
📌 Как защититься
Точно так же, как и с другими типами инъекций – экранировать все данные, которые используются в запросах. Вредоносные данные могут приходить на публичные эндпоинты и на приватные, через другие методы или прослойки. Любой запрос к базе данных должен быть экранирован, даже если он на прямую не использует публичные данные.
❗️Для тестирования подобных инъекций опубликовано две задачи на нашей площадке, на них можно потренироваться:
– Слепая инъекция
– Совсем слепая инъекция
👨💻 Не влезает все в один пост. Тут только теоретическая часть, следом выйдет второй пост со скриптами и описанием инструментов.
———
#⃣ #SQL #БазаЗнаний
🐞 Канал // Чат // Задачи2 608
Задача «Тест по YAML». Разбор и победители
📖 6 сентября запускали задачку «Тест по YAML», за ее решения были назначены призы первым трем решившим. Задачу на данный момент одолели шесть человек.
Первая тройка по времени решения:
🥇 fASTYYY – приз 3 месяца премиум телеграм вручен
🥈 AlexB – приз 250 звезд телеграм вручен
🥉 xof – приз 100 звезд телеграм. Отказался от приза в пользу фонда развития БАГодельни 😁
Поздравляю! Кому интересна задача, можно попробовать свои силы тут: площадка с задачами.
📌 Разбор задачи
Смысл задания был в том, чтобы передать не сервер такой текст Yaml, который будет парситься двумя версиями Yaml: 1.1 и 1.2. И результат парсинга должен отличаться, не равные результаты нужно получить, причем версия 1.1 должна сформировать число 1337.
Задача показывает, как сильно могут отличаться парсеры в зависимости от версии. И что это нужно учитывать в разработке, чтобы не попасть в неприятности при обновлении библиотек или рефакторинге кода. К тому же, кроме отличий в версиях парсинга, Yaml в некоторых случаях выполняет преобразования значений весьма неочевидным образом, что тоже может легко привести к неприятным сюрпризам. Есть очень наглядный квиз, который показывает проблемы и странное поведение Yaml. Проверить свои навыки можно в задаче(часть показано в тесте) и в оригинальном квизе, откуда скопированы эти вопросы(тут из больше - 22 шт): ohyaml.wtf.
📌 Решение
Решить можно было несколькими способами. Я знаю два решения, но подозреваю, что можно придумать еще несколько, если кто-то знает еще варианты – присылайте в комментарии.
Первое решение
Yaml версии 1.1 поддерживает шестидесятеричное число, которые можно передавать в формате a:b, которое потом преобразуется в десятичное по формуле a * 60 + b. Видимо, эта функция высчитывала количество минут, если передать часы:минуты. Но в версии Yaml 1.2 такая запись уже не обрабатывается и парсится как обычная строка. Поэтому если передать 22:17, то в версии 1.1 это будет
22 * 60 + 17 = 1337. А в 1.2 это просто строка «22:17». Таким образом значения будут отличаться, и версия 1.1 сформирует нужное, для получения флага, значение
Второе решение
Решение основано также на системе исчисления, только уже восьмеричной. Если Yaml 1.1 обрабатывает значение, которое имеет ведущий ноль и остальные цифры не превышают 7, то такое значение конвертируется из восьмеричного в десятичное число. Поэтому, если парсить 02471, то версия 1.1 преобразует его в десятичное 1337. А Yaml версии 1.2 посчитает такое значение строкой и оставит «02471».
📌 Полезные ссылки
– Попробовать решить задачку: тут
– Квиз про парсинг в Yaml: ohyaml.wtf
– Статья на Habr: «YAML из Ада»
———
#⃣ #Задачи #Разбор #CTF
🐞 Канал // Чат // Задачи2 608
Выборка WHERE txt_field = 0 для текстовых полей
📖 Сразу оговорюсь – я понимаю, что никому в здравом уме не придет идея делать подобные запросы умышлено. Но понимание таких нюансов может пригодиться для упрощения дебага, а также при каких-то нестандартных ситуациях, не связанных с разработкой для продакшена.
Как раз во время поиска проблемы с выборками из БД и был обнаружен подобный запрос. В коде был баг, который при определенных обстоятельствах превращал параметр строкового ключа в число ноль и в типе 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——— #⃣ #Костыли #sql #Типы 🐞 Канал // Чат // Задачи
2 608
Алгоритм Ray Casting
📖 При работе с картами или любой другой сеткой координат, иногда нужно определить, находится ли объект внутри области или за ее пределами. Самый частый и наглядный случай, с которым приходилось сталкиваться в работе с вебом – это определение доступности адреса в конкретной зоне доставки. Первый раз, когда с подобным столкнулись, начали выдумывать свой алгоритм, но быстро сообразили, что должны быть и готовые формулы и алгоритмы. Так и оказалось.
📌 Ray Casting – простой, но очень действенный алгоритм для определения положения точки относительно многоугольной области: точка находится внутри или снаружи. Для проверки положения, из точки выпускается луч право и считается сколько произошло пересечений с областью. Если пересечений четное количество, то точка находится за пределами области, а если не четное, то внутри. Ноль – четное число, тут нет противоречий или дополнительных обработок, логика не ломается. Для наглядности, в картинке к посту добавил область на карте и трех жуков, от них отходят лучи. И только у того, кто внутри треугольника, луч пересекает зону нечетное количество раз – единожды. Для не областей с стандартными формами, пересечений может быть 3, 5, 7 и тд. Но все равно условие с четностью будет выполняться.
Чтобы рассчитать количество пересечений, есть математическая формула:
xIntersection = xj + (y - yj) * (xi - xj) / (yi - yj)Это уравнение прямой через две точки (xj,yj) и (xi,yi), решенное относительно x при заданном y. Зная эту формула, написать метод определения положения точки относительно области, уже дело техники. Для примера можно посчитать географические координаты, используя долготу и широту:
function isPointInPolygon(point, polygon) {
const { lng: pointX, lat: pointY } = point;
let isInside = false;
// Проходим по всем ребрам многоугольника
for (let currentIndex = 0, previousIndex = polygon.length - 1;
currentIndex < polygon.length;
previousIndex = currentIndex++) {
const currentVertex = polygon[currentIndex];
const previousVertex = polygon[previousIndex];
const { lng: currentX, lat: currentY } = currentVertex;
const { lng: previousX, lat: previousY } = previousVertex;
// Проверяем, пересекает ли луч ребро
const isRayCrossingEdge = (currentY > pointY) !== (previousY > pointY);
const edgeIntersectionX = previousX +
(pointY - previousY) * (currentX - previousX) / (currentY - previousY);
if (isRayCrossingEdge && pointX < edgeIntersectionX) {
isInside = !isInside;
}
}
return isInside;
}
И пример использования:
const deliveryZone = [
{ lng: 34.349, lat: 53.417 },
{ lng: 34.066, lat: 53.141 },
{ lng: 34.706, lat: 53.150 },
];
const clientAddress = { lng: 34.350, lat: 53.410 };
console.log(isPointInPolygon(clientAddress, deliveryZone));
👨💻 Код можно запустить онлайн тут: ссылка.
❗️Такой расчет можно делать не только с географической картой, но и любой другой 2d сеткой координат.
———
#⃣ #БазаЗнаний #RayCasting
🐞 Канал // Чат // Задачи2 608
Файлы .git в публичной папке
📖 Контроль версий кода – удобный инструмент, уже давно без него не представляется ни одна разработка. Я еще немного застал системы контроля версий svn, потом mercurial, а потом и git, который сейчас стал стандартом и, кажется, нет альтернатив. Каждый проект имеет свой git-репозиторий, который зачастую попадает в продакшен или вообще используется для деплоя. Да, не все приложения разворачиваются с докерами, куберами и прочим, очень много реальных и живых проектов все еще используют ci/cd с набором скриптов для автоматического стягивания с репозитория и последующего билда. И есть такие, которые полностью в ручном режиме релизятся. Такие решения даже могут быть оправданы. Но не об этом пост. Это я все к тому, что так или иначе зачастую на продакшене оказывается актуальный репозиторий, а вместе с ним и все его файлы настроек, объектов, логов, хуков и всего остального. Бывает такое, что папка .git попадает на прод и это факт. И встречается это куда чаще, чем отлаженные инфраструктуры с ci/cd и прочими примочками.
📌 То, что папка .git зачастую лежит в продакшене – это реальность. Это не плохо и не хорошо, такую ситуацию диктуют куча разных условий, которые для каждого проекта свои. Но очень плохо и не безопасно то, что .git с завидной регулярностью упускается разработчиками из виду и попадает не просто в продакшен, а в публичную папку. Если не позаботиться о приватности, то весь репозиторий со всеми его ветками и коммитами, можно легко найти и полностью скачать. А имея полный доступ к кодовой базе и истории коммитов, найти уязвимость в проекте становится делом времени. И если еще в коде захардкожены доступы или файлы конфигов находятся под контролем версий, то это совсем уже печально и такая находка сродни получению полного доступа.
📌 Как эксплуатировать
Если .git оказалась в публичной папке, то скорее всего это будет корень проекта. Поэтому самый простой способ обнаружить открытый репозиторий, это «дернуть» файл с конфигурацией, который есть в каждой папке .git, по урлу:
хост/.git/config. Если папка доступна, то получится скачать файл конфигурации. Цель найдена, остается выкачать все файлы. «Руками» такое сделать не реально для больших репозиториев, поэтому нужна автоматизация. Можно написать свой парсер, а можно воспользоваться готовым инструментом git-dumper. Git-dumper работает на python и установить его можно через pip:
pip install git-dumper
И остается только запустить git-dumper, указав адрес сайта-цели и папку, в которую скачать весь .git:
git-dumper http://хост.com ./folderГотово. А что делать со скаченной папкой .git всем и так понятно — удалить, а о существующей проблеме с безопасностью сообщить владельцу ресурса, откуда выкачали репозиторий. 📌 Как защититься Чтобы папка не была доступна, ее нужно выносить на уровень выше, чем публичная. Тогда она будет недоступна по http. Но такой подход подразумевает изменение вложенности, если такое сложно и трудозатратно организовать, то можно закрыть доступ на уровне сервера. Для nginx это делается через конфиг для хоста:
location ~ /\.git {
deny all;
}
А для веб-сервера Apache нужно добавить правило в .htaccess:
<DirectoryMatch "/\.git">
Order allow,deny
Deny from all
</DirectoryMatch>
📌 Тренировка:
Для тестирования эксплуатации этой уязвимости запущенна задачка «Старый коммит» на нашей площадке с коллекцией челенджей. А если будут сложности, то приходите в чат, там можно пообщаться и задать вопросы.
———
#⃣ #БазаЗнаний #Web #git
🐞 Канал // Чат // Задачи2 608
Задача «Тест по YAML»
❗️ Эта задача анонсировалась заранее и будет небольшое награждение первой тройки решивших. Призы символические, но так интереснее, чтобы был небольшой азарт.
Ссылка на задачу на нашей площадке: задание.
📌 Исходники бекендовой части задачи прикреплены на сайте.
Описание задачи не большое:
Для получения флага, нужно получить 1337 очков в тесте, где представлены 7 вопросов про парсинг YAML-файлов. Ответы проверяются в бекенде, по запросу с фронта.
📌 Заявки принимаются на сайте с задачами, где фиксируется время отправки и валидность флага. Про первые три решения автоматически сообщает бот в нашем чате.
Ответы в зачет принимаются до 12 сентября 12:00 МСК, есть ровно неделя на решение. Далее будет пост с полным разбором этой задачи и объявлением победителей.
Кто первый, тот молодец. Поехали!
❗️ Ссылка на задачу: перейти.
———
#⃣ #Задачи #CTF
🐞 Канал // Чат // Задачи
2 608
Как хранить и обрабатывать деньги?
❗️ Быстрый ответ на вопрос. Храните свои деньги в сберегательной кассе. А если это чужие деньги, то лучше их хранить в базе данных в полях с типами
INTEGER, BIGINT, NUMERIC или специализированным типом Money, если его поддерживает СУБД. Но никак не в типах с плавающей точкой, это приведет к ошибкам и появлению лишнего или потере существующего баланса. Деньги обязательно должны храниться и обрабатываться только в целочисленных типах данных. А если нужны копейки, то число должно быть умножено на 100, а при необходимости форматированного вывода, достаточно обратно поделить на 100 и вывести целую и дробную части. Иногда можно гранить рубли и копейки в разных полях, но все также в целочисленных типах данных. Аналогично должна происходить и логика обработки в коде, а не только хранение.
📌 Для наглядности: 0.1 + 0.2 !== 0.3 – это условие вернет true. Например, в js 0.1 + 0.2 = 0.30000000000000004. В других языках ситуация такая же. Это небольшая погрешность, но при работе с крупными объемами данных и большим количеством операций над этими значениями, можно получить серьезную проблему.
Почему так происходит? Числа с плавающей точкой хранятся в двоичной системе исчисления по стандарту IEEE 754. Это не ошибка языка, а следствие того, что числа 0.1 и 0.2 являются бесконечными дробями в двоичной системе, так же как 1/3 (0.33333...) является бесконечной дробью в десятичной системе исчисления. То есть это нормальное поведение чисел и об этом нужно знать при работе с деньгами, иначе такой очень маленький(0.00000000000000004) «хвост» может вызвать кучу проблем.
📌 На тему поста для демонстрации проблемы опубликована задача: Обменник валют «У Апишечки». В задаче приложен код с ошибкой в типах данных, и если правильно воспользоваться этой проблемой, то можно увеличить свой баланс счета. Попробуйте решить, а если возникнут сложности, то приходите в чат, там можно спросить помощи или подсказку, а также там выходят анонсы новых небольших и простеньких задач, про которые не упоминается в канале.
———
#⃣ #БазаЗнаний #Ошибки
🐞 Канал // Чат // Задачи2 608
Запуск сайта с задачами
📖 В недавнем опросе по поводу тем постов и сложности задач, которые периодически публикуются тут в канале, мнения разделились – кому-то нужны полегче, а кому-то посложнее задачи. Но постить все подряд сюда в канал будет неудобно, вся лента только из задач и будет состоять, если публиковать и простые челенджи, а нужно еще оставить место и для основной тематики – заметки про разработку и разборы задач. А также хочется вести общий рейтинг по очкам участников за всю истории, и автоматизировать уведомления про первые три решения, это нужно для определения победителей в задачах с призами. Да и в целом, собрать все в одном месте будет удобнее, чем искать задачи по ленте в телеграм.
📌 Поэтому решено запустить сайт с коллекцией задач. Пока там постоянно будет находиться только такие задачи, которые не требуют отдельных инстансов на сервере и не отнимают много ресурсов. Но в будущем, если будет интерес, то может доработаем площадку.
Сайт уже заработал и там есть шесть задач – две старые, которые уже упоминались в канале и четыре новые. Можно переходить и решать: ссылка.
Две задачки из новых вчера ребята начали уже разбирать – в чате канала был предварительный анонс, а еще две совсем новые, они опубликованы одновременно с этим постом. Еще можно успеть решить первым!
📌 Новые задачи, которые еще не видели в канале:
– OSINT / Поездка: Беларусь
– OSINT / Смертельный интим
– STEGO / Комариный писк
– MISC / Лабиринт
Эти задачки прилично проще, чем те, что решали в канале, поэтому у всех есть возможность решить. Вперед!
❗️ Сайт с задачами: https://ctf.bug-makers.ru
———
#⃣ #CTF #Задачи
🐞БАГодельня: Канал // Чат // Задачи
2 608
Игра «Сапер». Пример использования алгоритма DFS
📖 В прошлом году ездил в столицу на поезде и взял с собой ноутбук, но не скачал туда ничего посмотреть или послушать. В дороге без интернета скучно, и чтобы чем-то заняться, написал «Сапёра». Сама по себе игра не сложная в реализации, но есть один интересный момент. Когда игрок кликает по клетке с «нулем» – ячейка поля, в которой нет мин и во всех соседних клетках тоже пусто, то должна открыться сразу вся область поля соседствующими «нулями». То есть открывается часть поля, со всеми соседствующими клетками с нулями, пока не встретится граница или ячейка с цифрами (от 1 до 8, зависит от количества клеток-соседей с минами).
Если начать выдумывать свой алгоритм раскрытия поля с пустыми ячейками, то можно прилично закопаться в условиях и циклах. Именно этим я и занялся сперва – начал мудрить свой алгоритм. Но закопавшись в ветвлении логики, начал вспоминать алгоритмы, которые кроме как в тренировочных задачах, больше особо и не использовал раньше. Может быть, у кого-то в рабочих задачах и пригождаются алгоритмы каждый день, но я с ними пересекаюсь только во всяких учебных и тренировочных задачах или в описании статей. Поэтому нужный алгоритм пришел на ум не сразу и сперва занимался дурью с условиями и изобретал свое решение.
📌 Для такой задачи идеально подходит DFS – поиск по графу в глубину. Если кто понимает за асимптотику, то сложность этого алгоритма O(n), то есть линейная – время работы алгоритма линейно с увеличением размера входных данных. Это очень хороший показатель для алгоритма. Смысл алгоритма заключается в рекурсивном обходе всех соседей и сборе массива валидных координат. Так без лишних условий можно пробежаться по всем соседям и собрать нужные ячейки, которые будут открыты.
Для наглядности код алгоритма на примере поиска пустых ячеек в сапере:
function findAllEmptyCells(matrix, startY, startX) {
// Размер игрового поля
const rows = matrix.length;
const cols = matrix[0].length;
// Направления поиска соседей:
// Вверх, влево, вниз, вправо
const directions = [[-1,0], [0,-1], [1,0], [0,1]];
// Матрица посещённых клеток
const visited = [];
const result = [];
function dfs(y, x) {
// Проверка границ, значений из клеток соседей
// и актуальность посещения клетки
if (y < 0 || y >= rows || x < 0 || x >= cols || matrix[y][x] !== 0 || visited[y][x]) {
return;
}
// Помечаем ячейку как посещенную
visited[y][x] = true;
// Добавляем координаты в результат
result.push([y, x]);
// Рекурсивно проверяем всех соседей
for (const [dy, dx] of directions) {
dfs(y + dy, x + dx);
}
}
dfs(startY, startX);
return result;
}
📌 Для наглядности еще пример, как отработает алгоритм.
Допустим, у нас есть поле:
[1, 1, 1, 0] [1, 0, 0, 1] [0, 0, 1, 1]При клике на ячейку
[1,1] (значение 0), алгоритм найдет все связанные пустые ячейки и вернет матрицу координат этих нулей: [[1,1], [1,2], [2,0], [2,1]]
Решение получается очень простым и предсказуемым. Но чтобы его написать, нужно иметь в запасе какой-то набор базовых алгоритмов. Учить наизусть подобные алгоритмы нет смысла, но понимать, как они работают и знать про их существование не будет лишним. Учить наизусть только для собесов надо, на сколько я понимаю 😁. А в реальных задачах такое не часто встречается и достаточно просто знать и вовремя вспоминать, чтобы можно было нагуглить описание и применить. Это мое мнение, не призываю никого, если есть желание заучивать, то занимайтесь)
💣 Полный код сапера можно посмотреть в моем github, реализован на js.
А так же можно поиграть и потестить логику, билд тут: Сапёр.
———
#⃣ #DFS #Алгоритмы #Сапер
🐞БАГодельня: Канал // Чат2 608
Задача «Тихий страж». Решение 2
Решение задачки из поста от 20 августа: описание задачи
Бинарник для тренировки реверса и его исходник можно скачать тут: github https://github.com/Ipatov/CTF-Silent-Guardian
📌 Второе решение. Полный реверсинг бинарника
Для реверса бинарника, его сперва нужно выкачать. Самый простой способ – это подключиться к серверу, закодировать файл ctf в base64, и полученную строку у себя на компьютере обратно сконвертировать в бинарник:
Кодируем:
cat ./ctf | base64
Сохраняем бинарник: echo "строка_base64" | base64 -d > output_binary
Теперь нужно сделать дизассемблирование бинарника, для этого есть программы: бесплтаная Ghidra и IDA(платная и бесплатная версии). Обе программы работают примерно одинаково. Запускаем приложение и выбираем нужный бинарник, на выходе получаем список функций и их код, используемые данные, которые зашиты в бинарнике, а также получаем схему логики – ее кусочек на превью поста, это скрин из IDA.
Код бинарника после реверса отображается кодом ассемблера. Но ассемблер сложноват для восприятия, однако его можно перевести в си-подобный псевдокод. Конвертировать умеет и Ghidra и IDA – с этим нет проблем. Поэтому переводим код в си-подобный и смотрим, что происходит внутри бинарника.
Для тех, у кого нет установленных программ для реверса, залил самые интересные куски псевдокода в гитхаб: github. В репозитории полный код функций main и sub_1345, а также объект с данными .rodata – это статичные данные, которые хранятся внутри скомпилированного приложения, они нам тоже пригодятся.
Когда бинарник декомпилирован начинаем анализировать полученный код, первым делом находим точку входа – это функция start, там будет вызов функций с логикой, в данным случае это main. Внутри функции main сразу же находим нужный нам участок, вот самое интересное:
if ( !strcmp(buf, "/flag") )
{
v6 = (unsigned __int8 *)sub_1345(&unk_2030, 26, "YnJ1aA==", 8);
if ( v6 )
{
for ( i = 0; i != 26; ++i )
{
v8 = v6[i];
putchar(v8);
}
free(v6);
}
}
Псевдокод нормально читается, и из него становится ясно, что запущенный процесс ждет строку «/flag», которую мы передавали в первом варианте решения. Далее происходит какая-то обработка данных из переменной unk_2030 внутри функции sub_1345, а итоговый результат выводится в stdout.
Нужно теперь разобраться, что делает функция sub_1345 и найти значение переменной unk_2030. Анализируем код sub_1345:
_BYTE *__fastcall sub_1345(__int64 a1, size_t a2, __int64 a3, unsigned __int64 a4)
{
_BYTE *v8; // rdi
size_t v9; // rsi
v8 = malloc(a2);
v9 = 0;
do
{
v8[v9] = *(_BYTE *)(a1 + v9) ^ *(_BYTE *)(a3 + v9 % a4);
++v9;
}
while ( v9 < a2 );
return v8;
}
Это простая логика XOR-а, где по байты ключа ксора используются по очереди и по кругу, если длина ключа короче зашифрованной строки. Если код не читается, то его можно переписать на более понятный – это нейронки хорошо умеют, но за ними нужно перепроверять. Один раз нарывался на то, что нейронка неправильно отформатировала код и потратил пол дня, пока не понял, что копаюсь с неправильным куском логики.
Теперь мы знаем, что для получения флага, нужно выполнить xor для значения из unk_2030 с ключом «YnJ1aA==». Ключ, кстати, был виден в первом решении, когда выполнялся strings для изучения бинарника.
Остается найти значение unk_2030 – оно хранится в .rodata, разбитое по байтам. Забираем его оттуда и выполняем преобразование xor-ом. Чтобы не считать ксор руками, можно написать простой скрипт, например, на питоне: скрипт / запустить. Раскодированная строка — это наш флаг. Победа!
❗️ Важный анонс
Следующая задача будет запущена 6 сентября в 12:00 по МСК. Категория web. За первые три решения будут призы: 3 месяца премиума в телеграм, 250 и 100 звезд. Не пропустите 😁
———
#⃣ #CTF #РазборыЗадач
🐞БАГодельня: Канал // Чат2 608
Задача «Тихий страж». Решение 1
Решение задачки из поста от 20 августа: описание задачи.
Подключение к серверу будет доступно еще все выходные, можно попробовать порешать после прочтения этого разбора.
Бинарник для тренировки реверса и его исходник можно скачать тут: github.
📖 Кратко суть задачи: есть доступ к серверу, где нужно найти флаг. При подключении сразу виден бинарник и скрипт, в котором описан запуск этого бинарника. Так же из условия задачи понятно, что нужно либо реверсить бинарный файл либо найти запущенный процесс и передать ему ключ.
📌 Первое решение. Через анализ системы и бинарника
В первую очередь после подключения к серверу смотрим, какие файлы нам доступны:
> ls -la -rwxr-xr-x 1 ctfuser ctfuser 14072 Aug 20 20:18 ctf -rwxr-xr-x 1 ctfuser ctfuser 56 Aug 20 20:17 entrypoint.shИз содержимого entrypoint.sh понимаем, что в системе скорее всего запущен бинарник ctf. Поэтому стоит проверить, работает он еще или нет:
> ps aux | grep ctf 8 ctfuser 0:00 ./ctfИ замечаем, что процесс запущен в системе, его PID = 8. Теперь нужно понять, что делает этот процесс и с чем взаимодействует. Одна из подсказок была, про то, что всё в linux – это файлы. Проверяем наш процесс с помощью lsof:
> lsof -p 8 8 /home/ctfuser/ctf 0 /dev/null 8 /home/ctfuser/ctf 1 pipe:[58609665] 8 /home/ctfuser/ctf 2 pipe:[58609666] 8 /home/ctfuser/ctf 4 pipe:[58608517] 8 /home/ctfuser/ctf 69 pipe:[58608517]В ответе для нас самый интересный третий столбец, он хранит FD (File Descriptor) — числовой идентификатор, который процесс использует для работы с этим открытым файлом. FD 0 — это стандартный ввод (stdin). FD 1 — вывод (stdout). FD 2 — вывод ошибок (stderr). А вот FD 4 и FD 69 — это дополнительные файловые дескрипторы. И они оба подключены к одному и тому же каналу (58608517). Поскольку по условию задачи нам нужно найти «Стража» и сказать передать ему правильную команду, то скорее всего какой-то из нестандартных FD настроен на чтение данных. И чтобы отправить строку процессу нужно записать строку через файловый дескриптор:
echo "строка" > /proc/$PID/fd/$FD, где $PID – это PID процесса, у нас это 8, а $FD – файловый дескриптор 4 или 69.
📌 Остается понять, какие данные нужно передать. Возвращаемся к условию задачи и там находим, что «Кодовая фраза где-то рядом... возможно, даже в самом бинарнике». Тут мы можем сделать дизассемблирование бинарника или сперва попробовать просто извлечь из него все доступные строки. Пробуем вариант попороще – извлекаем строки с помощью утилиты strings и анализируем содержимое:
> strings ./ctf ... __libc_start_main free libc.musl-x86_64.so.1 __deregister_frame_info ATUSH |$xH ... pipe dup2 /flag read YnJ1aA== d@Sn ;*3$" GCC: (Alpine 14.2.0) 14.2.0 .shstrtab ...Часть вывода я отрезал – там лишнее и заметил троеточием. В выводе замечаем несколько не стандартных строк – это
/flag и YnJ1aA==. Вторая часть это base64 строка, раскодируем ее на всякий случай, получаем bruh. Но строка /flag больше всего подходит под «команду для стража», поскольку в начале строки есть слеш и в целом «flag» уже хранит намек. Пробуем отправить эту строку нашему стражу:
> echo "/flag" > /proc/8/fd/4
BugCTF{FD_69_IS_THE_KEY}
Сработало! Флаг получен. Это работает с fd 4 и 69, оба дескриптора принимают значение и отдают флаг, если строка с командой корректная.
❗️Второй способ решения – через реверсиинг бинарника, не влезает в этот пост, не хватает лимита телеграмм. Опубликую вечером вторым постом.
———
#⃣ #CTF #РазборыЗадач
🐞БАГодельня: Канал // Чат2 608
Костылим со всей силы в 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-запросов, кидайте в комментарии, может быть есть более простые или интересные варианты.
———
#️⃣ #sql #костыли
🐞БАГодельня: Канал // Чат