[Dreamhack] simple_sqli
문제 정보
로그인 서비스입니다.
SQL INJECTION 취약점을 통해 플래그를 획득하세요. 플래그는 flag.txt, FLAG 변수에 있습니다.
문제페이지이다. 문제 정보처럼 로그인 서비스만 구축되어 있다.
#!/usr/bin/python3
from flask import Flask, request, render_template, g
import sqlite3
import os
import binascii
app = Flask(__name__)
app.secret_key = os.urandom(32)
try:
FLAG = open('./flag.txt', 'r').read()
except:
FLAG = '[**FLAG**]'
DATABASE = "database.db"
if os.path.exists(DATABASE) == False:
db = sqlite3.connect(DATABASE)
db.execute('create table users(userid char(100), userpassword char(100));')
db.execute(f'insert into users(userid, userpassword) values ("guest", "guest"), ("admin", "{binascii.hexlify(os.urandom(16)).decode("utf8")}");')
db.commit()
db.close()
def get_db():
db = getattr(g, '_database', None)
if db is None:
db = g._database = sqlite3.connect(DATABASE)
db.row_factory = sqlite3.Row
return db
def query_db(query, one=True):
cur = get_db().execute(query)
rv = cur.fetchall()
cur.close()
return (rv[0] if rv else None) if one else rv
@app.teardown_appcontext
def close_connection(exception):
db = getattr(g, '_database', None)
if db is not None:
db.close()
@app.route('/')
def index():
return render_template('index.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
else:
userid = request.form.get('userid')
userpassword = request.form.get('userpassword')
res = query_db(f'select * from users where userid="{userid}" and userpassword="{userpassword}"')
if res:
userid = res[0]
if userid == 'admin':
return f'hello {userid} flag is {FLAG}'
return f'<script>alert("hello {userid}");history.go(-1);</script>'
return '<script>alert("wrong");history.go(-1);</script>'
app.run(host='0.0.0.0', port=8000)
위는 문제 코드 전문이다.
코드에서 자세히 볼 정보는 총 2개이다.
1. userid, userpassword컬럼에 각각 guest,guest인 계정 하나, userid는 admin인 계정은 password를 모른다.
2. Flag는 userid가 admin일 때 출력되다. userid는 로그인페이지에서 아이디로 입력하면 userid 변수로 들어가고 이게 쿼리문으로 들어간다.
admin 계정의 비밀번호를 모르므로 1번 정보를 이용해 공개되어있는 guest계정으로 로그인 해준다.
alert 창이 뜨고 확인을 누르면 이전 로그인페이지로 돌아가는 것을 알 수 있다.
이번엔 2번 정보를 이용해서 로그인을 해보도록 하겠다. 로그인에 사용되는 쿼리문은 아래와 같다.
query_db(f' select * from users where userid="{userid}" and userpassword="{userpassword}" ')
내가 아는 정보를 파란색, 내가 모르는 정보를 빨간색으로 칠하였다. userid가 userid가 admin이고 해당 쿼리문이 참이면 flag를 얻을 수 있따. 그러니 내가 아는 정보에서 쿼리문을 끝낼 수 있도록 입력해준다.
userid 값으로 admin"--를 입력하면 된다.
userid="까지 이미 코드에 포함되어 있으므로 userid 변수에는 내가 입력하려는 admin을 입력하고 " 큰 따옴표를 닫아준 뒤 코드 뒤에 이어지는 " and userpassword~~~ 부분을 주석처리 해주기 위해 --을 붙여주는 것이다.
userpassword가 들어가는 쿼리문 부분은 주석처리 해주었으므로 비밀번호는 아무값이나 친다.
위 같이 플래그를 얻을 수 있었다.
db query문 기본 문법을 배울 수 있는 문제였다.