Phần giới thiệu
CSAW CTF 2024 diễn ra từ ngày 06/8/2024 đến 07/8/2024. Có 04 challenge về pwn với mức độ tương đối cơ bản, team chúng tôi đã vượt qua được 04/04 challenge lần này.
1. Diving Into Null
Như giới thiệu của tác giả: Oops, I rm -rf 'ed my binaries. Tất cả các lệnh binary commands (hoặc executable commands) đều bị xóa đi. Thử thách này đơn giản là yêu cầu tìm và mở được tệp flag mà không sử dụng các lệnh thường dùng là ls, cat, less,... Liên quan Escaping from Jails hơn là Pwn.
Như giới thiệu của tác giả: Oops, I rm -rf 'ed my binaries. Tất cả các lệnh binary commands (hoặc executable commands) đều bị xóa đi. Thử thách này đơn giản là yêu cầu tìm và mở được tệp flag mà không sử dụng các lệnh thường dùng là ls, cat, less,... Liên quan Escaping from Jails hơn là Pwn.
Để vượt qua thử thách, có thể sử dụng lệnh "echo /path/to/files/*"; "echo /path/to/files/.*" để thay thế cho lệnh "ls". Sử dụng lệnh shell "while read line; do echo "$line"; done < /path/to/file/.*" để đọc từng dòng trong file đó.
2. Mini Golfing
Thử thách cung cấp tệp nhị phân golf.
Phân tích tĩnh tệp nhị phân:
- Tại function main(), chương trình nhận đầu vào từ người dùng (tối đa 0x400 ký tự) lưu vào trong biến local_518, tiếp theo ta thấy lỗ hổng format string tại printf((char *)&local_518) do chương trình sử dụng printf mà không dùng tham số định dạng. Sau đó, chương trình nhận tiếp một chuỗi đầu vào local_18 với định dạng scanf là %lx. Sau đó thực hiện địa chỉ local_18.
- Chương trinh có cung cấp hàm win để mở flag:
- Khi phân tích tĩnh bằng gdb địa chỉ hàm win và main lần lượt tại 0x1209 và 0x1223:
Khai thác: Sử dụng lỗ hổng format string để rò rỉ địa chỉ hàm main. Sau đó suy ra địa chỉ hàm win để nhập flag. Ví dụ:
Địa chỉ hàm main trong hình là 0x560f33a43223 suy ra địa chỉ hàm win là 0x560f33a43209. Nhập đầu vào với địa chỉ win để nhận flag.
3. Nix Philosophies
Tệp nhị phân của thử thách: chal.
Phân tích:
- Sau nhiều lần phân tích hàm main, tôi đã hiểu được rằng sau khi chương trình nhận một chuỗi đầu vào, vòng lặp while sẽ tính tổng các ascci giá trị thập phân của các ký tự từ vị trí thứ 1 đến hết chuỗi (lưu ý vị chuỗi bắt đầu bằng vị trí 0). Tổng này sẽ lưu vào biến local_294.
- Kế tiếp chương trình sẽ read(local_294 - 0x643, buf, 0x20). Sau đó kiểm tra nếu buf là chuỗi "make every program a filter\n" thì in flag.
Khai thác: Cần nhập một chuỗi đầu vào sao cho tổng giá trị ascci thập phân của các ký tự bằng 0x643 để tham số thứ nhất của hàm read là 0 tức là đọc từ đầu vào stdin chuẩn. Sau đó nhập chuỗi "make every program a filter" để nhận flag.
4. VIP Blacklist
Tệp nhị phân của thử thách: vip_blacklist
Luồng thực thi:
- Sau khi khởi tạo, hàm main() gọi hàm handle_client()
- Hàm handle_client() ban đầu gọi hàm randGen() với tham số đầu vào là biến local_a0.
- Hàm randGen() thực hiện lấy giá trị thời gian hiện tại làm tham số cho hàm srand(), sinh ra 10 giá trị ngẫu nhiên bằng hàm rand() với mỗi giá trị chuyển về định dạng ký tự và lưu lần lượt 10 ký tự đã sinh vào param_1 tức là biến local_a0. Tại đây xuất hiện điểm yếu đầu tiên của chương trình: Người dùng khi thực thi chương tình hoàn toàn có thể biết được giá trị thời gian sinh ra từ hàm time(), do đó có thể mô phỏng lại tương tự để xác định 10 giá trị ngẫu nhiên sinh ra từ hàm rand().
- Hàm handle_client() gọi tiếp hàm displayCommands(). Hàm này lần lượt in ra 04 chuỗi giãn cách nhau 06 byte chứa trong biến whitelist. Ban đầu whitelist là chuỗi byte "clear\x00exit\x00ls\x00".
- Chương trình đi tiếp vào vòng lặp do while, rồi nhận đầu vào từ bộ nhập chuẩn 32 byte ký tự lưu vào biến local_78. Sau đó so sánh biến local_78 này với chuỗi random đang được lưu tại biến local_a0 và các chuỗi trong whitelist. Nếu khớp với chuỗi trong local_a0 thì được đi đến hàm allowCopy(), nếu khớp với bất kỳ chuỗi nào trong whitelist thì gọi lệnh thực thi câu lệnh tương ứng (exit - thoát chương trình, ls - liệt kê các tệp và tập tin ngang cấp, clear - xóa màn hình).
- Hàm allowCopy() cho phép người dùng nhập đầu vào 32 byte ký tự, lưu vào biến local_48.
- Tiếp hành so khớp 05 ký tự đầu chuỗi với "queue" nếu không khớp chương trình gọi hàm kickOut() để thoát. Ngược lại chương trình sẽ thực hiện copy chuỗi "clear\x00exit\x00ls\x00" tịnh tuyến 06 byte ký tự, để copy chuỗi chứa tại biến local_48 vào phần đầu của whitelist. Tại đây xuất hiện điểm yếu thứ hai, vì chương trình sẽ copy toàn bộ chuỗi local_48, có thể ghi đè cả phần "clear\x00exit\x00ls\x00". Mặc dù, việc này được hàm safety() kiểm tra để phòng tránh, nhưng cách triển khai hàm này chưa hợp lý, người dùng vẫn có thể ghi đè "clear\x00exit\x00ls\x00" bằng "clear\x00exit\x00ls<chuỗi tùy ý>" để thỏa điều kiện trong hàm safety() và chèn vào chuỗi tùy ý. Tôi đã ghi đè thành "clear\x00exit\x00ls;sh\x00", khi đó, quay về handle_client(), chỉ cần nhập đầu vào "ls;sh" thì chương trình sẽ thực thi lệnh ls rồi thực thi lệnh sh (lệnh này cho phép người dùng thực hiện shell.
Hàm safety():
Khai thác:
- Hàm mô phỏng lại hàm randGen() để đoán giá trị random nhận được:
- Mã khai thác: Tôi thực thi chương trình t - đây là chương trình mô phỏng các giá trị hàm randGen() sẽ sinh ra. Sau đó thực hiện chương trình vip_blacklist theo chiến lược đã đề ra.
-- Kết thúc phần writeup --
Các thử thách trong CSAW CTF 2024 khá dễ, như đã giới thiệu "esigned as an entry-level, jeopardy-style CTF, this competition is for students who are trying to break into the field of security, as well as for advanced students and industry professionals who want to practice their skills". Phù hợp với các bạn bắt đầu tìm hiểu hướng đi về bảo mật.