Конкурс завершился!
Результаты конкурса
Решили задачу 3 человека:
Первый решил
sinner67 максимально близко к задуманному
Второй решил
Bidjo111 раскрутив таск вслепую
Третий решил
SooLFaa грязновато, но всё же результат получил
sinner67 сказал, что он решает вне конкурса, чисто для себя. Таким образом результаты выглядят так:
1 место - Bidjo111
2 место - SooLFaa
3 место - не занял никто
Что я задумывал в задаче:
Сделать её достаточно сложной, амбициозной, но одновременно решаемой несложными запросами.
Сделать решение невозможным при помощи автоматизированных программ, и наглядно показать что "sqlmap не панацея".
Мои впечатления и наблюдения:
Таск задумывался чтобы оценить общий уровень подготовки форумчан. К большому сожалению он оказался весьма низким. Я рассчитывал, что решивших будет больше. Я считаю, что такие уязвимости как SQL и XSS, все интересующиеся ИБ должны знать не ниже чем на среднем уровне. Эти уязвимости бессменно входят в OWASP Top 10.
Хочу сказать огромное спасибо ВСЕМ кто участвовал в конкурсе! Ваша активность была колоссальной!!! Сервер кряхтел и дымился от шквала запросов.
Несмотря на мои многократные предупреждения, насчёт использования программ, 99% запросов были автоматическими. И лишь неделю спустя после старта конкурса, стало заметно больше ручных запросов.
По ходу конкурса я не раз давал намёки, а потом и подсказки. Тем не менее решивших очень мало. Я покажу вам наглядный пример, как один из участников
Bidjo111 проявил внимательность к моим комментариям, и поэтому смог решить таск ещё до выкладывания конкретных подсказок.
Bidjo111 прислал мне отчёт по таску, которым я просто зачитался.
Выражаю огромную благодарность тебе за столь замечательное описание прохождения задачи!!!
-------------------------------------------------------------
Отчёт от Bidjo111:
Настроившись на то, что таск будет сложным, сразу же начал решать не с того конца. Вместо подстановки одного из самых популярных параметров в запрос GET, я начал искать уязвимость в заголовках http. Перепробовав кучу вариантов все-таки вспомнил про самый простой. Вспоминается совет на форумах HTB, где одной из самых часто встречаемых подсказок является ”Don’t overthink”.
Итак мы имеем:
?id=1
...что дает нам задуманный разработчиком результат.
Далее, разумеется, сразу полетела кавычка, которая получила в ответ алерт. Так как я заранее знал, что на этой странице должна присутствовать инъекция, то закомментировал строку всеми способами, которые помнил. Но ни один из них не сработал. Далее подставлял другие кавычки, игрался со скобками и т.п. Попробовав разные комбинации с символами вспомнил, что помимо кавычек и скобок уязвимость может быть в ошибке логики запроса. И тут, сделав вполне закономерный запрос, но категорически неправильный вывод, я совершил фатальную ошибку:
?id=0 or 1
...который выдает результат при
id=1 и
?id=0 or 0
...который выдает результат при
id=0. Идеально.
Обрадовавшись, что нашел точку, где сейчас мигом все раскручу, провел много часов, получая в ответ очень странные результаты. И, конечно, дальше ничего не вышло.
Дальше в ход пошел брат Гугл, всевозможные мануалы, методички из курса WAPT. Тут я совершил вторую ошибку. Проштудировав вдоль и поперек материалы курса, в моей голове в переменной
методичка было решительно выставлено значение
«полностью усвоено», отчего впоследствии я к ней не возвращался ни разу, что в дальнейшем кардинально повлияло на ход решения.
Прочитав первый намек создателя таска на то, что подсказка находится в его статьях, полез читать их, перечитывать и разбирать все мало-мальски непонятные моменты. Тут уже и наткнулся на комментарий вида
;%00, который прекрасно подошел к запросу
?id=1’;%00
Дальше следовали многие часы долбежки в стену головой из-за того самого неправильного вывода, пробела и операторов
and и
or. Причем все трое тихонько отфильтровывались и я получал ерунду на выходе. Западня заключалась в том, что в большинстве запросов я одновременно использовал и пробел и оператор сравнения и догадаться, что они могут оба фильтроваться я никак не мог. Часто приходили мысли о том, что что-то из этого отбрасывается, применял соответствующие техники, но не одновременно к обоим объектам.
Так за пару дней по много часов в вышеуказанный запрос было впихнуто все, что только можно и нельзя. Наконец-то сработал один запрос:
?id=0’ %7c%7c sleep(10);%00
Настроение улучшилось, так как наконец-то найден способ влиять на БД. Тут уже стало ясно, что и
and и
or отбрасываются фильтром, и про символ пробела я на время уж тем более забил. Дальше по технике
timebased стал потихоньку раскручивать это дело. Получалось что-то вроде этого:
/?id=1’ %26%26 if(true,sleep(3),0);%00
...этот запрос работал, за ним шел
?id=1’ %26%26 if((ascii(substring(‘a’,1,1))>96),sleep(3),0);%00
...который тоже работал. Решив, что дело в шляпе тут же шмальнул
?id=1’ %26%26 if((ascii(substring((select database()),1,1))>96),sleep(3),0);%00
Тут я растерялся ибо все шло вроде нормально, и на ровном месте запрос не сработал. Напомню, что про пробел я на тот момент еще не знал. Более того в начале запроса стояли пробелы и, не смотря на это, все работало. Перепробовав разные варианты я чуть ли не случайно сделал следующий запрос
?id=1’ %26%26 if((ascii(substring((database()),1,1))>96),sleep(3),0);%00
...и был в шоке. Запрос дал задержку по времени.
Вытащив название базы и юзера начал уже мозговать, отчего и почему так. Стал разбирать не “почему работает без select”, а “почему
НЕ работает
С select”. Решив, что
SELECT как-то фильтруется, стал применять техники обхода. Каково было мое удивление, когда сработал следующий запрос:
?id=1’ %26%26 if((ascii(substring((select @@version),1,1))>96),sleep(3),0);%00
Это был «контрольный выстрел». Тем не менее такой конструкцией удалось вытащить имя одного из «хозяев» денег. А так же наугад подобрал несколько названий колонок.
Так как хоть какой-то вывод на экран значений из БД у нас есть, изменил запрос, чтобы избавится от
sleep().
?id=1’ %26%26 if((ascii(substring((select @@version),1,1))>96),1,0);%00
Тут на экране получаем «500000», если выражение в
if верно и «You hacker», если нет.
В общем на этом этапе, кроме имен в колонке “name”, я больше не понял как и что вытаскивать. Здесь на ход решения повлиял комментарий тов. Explorer-а о том, что я пошел самым нерациональным путем. С одной стороны я обрадовался, что данный метод все-таки может увенчаться успехом, но с другой обидно, что за столько времени так и не удалось напасть на правильный след.
На следующий день выдалась пара свободных минут, и я попробовал пару идей из браузера телефона. Там было жутко неудобно редактировать длинные запросы, поэтому я решил заодно поискать тот самый «рациональный» путь. Для этого вернулся к исходному простому запросу, который не работал.
К тому моменту я уже понял, что когда мы видим «
Hacker detected», то это значит, что наш запрос — неправильный с точки зрения синтаксиса или логики. Но еще и отфильтровываются некоторые символы/строки. В результате, даже если мы составим правильный/рабочий запрос, то если будут вырезаны некоторые символы, то либо синтаксис либо логика запроса будет нарушена и в итоге запрос будет «сломан» и мы получим алерт.
Итак я ввел исходный
?id=1%27;%00
Здесь никак не хотели работать ни «union select» ни «group by». Но по вышеуказанным причинам я был уверен, что фильтруются строки. И тут наконец-то пришла спасительная мысль, что все дело в символе пробела. Проверив, оказалось, что так и есть:
?id=1%27group/**/by/**/1;%00
Запрос прекрасно работал и показал мне количество столбцов. Все эти несколько дней я не замечал такой простой вещи и из-за этого получал странные результаты, которые в свою очередь толкали меня к неверным выводам.
Далее сразу же последовало
?id=1%27union/**/select/**/1,2;%00
...на что алерта не последовало, что говорило о синтаксической правильности запроса, но результата я на экране не увидел. Здесь как раз и сыграла свою роль моя неуместная уверенность в том, что я уже перечитал и перегуглил все, что можно на эту тему. И если задача и решается дальше, то каким-то экзотическим методом, которого я еще не нашел. Зато теперь можно было продолжать мой «нерациональный» путь, что я и сделал, так как хотел решить таск как можно скорее.
?id=1%27%20%26%26%20if((ascii(substring((select/**/table_name/**/from/**/info%2brmation_schema.tables/**/where/**/table_schema/**/like/**/database()/**/limit/**/0,1),1,1))>96),1,0);%00
Учитывая, что строка «or» и символ «=» фильтруются, применил техники обхода. Запрос сработал. Я так обрадовался, что яростно стал подбирать всю необходимую информацию и в итоге нашел ключ. Но на это потребовалось время. Благо база была всего из двух таблиц и нужная таблица лежала именно в этой базе.
Когда узнал про routed sql, осознал до конца свою главную ошибку. Этот метод русским по белому был подробно описан в методичках WAPT, но увы, мой неметодичный подход к решению наказал меня.
С другой стороны, если метод «timebased» вообще не работал и я бы не тратил на него столько времени, думаю, рано или поздно я бы догадался про routed.
Еще осталось пара непонятных моментов, но в целом таск очень понравился. Действительно, если делать все по уму и самое главное постепенно, то таск вполне логично решается и довольно быстро. Но уверен, что это всегда так кажется после любой решенной задачи из любой области.
Explorer, большое спасибо за задачу и конкурсную мотивацию!
-------------------------------------
Послесловие:
Очень неожиданно и прямо эпично получилось с участниками:
sinner67 - инструктор курса WAPT от Codeby
Bidjo111 - ученик из TOP-а курса WAPT
Ну и создатель таска оттуда же )
Скрин с курса WAPT:
Так что наглядно видно, что курс от Codeby даёт реальные результаты. К слову говоря, после того как Bidjo111 прислал мне secret_key, я ему дал подсказку routed sql и предложил перерешать. Менее чем за пол-часа он уже прислал мне payload на 100% повторяющий оригинальную задумку!!! Меня это здорово порадовало. Мой большой респект, человек умеет думать, учитесь )
Подробное прохождение таска выложу на днях. Сайт ещё работает, поэтому любые желающие могут ещё потренироваться в решении задачи.
Ещё раз всем огромное спасибо, до встречи!