CTF용 간단한 SQLI 문제 제작기

sani·2023년 2월 1일

이번에 동아리에서 준회원 CTF를 위한 문제를 제작하는 기회가 생겨서
간단한 SQLI 문제를 만들어 보기로 결정했다.

문제 컨셉은 Blind SQLI를 통한 관리자 로그인으로 결정했다.

또한 dreamhack이나 다른 CTF web문제를 보게 되면 대부분 js, flask를 이용한 문제가 많아, 이번에는 flask를 이용하여서 문제를 제작하게 되었다.

Flask를 이용해 코드를 짜는것이 처음이라서 낯설었지만, dreamhack 문제 코드나 다른 flask 코드들을 참고하여서 다행히 완성할 수 있었다.

app.py

import os, random, base64
from flask import Flask, request, render_template
from flask_mysqldb import MySQL


app = Flask(__name__)
app.config['MYSQL_HOST'] = "db"
app.config['MYSQL_USER'] = "root"
app.config['MYSQL_PASSWORD'] = "root"
app.config['MYSQL_DB'] = os.environ.get('MYSQL_DB', 'users')
mysql = MySQL(app)

app.secret_key = os.urandom(32)
@app.route("/", methods = ["GET","POST"])

def index():
    if request.method == 'GET':
        result = request.args.get('test')
        return render_template('index.html')
    if request.method == 'POST':
            uid = request.form['email']
            passwd = request.form['password']
            if uid and passwd:
                cur = mysql.connection.cursor()
                cur.execute(f"SELECT * FROM user WHERE uid='{uid}' and upw='{passwd}';")
                result = cur.fetchone()
                if not result:
                    return render_template('fail.html')
                else:
                    if request.form['email'] == "admin" and request.form['password'] == "Where_is_my_flag?":
                        return render_template('flag.html')
                    else:
                        return render_template('guest.html')
            else:
                return render_template('index.html')

if __name__ == '__main__':
    app.run(host = '0.0.0.0', port=5001)

SQLI를 이용한 문제이기 때문에, 당연히 SQL DB를 활용하게 해야했고, Blind SQLI 이므로 정확한 id / passwd를 입력해야 로그인이 가능하도록 만들었다.

init.sql

CREATE DATABASE IF NOT EXISTS `users`;

USE `users`;
CREATE TABLE user(
  idx int auto_increment primary key,
  uid varchar(128) not null,
  upw varchar(128) not null
);

INSERT INTO user(uid, upw) values('guest', 'guest');
INSERT INTO user(uid, upw) values('admin', 'Where_is_my_flag?');
FLUSH PRIVILEGES;

풀이

문제 코드에서 정확한 id / passwd 를 요구하므로 sqli를 통한 관리자 계정 로그인은 불가능하다.
대신 guest으로 로그인하거나, 로그인을 실패하게 되면 화면이 달라지므로, 그것을 통하여 참 / 거짓을 알아 낼 수 있다.
이를 이용하여서 id / passwd를 알아내 로그인 할 수 있다.

배운점

문제를 제작하면서 flask자체는 별로 어렵지 않았지만,
이후 서버에 업로드하기 위한 docker-compose 파일 설정이 제일 힘들었다.

Flask와 mysqlDB 서로 연동시켜야 했는데, docker를 통하여 서로 연동시키는 법을 배운적이 없어 인터넷 여러곳에서 자료를 수집해 flask-mysqlDB를 연동 시켰다.

docker-compose.yml

version: "3"
services:
  db:
      image: mysql:5.7
      ports:
        - "3306:3306"
      environment:
        MYSQL_ROOT_PASSWORD: "root"
        MYSQL_TCP_PORT: "3306" 
      volumes:
        - ./db:/docker-entrypoint-initdb.d/:ro
  app:
    build: ./app
    links:
      - db
    ports:
      - "5001:5001"

평소 도커 설정을 보기만 했지 직접 구성한 적은 없었는데, 이번기회에
도커에 대해 더 많이 알게 되었다.

문제는 푸는것보다 만드는게 더 어려운것 같다...............

profile
창원대학교 보안동아리 CASPER

0개의 댓글