feat: challenge registry-driven platform + XVI/XVII imports + admin toggle + domain rename

- Rename repo/domain: attack-defense-platform / attackdefense.imrnes.team (all refs replaced)
- challenge_registry.json: single source of truth (28 challs across gemastik18/xvi/xvii)
- teams.py: registry-driven CHALLENGES, set_challenge_enabled, sync_challenge_runtime
  (apply enable/disable to live teams: build/up or stop/remove + receiver restart)
- compose_gen.py: render per-team compose from canonical per-challenge templates
  (image reuse, per-team ports 30xxx, flag mounts, passwords)
- gen_canonical_composes.py: canonical docker-compose.yml for all services
- import_new_challenges.py: import XVI/XVII services + EOL base image fixes
  (debian:buster→bookworm, node:14→20, python:3.7-slim→3.11)
- receiver: xvi package (10 checkers) + xvii package (12 generic checkers),
  Challenge base reads PASSWORD_<team_port> from env; gen_receiver_main.py
  generates per-team main.py from registry
- main.py: /api/challenges returns full registry; PATCH /api/challenges/<name>
  toggles enabled + applies to live teams
- index.html: 🏗️ Challenge Manager tab (toggle per challenge, grouped by set)
- SLA bonus now dynamic (all enabled challenges, not hardcoded 6)
This commit is contained in:
MythEclipse committed 2026-09-25 14:04:33 +08:00
1 parent c35b23a37f
commit c6fd9ec268
1317 files changed
+306586 -128

No files matched your search

+32
View File
@@ -0,0 +1,32 @@
FROM ubuntu:24.04
ARG PASSWORD
ENV DEBIAN_FRONTEND noninteractive
RUN echo root:${PASSWORD} | chpasswd
COPY apt-insecure.conf /etc/apt/apt.conf.d/99gemastik-insecure
RUN apt-get -o Acquire::AllowInsecureRepositories=true update && apt-get install -y openssh-server xinetd cmake gcc curl
RUN echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config
RUN echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
RUN service ssh start
RUN useradd -m ctf
WORKDIR /ctf
RUN echo "Connection blocked" > /etc/banner_fail
COPY ctf.xinetd /etc/xinetd.d/ctf
COPY ./src/main.c ./
COPY ./run.sh ./
COPY ./start.sh ./
RUN gcc /ctf/main.c -o /ctf/main
RUN touch /flag.txt
RUN chmod -R 755 /ctf
RUN chmod +x /ctf/start.sh
CMD ./start.sh
EXPOSE 8000
+3
View File
@@ -0,0 +1,3 @@
Acquire::AllowInsecureRepositories "true";
Acquire::AllowDowngradeToInsecureRepositories "true";
Apt::Get::AllowUnauthenticated "true";
+16
View File
@@ -0,0 +1,16 @@
service ctf
{
disable = no
socket_type = stream
protocol = tcp
wait = no
user = root
type = UNLISTED
port = 8000
bind = 0.0.0.0
server = /bin/sh
server_args = /ctf/run.sh
banner_fail = /etc/banner_fail
# safety options
rlimit_cpu = 1 # the maximum number of CPU seconds that the service may use
}
+18
View File
@@ -0,0 +1,18 @@
services:
bit-canvas:
container_name: bit-canvas_container
hostname: bit-canvas
restart: always
build:
context: .
args:
- PASSWORD=$PASSWORD_20000
volumes:
- ../receiver/flags/bit-canvas.txt:/flag.txt:ro
- ../utils/bashrc:/root/.bashrc:ro
- ../utils/preexec.sh:/root/.preexec.sh:ro
ports:
- "20000:8000"
- "20022:22"
extra_hosts:
- "host.docker.internal:host-gateway"
+1
View File
@@ -0,0 +1 @@
su ctf -c "timeout 60s /ctf/main"
+112
View File
@@ -0,0 +1,112 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
int main() {
setbuf(stdout, NULL);
int choice = 0;
int debug = 0;
int size = 16;
int canvas[16] = {0};
puts("bit-canvas @ gemastik-xvii");
puts("1. draw");
puts("2. clear");
puts("3. resize");
puts("4. admin");
puts("5. exit");
while (1) {
printf("choice? ");
scanf("%d", &choice);
switch (choice) {
case 1:
int n = 0;
int x = 0;
int y = 0;
printf("how many bits? ");
scanf("%d", &n);
if (n > (size * size * 2)) {
puts("too many bits");
return 1;
}
for (int i = 0; i < n; i++) {
printf("where x y? ");
scanf("%d %d", &x, &y);
bool prev = 0;
bool next = 0;
prev = canvas[x] >> y & 1;
next = prev ^ 1;
canvas[x] ^= 1 << y;
if (debug) printf("[DEBUG] x: %d, y: %d, prev: %d, next: %d\n", x, y, prev, next);
}
break;
case 2:
for (int i = 0; i < size; i++) {
for (int j = 0; j < size * 2; j++) {
canvas[i] = 0;
}
}
break;
case 3:
printf("size? ");
scanf("%d", &size);
break;
case 4:
FILE *f = fopen("/flag.txt", "r");
if (f == NULL) {
puts("flag not found");
return 1;
}
char flag[43];
char buffer[43];
fgets(flag, sizeof(flag), f);
fclose(f);
printf("password? ");
scanf("%s", buffer);
if (!strcmp(buffer, flag)) {
debug = 1;
puts("debug mode enabled");
} else {
puts("invalid password");
}
break;
case 5:
puts("bye");
return 0;
default:
printf("invalid choice %d\n", choice);
return 1;
}
for (int i = 0; i < size; i++) {
for (int j = 0; j < size * 2; j++) {
printf("%d", canvas[i] >> j & 1);
}
puts("");
}
}
return 0;
}
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
/usr/sbin/sshd -D &
/usr/sbin/xinetd -dontfork