문제 파일 다운 및 문제 화면을 보도록 하자.
#!/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)
문제 소스 코드다.
중요한 것들만 발췌한다면....
uid = request.form.get('uid', '').lower()
upw = request.form.get('upw', '').lower()
level = request.form.get('level', '9').lower()
uid, upw, level는 POST 요청의 파라미터로 전달된 데이터를 받는다.
패킷으로 확인 가능하다.
sqli_filter = ['[', ']', ',', 'admin', 'select', '\'', '"', '\t', '\n', '\r', '\x08', '\x09', '\x00', '\x0b', '\x0d', ' ']
SQL injection에 대한 필터링 각종 문자열들을 막는다.
해당되는 것은
'[',']' : 배열을 나타낼 수 있는 대괄호 기호
', ' : 다중 쿼리에 대한 코마 기호
'admin' : 문자열 admin
'select' : 문자열 select
'\', '\"' : 역슬래시 기호
'\t', '\n', '\r' : 입력칸 조작 기호
'\x08', '\x09', '\x00', '\x0b', '\x0d' : 16진법 ASCII 코드를 이용한 입력칸 조작 기호
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!'
query 부분을 보면 '{uid}' , '{upw}'에서 싱글쿼터를 사용하지만 옆에 level={level}를 보면 싱글 쿼터를 사용하지 않는다.
그렇다면 level 에 파라미터 값 전달을 통해서 해답을 얻을 수 있을 거 같다.
burp suite를 이용해서 문제를 살펴보자.
패킷을 잡아보니 uid, upw 가 나와있고 여기서 level를 같이 엮어 집합 연산자인 UNION을 사용하도록 하자.
필터링을 우회하여 공백을 '/**/'으로 대체하였고 문자열을 더해주는 '||'을 사용했다.
char를 이용 아스키코드에 해당되는 문자로 admin를 만들 수 있다.
'DreamHack' 카테고리의 다른 글
DreamHack - command-injection-1 (0) | 2024.05.31 |
---|---|
DreamHack - simple-ssti (0) | 2024.05.17 |
DreamHack - image-storage (0) | 2024.05.17 |
Dreamhack - Csrf2 (수정) (0) | 2024.04.05 |
Dreamhack - csrf1 (Cross-Site Request Forgery) (수정) (0) | 2024.04.05 |