Tổ chức một kỳ thi Capture The Flag như thế nào?
Trung Nguyen

Giới thiệu
CTF là một môn thể thao trí tuệ của giới hacker. Và đương nhiên, khi tổ chức một cuộc thi như vậy thì ban tổ chức sẽ phải đương đầu với chính những người chơi của mình. Rất nhiều vấn đề phát sinh trong suốt thời gian cuộc thi diễn ra, để giải quyết đòi hỏi cả khả năng kỹ thuật cũng như kinh nghiệm triển khai. Bài viết này dành cho các cá nhân/tổ chức muốn tổ chức một kỳ thi Capture The Flag an toàn và có chất lượng.
Tác giả từng là Tech Lead, phụ trách thiết kế hệ thống và ra đề thi cho WhiteHat Wargame, WhiteHat Contest và WhiteHat Grandprix.
Tài liệu này cũng tham khảo nhiều kinh nghiệm quý báu từ đội PPP và Captf.
Tổng quan
Trước khi có ý định tổ chức một cuộc thi CTF, bạn nên dành thời gian để chơi CTF đã. Việc làm quen với các đề thi CTF sẽ giúp bạn có một ý niệm chính xác về cách ra đề cũng như các hình thức thường được áp dụng để triển khai CTF.
Thời gian tổ chức
- Nên tổ chức vào cuối tuần
- Xem lịch ở CTFTime để tránh các cuộc thi lớn khác có thể diễn ra cùng thời điểm
- Nếu tổ chức giải quốc tế thì nên tránh các kỳ nghỉ lễ của nước ngoài
- Thời gian tổ chức nên là bội của 24 giờ để các đội ở các quốc gia khác nhau không cảm thấy bị thiệt về thời gian
- Nếu có ý định đưa cuộc thi của mình lên CTFTime thì cần kiểm tra lại kỹ các thông tin sau khi submit, gửi mail cho ctftime team nếu thấy giải của mình chưa được cập nhật.
Khuôn dạng Flag
- Để dạng chung, người chơi nhìn vào là biết ngay flag như: Flag{e0fb6652a703c0018e0bfd8bd98a6032}
- Không đặt flag linh tinh, làm rối người chơi như hihi123, vovavovan…
Kiểm thử
Việc kiểm thử là cực kỳ quan trọng trước khi quyết định có sử dụng đề hay không. Đôi khi ý tưởng của người ra đề không giống với cách mà người chơi nghĩ về đề, nên:
- Bắt buộc phải kiểm thử trước khi public đề
- Người ra đề và người kiểm thử phải làm việc độc lập
- Kiểm thử đển khi nào ra được flag thì dừng, nếu thấy không làm được thì xin thêm hint từ tác giả.
Truyền thông
- Nên có 1 Notification Page chính thức trên Scoreboard
- Sử dụng twitter/facebook để dự phòng hoặc trong trường hợp người dùng bất kỳ không thể vào scoreboard
- Liên lạc với thí sinh qua kênh chat IRC. Ưu điểm: bất kỳ ai cũng có thể join, không cần tạo tài khoản, có cả chat private lẫn public, và có thể lấy được IP người chơi, phục vụ điều tra sau này nếu cần
- Các thông báo quan trọng cần đưa lên cả Notification Page lẫn irc để người chơi không bỏ sót
Cập nhật challenge
- Khi có thay đổi về challenge, thông báo broadcast lên tất cả các kênh liên lạc
- Cập nhật lại tên binary khi có thay đổi
- Nếu thực sự cần thay đổi khi đã có đội giải được, cần cân nhắc vì nó ảnh hưởng đến điểm của các đội và giải quyết theo từng trường hợp cụ thể
Phân phối Binary
- Lưu tất cả binary trên 1 server riêng, không nằm chung với đề
- Tên file nên kèm theo hash để người chơi có thể tự kiểm tra tính toàn vẹn
- Nếu có file kích thước lớn, hãy đặt mật khẩu và cho người chơi tải về trước cuộc thi. Và cung cấp mật khẩu cho họ khi mở đề
Luật thi
- Ban tổ chức phải đưa ra một quy định rõ ràng, đầy đủ và công khai trước khi cuộc thi diễn ra tránh gian lận và những tranh chấp không đáng có. Chẳng hạn như sự cố ở Codegate 2016
- Các quy định nên có:
- Không DoS/DDoS hay sử dụng các tấn công mang tính phá hoại vào hạ tầng và các chủ thể không nằm trong đề thi
- Không chia sẻ flag giữa các đội
- Nếu cuộc thi là onsite, nên quy định:
- Số lượng thành viên tham gia
- Các yếu tố liên quan đến văn hóa, đặc điểm riêng tại quốc gia thi
- Quyết định của ban tổ chức luôn là quyết định cuối cùng
Kiến trúc chung
1. Front-end
Scoreboard
Đây là giao diện xác thực, submit điểm và cập nhật bảng xếp hạng và là tính năng bắt buộc phải có ở bất kỳ cuộc thi nào.
- Nên cung cấp Service (RESTFUL) bảng xếp hạng để tái sử dụng nếu cần thiết, chẳng hạn như cho ctftime
- Không nên tự code, nếu chưa có kinh nghiệm vì rất dễ xảy ra sai sót và tốn thời gian
- Có nhiều opensource có thể sử dụng: fbctf, ctfd.io, mellivora…
- Những lỗi hay xảy ra: Race-condition, IDOR (insecure direct object reference), XSS
- Tính năng bắt buộc có:
- Ghi log user và log submit để giải quyết tranh chấp nếu có: thời điểm submit (timestamp hoặc thời gian tính đến milisecond), user submit, nội dung flag, ip, user-agent
- Cộng/trừ điểm thủ công, đề phòng trường hợp có sự cố về điểm của các đội, chẳng hạn ghi nhận sai
Load balancer
- DNS-based load balancing
- Đảm bảo hệ thống luôn hoạt động ổn định
- Sẽ rất quan trọng nếu có số đội tham gia lớn
2. Database Server
- Thường nằm chung scoreboard server, tuy nhiên nên tách riêng để dễ xử lý.
- Dùng loại nào tùy thuộc vào platform bạn sử dụng hoặc sở thích
- Nên dùng: SQL Server, MySQL, PostgresSQL, MongoDB
3. Challenge Server
- Tốt nhất mỗi challenge một server nếu không có kinh nghiệm tổ chức
- Nên dùng server linux, không dùng windows server do việc phân quyền trên linux tốt hơn, kiểm soát người chơi được. Tránh bị pwn hẳn server
- Nếu đặt chung server thì cần đặt theo loại bài: pwn, web, crypto và mỗi bài thì nằm trong một thư mục user riêng.
- Cần cập nhật hệ điều hành bản mới nhất, patch đầy đủ các bản vé để tránh pwn qua OS
- Cần phân quyền tốt, sử dụng
chroot
hoặc tự phát triểnsandbox
nếu cần thiết - Tốt nhất nên để 1-2 người phụ trách công việc deploy đề, họ phải là những người có kỹ năng tốt và kinh nghiệm về Linux, hiểu biết về nhiều mảng đề khác nhau. Nếu nhiều người cùng làm thì dễ bị misconfig
Hình thức thi đấu
Jeopardy
Remote Pwnable
Đây là hình thức thi đấu phổ biến nhất cho pwn hiện nay, và cũng dễ thực hiện nhất. Ý tưởng ở đây là:
- Chương trình có lỗ hổng hoạt động như một service thông qua một port được bind trước.
- Người chơi kết nối đến port này và gửi dữ liệu về cho chương trình, lợi dụng lỗi khai thác thông qua các
malformed input
.
Một vấn đề ở đây là nếu bind port trực tiếp trên binary thì sẽ dẫn đến tình trạng chương trình bị crash nếu một người chơi gửi malformed input, chương trình sẽ không tự bật lại và làm ảnh hưởng đến những người chơi khác.
Có 2 giải pháp cho vấn đề này:
1. Forking
- Là cơ chế của hệ điều hành
*nix
cho phép tạo ra các sub-process, và có thể dùng lại một phần bộ nhớ của process cha - Main process tạo listening socket, nhận request từ người chơi và fork ra các subprocess
- Không nên tự code nếu không hiểu hết về quản lý tiến trình của hệ điều hành
- Nên sử dụng các pattern đã chạy ổn định từ trước, chẳng hạn Ghost in the Shellcode Forking
2. Port Forwarding:
- Nhận request từ user và forward đến vulnerable program phía trong
xinetd
là một daemon của Linux, giao tiếp với vulnerable program thông qua stdin/stdout nên vuln program chỉ cần code dưới dạng stdin/stdout mà không cần quan tâm đến socket- Giải pháp khác: socat
Nguyên tắc setup
useradd -m problemuser
chown -R root:problemuser /home/problemuser
chmod 750 /home/problemuser
touch /home/problemuser/flag
chown root:problemuser /home/problemuser/flag
chmod 440 /home/problemuser/flag
Để tăng tính an toàn cho challenge server, cần đặt challenge trong sandbox hoặc hạn chế các quyền của user. Gợi ý:
- chroot
- facl
Chẳng hạn:
setfacl -m user:$USER:0 /var
setfacl -m user:$USER:0 /dev
setfacl -m user:$USER:0 /mnt
setfacl -m user:$USER:0 /tmp
Cần lưu ý:
- Không chặn
/bin/cat
,/bin/sh
,/bin/bash
và một số binary hệ thống nhạy cảm khác để đảm bảo chương trình hoạt động bình thường và người chơi có thể đọc được flag. Trong những trường hợp hạn chế nhiều tính năng cần thông báo cho người chơi biết. - Cung cấp đủ thông tin cho người chơi như môi trường, hệ điều hành, cấu hình (ASLR có bật không), lib nếu cần…
Web
Việc cấu hình các challenge này phụ thuộc lớn vào ý tưởng ra đề, tuy nhiên có một số lưu ý chung:
- Không nên quá mạo hiểm khi triển khai những challenge có khả năng upload shell và RCE. Trong trường hợp có những challenge thế này hãy đảm bảo là bạn đã cấu hình
chroot
hoặc 1 sandbox tương đương - Với những challenge có liên quan tới Database, hãy tạo một user dành riêng cho schema của challenge đó và grant privileges quyền tối thiểu có thể hoạt động được cho user này.
- Với những challenge liên quan đến Stored XSS thì phantomjs, selenium là những lựa chọn tốt nếu bạn muốn xây dựng một con bot kiểm tra feedback tự động
- Cấu hình thư mục web 755
- Upload file với quyền apache/httpd/nginx, không sử dụng quyền
root
Crypto
Một challenge Crypto hay không làm người chơi mất quá nhiều thời gian (trong tuyệt vọng) để đoán được loại mật mã được sử dụng (cổ điển hay hiện đại, RSA hay DES…). Thay vào đó người chơi chỉ nên tập trung vào độ khó của bài toán, đó nên là challenge sử dụng logic, suy diễn toán học hoặc cần các kỹ thuật tấn công mật mã đã biết. Có nhiều cách để triển khai crypto như binary file, web app, network service. Nếu là network service, hãy tham khảo cách cấu hình của pwnable challenge.
Reverse
- Phải nêu rõ bạn muốn người chơi submit giá trị gì khi reverse thành công, chẳng hạn như key hay một string mà người chơi nhìn thấy sau khi nhập key đúng
- Đảm bảo chỉ có 1 key duy nhất đúng nếu bạn muốn người chơi submit key, có 2 kết quả trở lên thì mọi thứ sẽ rất tệ hại
Attack/Defense
Đây là một hình thức thi đấu rất khó để tổ chức và thực sự là bạn không nên tổ chức nếu như chưa từng có kinh nghiệm trước đó để tránh các kết cục đáng tiếc.
Nguyên tắc tối thiểu
- Phải hạn chế được rủi ro ở mức thấp nhất
- Ban tổ chức luôn kiểm soát được tình hình
Kịch bản
Không có một mô hình chung nào cho CTF Attack/Defense và ở mỗi cuộc thi, các nhóm ra đề thường có một ý tưởng riêng thể hiện sự sáng tạo của họ. Nhưng về cơ bản thì kịch bản game phụ thuộc phần lớn vào phương pháp phòng thủ mà BTC muốn người chơi thực hiện. Yếu tố này rất quan trọng, về nếu không kiểm soát được cách làm của người chơi thì cuộc thi rất dễ đổ vỡ.
Các cách phòng thủ thường được áp dụng đó là Patch binary và Filter traffic
Cách tính điểm
- Có 2 loại điểm: Điểm tấn công và điểm phòng thủ
- Điểm tấn công được ghi nếu một đội chơi khai thác thành công challenge của đội bạn
- Điểm phòng thủ do scorebot tự tính, nếu kiểm tra thấy hệ thống hoạt động bình thường (không chặn quá đà, không đóng dịch vụ)
- Scorebot hoạt động một cách tự động, kiểm tra dịch vụ đội chơi không định kỳ (điều này giúp ngăn chặn đội chơi không biết được ý đồ)
Thiết kế hệ thống Attack/Defense
Ở đây tôi đề xuất một mô hình Attack/Defense mà nguyên tắc phòng thủ dựa trên việc kiểm soát traffic vào/ra vulnerable system
- Tài nguyên cho mỗi đội là 2 server
- Một Server các đội chơi được kiểm soát hoàn toàn và dùng để phòng thủ
- Một Server chứa lỗ hổng, và các đội không được thao tác gì trên server này
- Request đến server phòng thủ phải được forward hết vào phía trong cho server vuln
- Hệ thống mạng phải được thiết kế để các đội chơi không thể phân biệt được đâu là traffic đến từ đội chơi khác và đâu là traffic của scorebot để tránh trường hợp các đội chơi chặn đội khác nhưng vẫn mở dịch vụ cho scorebot vào check.
- BTC phải thiết kế 1 dịch vụ phía trước trên vuln server hứng request để giao tiếp với bot. Khi đấy bot sẽ biết được traffic đi vào vulnerable app có khớp với traffic gửi vào hay không.