1520 words
8 minutes
Xây dựng hệ thống CTFd - part 2

Sau khi hoàn tất việc xây dựng hệ thống ở mức cơ bản để có thể sử dụng trong bài viết đầu tiên về xây dựng hệ thống CTFd, trong bài này thì mình sẽ giới thiệu một số công cụ cùng với các plugins được sử dụng để có thể host một giải CTF chỉnh chu nhất có thể

CẢNH BÁO

Trong bài viết này mình chỉ hướng dẫn cho việc build from source nên khi các bạn tự pull về bằng docker CTF thì mình sẽ có một bài viết trong tương lai về phần này nhé

Bài viết này sẽ chia làm 02 phần cài ThemesPlugins

Themes#

Về phần theme, khi các bạn chơi CTF ở các giải khác nhau thì sẽ có rất nhiều theme khác nhau được sử dụng riêng cho giải đấu, hoặc các bạn có thể lên trang CTFd họ cũng bán các loại theme khác nhau để sử dụng trong CTF, và dĩ nhiên là nó tính phí. Bạn có thể xem tại đây

image

Và vì CTFd là một dự án Opensource, vì thế trên cộng dồng cũng đã phát triển khá nhiều Theme khác nhau và được CTFd mark cho một trang riêng để ta có thể tiện để có thể clone về và sử dụng. Các bạn có thể tham khảo tại đây

Và để có thể sử dụng các Theme này bên trong CTFd, ta sẽ cần phải biết đường dẫn của Theme, tại thư mục CTFd, theme sẽ được đặt tại CTFd\themes

Tại đây thì ta thấy được cơ bản CTFd cung cấp cho ta 02 themes và một trong quản trị admin

image

Mình sẽ lấy một Theme làm ví dụ, tại đây mình sẽ lấy Theme này để làm ví dụ (tại vì nó đẹp)

Một cấu trúc file Theme cơ bản sẽ có các thành phần sau:

image

Việc của chúng ta chỉ cần đem folder này ném vào trong CTFd\themes là thành công

image

Lưu ý

Tùy vào từng theme mà họ sẽ có những cách cài đặt khác nhau, và đây chỉ là cài đặt Theme cơ bản, mỳ ăn liền nên sẽ dễ tiếp cận với các bạn mới. Tuy nhiê nếu muốn tùy biến thì các bạn có thể tham khảo thêm trên docs của CTFd

Sau khi cài xongg rồi chúng ta sẽ vào phần config theo đường dẫn sau: <url thi>/admin/config và kéo xuống phần Appearance/Theme tại đây chúng ta đã thấy có Theme chúng ta đã thêm vào

image

Click chọn và nhấn Update, thoát ra trang chủ thì ta sẽ thấy sự thay đổi

image

Plugins#

Cũng giống như Themes, các Plugins cũng sẽ có một đường dẫn để chứa hết tất cả các Plugins, đường dẫn của nó sẽ nằm chung với thư mục cha của Themes

image

Tại phần Plugins mình sẽ Setup bao gồm các thứ như sau:

  • Discord firstblood
  • Scoring
  • Dynamic instance cho các challenge Web

Discord firstblood#

Đa phần các giải CTF đều sẽ có một con bot chuyên cho việc thông báo First Blood,tương tự như thế này

image

Để tạo được một bot như vậy thì tại đây mình sẽ dùng ctfd-discord-webhook-plugin của sigpwny, và đương nhiên là tất cả plugins này mình sẽ lấy trên Github tại mình quá noob để có thể dev ra những cái Plugins giống vầy

Để cài đặt, ta sẽ clone về thư mục Plugins

git clone https://github.com/sigpwny/ctfd-discord-webhook-plugin.git

Sau khi clone về thành công thì ta sẽ cần tới Discord webhook url, để lấy được Webhook URL thì chúng ta chỉ cần vào Discord đến kênh chúng ta muốn sử dụng để thông báo Firstblood chọn vào phần setting của kênh

image

Và chọn click vào theo thứ tự như hình bên dưới

image

Sau khi có được Webhook URL, ta sẽ sử dụng để cấu hình cho bot. Để cấu hình, ta sẽ vào bên trong file docker-compose.yml của CTFd để config.

Tại phần services/ctfd/environment ta sẽ thêm các dòng lệnh dưới đây để có thể thêm biến môi trường để bot có thể hoạt động

- DISCORD_WEBHOOK_URL="webhook_của_bạn"
- DISCORD_WEBHOOK_LIMIT="Số lượng người giải được"
- DISCORD_WEBHOOK_MESSAGE="Thông báo bạn muốn khi thông báo như thế nào"

Như ví dụ dưới đây thì mình sẽ có setting như sau:

- DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/1340061336134221834/A49eG4cvNKDALom_bWyksYvhBKq6RT4t6x3BYS5e8edSqQ8pK8OD4nDEWM5DJ8eycV4o
- DISCORD_WEBHOOK_LIMIT="1"
- DISCORD_WEBHOOK_MESSAGE=Chúc mừng \"{team}\" cho \"{fsolves}\" trên challenge \"{challenge}\"

Sau khi đã setup xong, chúng ta sẽ restart lại docker

# cho container down xuống
docker compose down 

#build lại container
docker compose up --build

#xóa đi các thứ không cần thiết
docker system prune -a

Kiểm tra bằng cách thử tạo ra một Challenge rồi thử tính năng

image

image

Scoring#

Về phần Scoring, thường thì phần này mọi người sẽ bỏ qua tại mọi người thường sẽ sử dụng Scoring của CTFd luôn, tuy nhiên thì sau khi mình đọc một bài nghiên cứu nói về Scoring của CTFd thì biểu đồ của CTFd nhìn không ổn tí nào, vì thế nên mình sẽ apply thêm motojcasi scoring khác trong hệ thống CTFd của mình

Đây là biểu đồ của CTFd điểm giảm:

image

Và đây là bản mod của sigpwny

image

Vào trong thư mục plugin, chúng ta sẽ cấu hình như sau:

git clone https://github.com/sigpwny/ctfd-dynamic-challenges-mod.git dynamic_challenges_mod 

Sau đó thực hiện việc restart lại docker

# cho container down xuống
docker compose down 

#build lại container
docker compose up --build

#xóa đi các thứ không cần thiết
docker system prune -a

Dynamic Docker Instance#

Vấn đề được đặt ra khi trong một giải đấu CTF đó chính là làm sao để hệ thống Challenge được host trên nền tảng luôn được trong trạng thái ổn nhất, đặc biệt các thử thách web challenge rất dễ bị tấn công bruteforce hoặc chiếm quyền điều khiển để đổi Flag trên hệ thống, vì thế Dynamic Docker instance được sinh ra để có thể cung cấp cho mỗi team một docker riêng cho thử thách để tránh việc ảnh hưởng tới các team khác

Để sử dụng, chúng ta sẽ tiến hành cài đặt. Trên trang github của author cũng ghi khá rõ về các bước thực hiện, tuy nhiên để tránh mất thời gian lòng vòng thì mình sẽ hướng dẫn luôn cho các bạn

  • Git clone repo về thư mục plugins
git clone https://github.com/phannhat17/CTFd-Docker-Plugin.git containers

Sau khi clone về xong, ta sẽ tiến hành set up, tại đây có hai cách set up

  • Setup sử dụng socket docker của CTFd
  • Setup sử dụng SSH qua một máy host đề khác

Socket Docker#

Tại đây thì cách này khuyến khích không nên dùng, vì khi kết nối Socket docker của máy host CTFd đồng nghĩa vói việc bạn sử dụng máy host CTFd làm máy host đề,

Điều này vẫn được nhưng không phải là Best Practice dựa trên doc của Docker, nhưng mà cứ làm đi =)))

Để làm điều này thì trong docker-compose.yml ta sẽ thêm phần sau đây vào services/ctfd/volumes

- /var/run/docker.sock:/var/run/docker.sock

Rồi sau đó sẽ chạy build lại docker là được. Sau khi restart thì ta có thể thấy rằng thanh kết nối reachable có nghĩa là đã thành công

image

Bây giờ chỉ việc spawn Docker challenge trên máy đang chạy CTFd là được rồi nhé :>

SSH Docker#

Tại đây thì nó sẽ phức tạp hơn một chút, vì chúng ta phải cấu hình máy đang chạy CTFd kết nối được tới máy host đề

Giả sử mình có hai máy sau:

  • Máy chạy CTFd: 35.229.144.39
  • Máy chạy chứa đề Docker đề web: 35.221.234.224

Các bước thực hiện như sau:

  • Tạo SSH key pair trên máy chạy CTFd:
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa
  • Copy Public key tới máy host đề. Mục đích để vào SSH mà không bị hỏi password
ssh-copy-id -i ~/.ssh/id_rsa.pub <tên user>@<IP máy host đ>
CẢNH BÁO

Khi copy thì có thể sẽ được hỏi fingerprint các bạn nhấn yes luôn nhé

  • Cho thông tin vào known_host, từ máy CTFd, ta sẽ tiến hành kết nối SSH tới máy host đề
ssh <tên user>@<IP máy host đ>

Mình sẽ được hỏi fingerprint như sau đây thì chỉ cần type yes:

image

  • Cấu hình ~/.ssh/config bằng cấu hình sau:
Host <IP server>
  HostName <IP server>
  User <tên để login>
  IdentityFile ~/.ssh/id_rsa

Như cấu hình của mình thì ở đây sẽ là:

Host 35.221.234.224
  HostName 35.221.234.224
  User lmao
  IdentityFile ~/.ssh/id_rsa
  • Vào trong thư mục chứa docker_compose.yml và thực hiện các câu lệnh sau:
mkdir ssh_config

cp ~/.ssh/id_rsa ~/.ssh/known_hosts ~/.ssh/config ssh_config/

image

  • Vào bên trogn docker-compose.yml và thêm các câu lệnh sau tai phần services/ctfd/volumes
- ./ssh_config:/root/.ssh:ro

Sau đó tiến hành restart lại Docker:

docker compose down
docker compose up

Sau đó thì vào và điền thêm SSH như trong ảnh rồi ta nhấn Submit sẽ thấy được connect status Reachable như hình

image

Một khi đã reachable thì ta sẽ test thử một challenge bằng docker. Tại đây mình đã chuẩn bị sẵn một bài CTF, build lên và tiến hành test.

Tại phần tạo Challenge, chúng ta sẽ sử dụng containers, và cấu hình như sau:

  • Images: Image docker mà bài bạn muốn host
  • Connection type: Loại kết nối
  • Port: đây là phần khá quan trọng, để kiểm tra Port mapping cho đúng thì ta sẽ sử dụng câu lệnh sau:
docker ps -a #sau đó tìm đúng tên container

Như ta thấy bài CTF của chúng ta đang muốn host đang sử dụng port 8386 nghe từ tất cả IP tới port 8386 của container, thì chỉ cần điền phần port 8386 vào thôi

image

image

Sau đó thì create như bình thường, vào challenges để xem thì ta có giống dưới đây

image

image

Kiểm tra trên máy host đề, ta có container được tạo như sau:

image

Truy cập thử trang web:

image

Xây dựng hệ thống CTFd - part 2
https://jerryyytheduck.id.vn/posts/ctfd-infrastructure/ctfd-infra-2/
Author
Jerryyy
Published at
2025-02-19