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;
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')
이 문제는 말 그대로 오류 기반 sql injection 문제다.
들어가기 전에, error based sql injection에 대해 정리하고 들어가도록 하자.
<aside> 💡 데이터베이스 오류 메시지를 활용하여 데이터베이스에 대한 정보를 획득하는 SQL Injection 기법
</aside>
→ 주로 데이터베이스에 대한 정보를 획득하기 위해 사용되는 공격 기법이다. SQL의 잘못된 문법이나 자료형 불일치 등에 의해 데이터베이스가 알려주는 데이터베이스 오류 메시지에 의존하여 수행된다. 따라서 웹 애플리케이션에서 데이터베이스 오류를 표시해주는 경우에 주로 사용할 수 있다. 공격자는 SQL 쿼리의 잘못된 문법을 사용해 고의적으로 오류를 유발시키고, 해당 오류 정보를 바탕으로 데이터베이스명, 테이블, 컬럼 정보 등의 데이터베이스 정보와 구조를 알아내어 개인 정보와 같은 민감한 데이터를 획득할 수 있다.
해당 문제는 mysql 기반으로 작성되었으므로, mysql을 기반으로 공격 기법을 작성하도록 하겠다.
여기서, XPath 방식을 활용해서 문제를 풀어볼 예정이다.
XPath 방법은 extractvalue() 함수를 활용하는 기법으로 MySQL 기준 5.1 이상의 버전에서만 유효하다.