- Dreamhack: simple_sqli_chatgpt2024년 10월 01일 19시 55분 51초에 업로드 된 글입니다.작성자: sonootri
1. 문제 설명
#!/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), userlevel integer);') db.execute(f'insert into users(userid, userpassword, userlevel) values ("guest", "guest", 0), ("admin", "{binascii.hexlify(os.urandom(16)).decode("utf8")}", 0);') 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: userlevel = request.form.get('userlevel') res = query_db(f"select * from users where userlevel='{userlevel}'") if res: userid = res[0] userlevel = res[2] print(userid, userlevel) if userid == 'admin' and userlevel == 0: 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. 문제 풀이
DATABASE = "database.db" if os.path.exists(DATABASE) == False: db = sqlite3.connect(DATABASE) db.execute('create table users(userid char(100), userpassword char(100), userlevel integer);') db.execute(f'insert into users(userid, userpassword, userlevel) values ("guest", "guest", 0), ("admin", "{binascii.hexlify(os.urandom(16)).decode("utf8")}", 0);') 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
userid, userpassword, userlevel: guest-guest-0, admin-랜덤값-0으로 되어있다.
@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: userlevel = request.form.get('userlevel') res = query_db(f"select * from users where userlevel='{userlevel}'") if res: userid = res[0] userlevel = res[2] print(userid, userlevel) if userid == 'admin' and userlevel == 0: 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>'
-> userlevel = request.form.get('userlevel'): 사용자가 입력한 userlevel 데이터를 가져온다.
-> res = query_db(f"select * from users where userlevel='{userlevel}'"): query_db 함수는 DB에 쿼리를 실행하는 함수이며, 가져온 userlevel을 바탕으로 쿼리문을 실행한다.
-> res는 DB 쿼리 결과를 나타낸다.
-> query_db는 리스트나 튜플 형태로 결과를 반환한다. 아까 userid, userpassword, userlevel 였으니 if문이 저렇게 쓰여지는거다.
-> 사용자로부터 입력받은 userlevel을 직접 SQL 쿼리문에 삽입하기 때문에, SQL Injection 공격이 진행될 수 있다.
userid == admin 그리고 userlevel == 0이어야 플래그가 반환된다. 쿼리문에 따라 우리가 0을 입력하면 guest와 admin 둘 다 조회될거다. 이후 조건문에 의해 admin이 아니게 되는것이다.
select * from users where userlevel='{userlevel}'
//이후 조건 if res: userid = res[0] userlevel = res[2] print(userid, userlevel) if userid == 'admin' and userlevel == 0: 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>'
3. 취약점
<시도했지만 실패한 것들>
1) 0'or'1 -> 1이 문자열로 해석되기 때문에 논리적 참이 아님. 생각을 잘 못했다.
2) 0'or'1'='1 -> 참을 만들어, DB의 모든 데이터를 반환하는 것을 생각했음. 하지만 실패
3) 0'or userid='admin -> 이것 또한 실패였음. 왜지
<성공한 것들>
1) 0' AND userid='admin -> where절 뒤에 AND를 사용해 조건을 더 붙이려고 했음
2) 0'and userid='admin -> or 조건일때는 안 됬는데 이거는 된다.....?
3) 0' union select * from users where userid='admin -> sql에서 사용되는 union을 사용해 쿼리문 확장
'Dreamhack > 워게임' 카테고리의 다른 글
webhacking.kr: old-50 (1) 2024.10.01 webhacking.kr: old-27 (0) 2024.10.01 Lord of Injection: germiln (0) 2024.10.01 Web Hacking_command-injection-1🚩 (3) 2024.09.28 Web Hacking_simple_spqi🚩 (0) 2024.09.27 다음글이 없습니다.이전글이 없습니다.댓글