Challenges: https://github.com/DuongHaoNika/CTF/tree/main/securinets
Puzzle
Đầu tiên, truy cập chức năng login
Đây là code xử lý đăng ký tài khoản tại file auth.py
Nhận thấy khi đăng ký tài khoản, mặc định người dùng được chỉ định role user –> Ta có thể chỉnh sửa request gửi lên để nhận role editor (Không thể sửa role = 0 lên admin vì bị chặn).
Sử dụng Burp Suite để intercept request, đây là request gốc khi đăng ký tài khoản mới
Sau đó thêm role với giá trị 1
Đọc code trong file routes.py thấy có file database
Đây là nội dung file database, bao gồm các thông tin như uuid, username, password, role,…
Chú ý thông tin của admin
Tiếp tục đọc code trong routes.py phát hiện 1 API cho phép lấy thông tin người dùng qua uuid, chức năng này chỉ cho phép admin hoặc editor dùng
Vậy là đã có uuid, kết hợp API trên thì có được thông tin của admin. Nhưng không, đúng như tên file old.db. Khi dùng uuid admin trong old.db -> Lỗi: {"error":"User not found"}
Bây giờ tìm uuid của admin theo cách khác.
Web này có chức năng up bài báo cùng collab, ta thử chức năng này, ở đây cho collab với tài khoản khác của mình.
Sau đó qua tài khoản này kiểm tra, vào Collaborations và Accept
Như vậy là đã collab thành công rồi
Thử bấm vào để đọc xem, nhận thấy response chứa hẳn uuid của người đăng và người collab cùng
Vậy là xong cách lấy uuid của người khác, nhưng làm thế nào để người này accept collab với mình?
Mò lại Proxy thì thấy request sau khi người dùng accept collab
Đây là code xử lý
=> Chỉ cần có request uuid, ta có thể accept được mọi collab mặc dù người collab không hề bấm Accept.
Như vậy flow để leo lên admin là collab với admin, sau đó accept request collab để lấy uuid của admin, cuối cùng thì sử dụng API với uuid là lấy được thông tin của admin.
Bây giờ thực hiện collab với admin
Sau đó vào tab Collaborations, mở Burp lấy request uuid, copy lấy uuid này
Sau đó thay uuid này vào request accept collab và gửi là được
Collab thành công với admin
Lấy uuid của admin
Gọi API lấy thông tin của admin qua uuid, lấy được username, password,…
Đăng nhập vào tài khoản admin, admin có thể truy cập vào /data/
Sau khi truy cập, tải được file secrets.zip
Để mở file zip này thì cần mật khẩu, khả năng flag nằm trong đây. Mình đã thử chạy wordlist nhưng không chưa mở được. Ở /data còn có cả dbconnect.exe, khả năng là file thực thi để kết nối với database. Mở Kali và grep xem có password lưu trong dbconnect.exe không (Dùng IDA cũng được) -> Tìm thấy password
Đây cũng là password mở file zip luôn, lấy được flag
Flag: Securinets{777_P13c3_1T_Up_T0G3Th3R}
S3cret5
Đầu tiên đăng ký 1 tài khoản rồi đăng nhập. Bài này có chức năng report URL (/routes/report.js)
Ta chỉ được phép report các URL bắt đầu với http://localhost:3000
Con bot này đăng nhập tài khoản admin rồi truy cập vào URL do người dùng cung cấp.
Để ý thì thấy có chức năng addAdmin (userController.js) và chỉ admin mới thực hiện được
Nội dung của đề như sau:
1 | My friend built a “secure” secret vault where anyone can register, log in, and save private secrets. He swears it’s fully secure: owner-only access, CSRF protection, logs. Prove him wrong. |
Nên khả năng cần khai thác lỗi CSRF. Mà web này có cơ chế bảo vệ CSRF, làm sao để bypass được?
/views/profile.ejs
Khi truy cập vào profile, script trên được chạy để ghi log. Mà profileIds là 1 mảng chứa các id, profileId là phần tử cuối của mảng. Sau đó fetch /log/+profileId kèm với CSRF token và userId của profile này. Có thể thấy profileId không hề được validate và cộng chuỗi luôn -> Path Traversal. Ta sẽ report URL là http://localhost:3000/user/profile?id=<userId>&id=../admin/addAdmin với userId là id người dùng của bạn, /log/+../admin/addUser -> /admin/addUser và body có userId: "<%= user.id %>" chính là id của profile (của bạn) và _csrf của admin được đính kèm luôn, như vậy có thể nâng cấp tài khoản của bạn lên admin.
Ở đây, userId của mình là 2
Khi đó URL để report là
1 | http://localhost:3000/user/profile?id=2&id=../admin/addAdmin |
Lên được admin
Admin có chức năng tìm kiếm các messages của toàn bộ người dùng
Flow tìm kiếm
1 | -> controllers/adminController.showMsgs |
Thấy clause là điều kiện WHERE và được nối vào câu SQL, sau đó đưa vào query -> SQL Injection.
filterHelper.js
Cho filterBy là type"='general'+and+((SELECT+SUBSTRING(flag,1,1)+FROM+flags)='S')+and+msgs."msg để tìm flag.