1. Đề bài

Cho web có tên là “emoji voting”

/images/posts/ctf/Cyber-Apocalypse-2021/Cyber-Apocalypse-2021-Web-emoji-voting-writeup/Web-emoji-voting.png

Source code emoji voting

/images/posts/ctf/Cyber-Apocalypse-2021/Cyber-Apocalypse-2021-Web-emoji-voting-writeup/source-code.png

2. Giải quyết

Dạo quanh source code một vòng và tôi phát hiện ra một số thứ như vầy.

Api với endpoint “/api/list” có nhận giá trị “order“ từ body của request (giá trị này người dùng kiểm soát được) và gửi tới function “getEmojis()” để truy vấn database

/images/posts/ctf/Cyber-Apocalypse-2021/Cyber-Apocalypse-2021-Web-emoji-voting-writeup/getEmojis.png

Đi vào function “getEmojis()”, thì thấy câu truy vấn database được nối chuỗi, và không có filters hay encode gì cả.

/images/posts/ctf/Cyber-Apocalypse-2021/Cyber-Apocalypse-2021-Web-emoji-voting-writeup/select-database.png

Xác định ngay và luôn là SQL injection (Thực ra là SQLite injection).

Vấn đề bây giờ là SQL injection với ORDER BY, nghe có vẻ khoai khoai, và tôi chọn câu lệnh để thực thi SQL injection là “CASE…WHEN”. Hiểu nôm na của câu lệnh này là “trong trường hợp như thế nào đó thì trả về cả gì đó”. Ví dụ: Khi bạn đọc bài của tôi, bạn sẽ thu về được kiến thức. => Đại loại thế.

Trước tiên tôi phải thử xem api này đang hoạt động như thế nào, và trả về cái gì đã, nên tôi intercept bằng burpsuite. Giá trị api list trả về.

/images/posts/ctf/Cyber-Apocalypse-2021/Cyber-Apocalypse-2021-Web-emoji-voting-writeup/api-return.png

Vấn của tôi bây giờ là sẽ phải bruteforce flag, mà để bruteforce flag thì phải biết tên bảng chứa flag, vì trong code có một đoạn tạo bảng cho database như vầy.

/images/posts/ctf/Cyber-Apocalypse-2021/Cyber-Apocalypse-2021-Web-emoji-voting-writeup/create-table-flag.png

Vậy là bảng chứa flag sẽ được tạo bằng cách cộng chuỗi “flag_” với một chuỗi random.


Ý tưởng: Tôi có 2 trường hợp để phân biệt câu lệnh đúng và câu lệnh sai.

Khi tôi request với order là “id” thì kết quả trả về emoji có id = 1 sẽ ở vị trí đầu tiên trong json trả về.

/images/posts/ctf/Cyber-Apocalypse-2021/Cyber-Apocalypse-2021-Web-emoji-voting-writeup/true.png

Khi tôi request với order là “count” thì kết quả trả về emoji có id = 3 sẽ ở vị trí đầu tiên trong json trả về.

/images/posts/ctf/Cyber-Apocalypse-2021/Cyber-Apocalypse-2021-Web-emoji-voting-writeup/false.png

Như vậy sẽ thực hiện, khi câu lệnh đúng thì order “id”, khi câu lệnh sai thì order “count”.

Như hình trên, tôi biết chữ cái đầu tiên của bảng chứa flag là “f”, vậy tôi kiểm chứng ý tưởng của tôi xem đúng không nhé.

Thực hiện gửi request với body

{"order":"case when (SELECT substr(tbl_name,1,1) FROM sqlite_master  WHERE type='table' and tbl_name like 'flag_%')='f' then id else count end"}

Là một câu lệnh đúng nên kết quả trả về là

/images/posts/ctf/Cyber-Apocalypse-2021/Cyber-Apocalypse-2021-Web-emoji-voting-writeup/true-with-payload.png

Thực hiện gửi request với body

{"order":"case when (SELECT substr(tbl_name,1,1) FROM sqlite_master  WHERE type='table' and tbl_name like 'flag_%')='l' then id else count end"}

Là một câu lệnh sai nên kết quả trả về là

/images/posts/ctf/Cyber-Apocalypse-2021/Cyber-Apocalypse-2021-Web-emoji-voting-writeup/false-with-payload.png


Vậy tôi viết được poc để bruteforce tên bảng như sau

/images/posts/ctf/Cyber-Apocalypse-2021/Cyber-Apocalypse-2021-Web-emoji-voting-writeup/poc-get-table-flag-name.png

Poc get flag table name

Sau khi có tên bảng là: flag_aade53e551, tôi tiến hành bruteforce flag với POC như sau.

/images/posts/ctf/Cyber-Apocalypse-2021/Cyber-Apocalypse-2021-Web-emoji-voting-writeup/poc-get-flag.png

Chạy và chờ kết quả thôi

/images/posts/ctf/Cyber-Apocalypse-2021/Cyber-Apocalypse-2021-Web-emoji-voting-writeup/flag.png

> Flag là: CHTB{order_me_this_juicy_info}