### Horse Source ![image](https://hackmd.io/_uploads/Skg3ZAtAlx.png) Truy cập trang web ![image](https://hackmd.io/_uploads/SJfabAKCgx.png) Kiểm tra mã nguồn ta tìm được flag ![image](https://hackmd.io/_uploads/SkGAWCFAxl.png) ### None Shall Pass ![image](https://hackmd.io/_uploads/SJ0SppFCxe.png) ![image](https://hackmd.io/_uploads/HJM20TK0ex.png) Đăng ký đăng nhập vào trang web , trang web có chức năng thêm sản phẩm vào giỏ hàng ,thanh toán . Số tiền hiện tại trong tài khoản là 10$ ![image](https://hackmd.io/_uploads/SkYuaaFAxe.png) Ta phát hiện có sản phẩm tên FLAG có giá trị 1337$ . Ta đoán rằng cần phải mua thành công được sản phẩm này để lấy flag ![image](https://hackmd.io/_uploads/SyCKaptReg.png) Theo đề bài ta thấy bài này liên quan đến json web token ![image](https://hackmd.io/_uploads/SJfnTaYClg.png) Nhìn vào jwt , ta thấy tham số `balance` đang thể hiện số tiền hiện tại của người dùng ![image](https://hackmd.io/_uploads/Bysp6pYReg.png) Nếu ta thay đổi giá trị `balance` và đảm bảo giá trị jwt vẫn hoạt động bình thường phục vụ cho cookie phiên thì ta hoàn toàn có thể mua được sản phẩm `FLAG` Ta thay đổi tham số thuật toán `alg` từ HS256 sang `None` khi này ta k cần ký lại jwt và đảm bảo tham số balance > 1337 -> `Jwt vẫn hoạt động bình thường k bị out khỏi phiên` ![image](https://hackmd.io/_uploads/r1FkJoyJWl.png) ![image](https://hackmd.io/_uploads/Hy24kjk1Wl.png) ![image](https://hackmd.io/_uploads/HkMaksJ1Wg.png) Ta mua sản phẩm thành công và thu được flag ![image](https://hackmd.io/_uploads/SkTvJjkJWx.png) `MetaCTF{JWT_N0n3_4lg_3xpl01t}` ### Mega Lens Pro Chức năng trang web là tải file lên và xem metadata của file . ![image](https://hackmd.io/_uploads/H1eHMCYAle.png) ![image](https://hackmd.io/_uploads/BkIIzCKRll.png) Nhìn kỹ ta thấy có thông tin về ứng dụng ExifTool với phiên bản 12.23 ![image](https://hackmd.io/_uploads/SJiU6qJJWg.png) CVE-2021-22204 Bài phân tích lỗ hổng `https://ine.com/blog/exiftool-command-injection-cve-2021-22204-exploitation-and-prevention-strategies` ![image](https://hackmd.io/_uploads/B1Q6Z5ykZe.png) Sử dụng Poc tạo ra file ảnh có payload để đọc file /etc/passwd (dể kiểm tra xem Poc có hoạt động không) ![image](https://hackmd.io/_uploads/H12eKcykWg.png) Thành công đọc được file /etc/passwd ![image](https://hackmd.io/_uploads/HkGJY5kJZe.png) Sử dụng POC để khởi tạo 1 ảnh nhằm tạo 1 reverse shell ![image](https://hackmd.io/_uploads/H1c459yybl.png) ![image](https://hackmd.io/_uploads/SyAucq1ybl.png) Thành công thu được reverse shell ![image](https://hackmd.io/_uploads/SkF855kkbg.png) Thành công đọc được file flag.txt ![image](https://hackmd.io/_uploads/HJ1oc9JkWx.png) `MetaCTF{exif_to0l_versi0n_c4n_kill_you}` ### MonsterMon Trang chủ ![image](https://hackmd.io/_uploads/HJpmbo1yWe.png) #### Phân tích luồng Đọc source code trong file ta thấy flag.txt sẽ nằm trong thư mục / ![image](https://hackmd.io/_uploads/Bkp1Gi1JWg.png) Trong file monstermon.go ta thấy hàm loadData() sẽ lưu giá trị trong file flag vào trường `Description` của người dùng `FuzzyFlash23` Và hàm loadData() sẽ được gọi mỗi khi app chạy ![image](https://hackmd.io/_uploads/rJdtNoJkZl.png) ![image](https://hackmd.io/_uploads/BkxJhnyJbe.png) Ta có đối tượng `user` và mỗi `user` có 1 đối tượng `card` Đối tượng user lưu trong biến ctf_user chính là bản thân hiện tại có giá value `33` Hàm `inspect` trả về dữ liệu thẻ của người dùng ctf_user ![image](https://hackmd.io/_uploads/SJbjMh11-e.png) ![image](https://hackmd.io/_uploads/HJmSCjJyWl.png) ![image](https://hackmd.io/_uploads/HJ_gh3kk-l.png) ![image](https://hackmd.io/_uploads/r1pA2o1yZe.png) Ta có hàm tradeCards() truyền vào tham số `user` ![image](https://hackmd.io/_uploads/ByCty3JJZl.png) - Sau đó sẽ gọi hàm findUserByName(username) để tìm đối tượng user dựa theo tham số giá trị tham số `user` rồi lưu kết quả vào biến `u` - Nếu biến u = null thì trả về không tìm thấy người dùng. - Nếu khác null tiếp tục so sánh giá trị thẻ nếu hiệu giá trị thẻ của người dùng khác so với người ctf_user < 25 thì server chạy goroutine thinkAboutTrade(u) . - Trong hàm thinkAboutTrade(u) thì sẽ -- Hoán đổi card giữa ctf_user và u -- Chờ 10 giây. -- Đổi lại như cũ #### Khai thác Ta thấy khi chạy hàm thinkAboutTrade(u) sử dụng go . Đây chạy `goroutine` chia sẻ cùng bộ nhớ với thread chính nhưng không có mutex hoặc sync lock. Goroutine này chạy song song, không khóa dữ liệu → chính là điểm yếu. Ý tưởng khai thác : * Khi gọi hàm thinkAboutTrade(u) có đoạn tráo đổi thẻ giữa hai người dùng `ctf_user.Card bị đổi tạm thời thành card của user kia` sau đó ngủ 10s . * Trong khoảng thời gian 10s ta có thể vô xem dược thông tin của thẻ người kia . Nếu ta áp dụng hàm thinkAboutTrade với u `FuzzyFlash23` thì ta dễ dàng xem được dữ liệu của người dùng `FuzzyFlash23` trong quá trình ngủ 10s thông qua hàm `inspect` GIẢI THÍCH TẠI SAO `semaphore >0` không hoạt động Tại sao semaphore hiện tại không an toàn 1. Không atomic / không protected semaphore là một int toàn cục. Các thao tác semaphore++ và semaphore-- không atomic — nếu nhiều goroutine đọc/ghi cùng lúc thì có data race. Go race detector (go run -race) sẽ báo lỗi. 2. Không có ràng buộc bộ nhớ (memory ordering) Trong Go, để đảm bảo thứ tự nhìn thấy các thay đổi giữa goroutine, bạn phải dùng cơ chế đồng bộ (mutex, channel, hoặc atomic ops). Không có đồng bộ, một goroutine khác có thể thấy ctf_user.Card được đổi mà không thấy semaphore đã được tăng (do reordering/memory visibility). Điều này cho phép kịch bản: inspect đọc ctf_user.Card với Description là flag trước khi thấy semaphore > 0. 3. Goroutine scheduling window tradeCards khởi tạo goroutine go thinkAboutTrade(u) và trả về tức thì. Có nhiều thứ bất định về lúc goroutine bắt đầu chạy; điều này tạo ra nhiều "timing windows" phức tạp — kết hợp với không có atomic / mutex có thể dẫn tới hành vi không mong muốn. 4. Kiểm tra semaphore trong inspect không đủ inspect kiểm tra if semaphore > 0 { ... } nhưng vì thiếu đồng bộ, giá trị semaphore có thể không phản ánh đúng trạng thái hiện tại của ctf_user.Card. Kết luận: semaphore hiện tại là một biến giả semaphore — ý định có, nhưng triển khai không an toàn. Dẫn tới data race và khả năng lộ flag. Trong bài web thì FuzzyFlash23 có thẻ giá trị 80 và ctf_user là có giá trị 35 . Hiệu của 2 thẻ > 25 không < 25 :) nên ban đầu click `Trade` bị `auto rejected` ![image](https://hackmd.io/_uploads/B1vo93ky-e.png) ### Super Quick Logic Invitational ![image](https://hackmd.io/_uploads/B1QwUCYCel.png) Truy cập trang web Thử ký tự đặc biệt và từ phản hồi trả về ta phát hiện được lỗ hổng SQL Injection ![image](https://hackmd.io/_uploads/HJmhIRKRgg.png) ![image](https://hackmd.io/_uploads/Sy4R5H9Rle.png) Thử kết hợp với điều kiện `'1'='1'` thì phản hồi sẽ trả về `"correct":true` ![image](https://hackmd.io/_uploads/BkhBGfcAge.png) Thử kết hợp với điều kiện `'1'='0'` thì phản hồi sẽ trả về `"correct":false` ![image](https://hackmd.io/_uploads/S1APzzcRxx.png) -> Đây là lỗ hổng SQL Injection Blind Boolean :) #### Ta trích xuất các bảng dữ liệu Cho `= x` x chạy từ 1 đến 100 ``` ' OR (length((select name from sqlite_master where type='table' limit 0,1))) = 1 -- ``` ![image](https://hackmd.io/_uploads/r19-pS5Cxl.png) Độ dài bảng đầu tiên là 8 Tiếp tục tìm kiếm tên bảng đầu tiên Cho `0,1),x,1))` x chạy từ 0 đến 8 và `== 'y'` y chạy từ a-zA-Z0-9 và ký tự đặc biệt ``` ' OR (substring((select name from sqlite_master where type='table' limit 0,1),0,1)) == 's' -- ``` ![image](https://hackmd.io/_uploads/B1Oa0HcRle.png) Ta tìm được bảng là `problems` Tiếp tục tìm kiếm bảng thứ 2 ``` ' OR (substring((select name from sqlite_master where type='table' limit 1,1),0,1)) == 's' -- ``` ![image](https://hackmd.io/_uploads/ry2zM85Ael.png) Ta không tìm thấy tên bảng -> Không có bảng thứ 2 #### Ta trích xuất các trường dữ liệu của bảng problems Trong đoạn `,x,1` cho x chạy từ 0 đến 30 . ``` ' OR (substr((SELECT GROUP_CONCAT(name) AS column_names FROM pragma_table_info('problems')),1,1)) == "i"-- ``` ![image](https://hackmd.io/_uploads/Hk1-BI9Cxx.png) Ta thu được gồm các trường id , question , answer,difficulty Dựa vào gợi ý ban đầu của đề bài ta đoán rằng giá trị flag sẽ nằm trong trường `answer` của câu hỏi `What is the flag for this CTF challenge?` Xác định độ dài giá trị trường `answer` với question `What is the flag for this CTF challenge?` Cho `= x` chạy từ 0 đến 100 ``` ' OR length((SELECT GROUP_CONCAT(answer) FROM problems WHERE question = 'What is the flag for this CTF challenge?')) = 44 -- ``` Ta tìm được độ dài giá trị trường `answer` =44 ![image](https://hackmd.io/_uploads/SkG_NwcAgg.png) Ta tiếp tục trích xuất các ký tự trong trường `answer` Cho `,x,1))` với x chạy từ 0 đến 44 . Và `== "y"` với y chạy trong khoảng a-zA-Z0-9 các ký tự đặc biệt ``` ' OR (substr((SELECT GROUP_CONCAT(answer) from problems where question = 'What is the flag for this CTF challenge?'),0,1)) == "a" -- ``` ![image](https://hackmd.io/_uploads/rJgMIPcRlg.png) ![image](https://hackmd.io/_uploads/ryRdrvcAxe.png) ![image](https://hackmd.io/_uploads/SJJhHv90ge.png) Ta trích xuất thành công thu được flag `MetaCTF{wh4t1s7h3fl4gf0r7hi5ch5l1eng3}`