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

+134
View File
@@ -0,0 +1,134 @@
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
import os
import random
import signal
import base64
FLAG = open("../flag.txt").read()
class GiftShop:
def __init__(self, name: str) -> None:
self.key = RSA.generate(1024)
self.Hm = SHA256.new(name.encode()).digest()
self.prefix = b"\x00\x02"
self.null = b"\x00"
def generate_voucher(self) -> str:
message = self.prefix + os.urandom(93) + self.null + self.Hm
voucher = pow(int.from_bytes(message, "big"), self.key.d, self.key.n)
return base64.b64encode(int.to_bytes(voucher, 128, "big")).decode()
def validate_voucher(self, voucher: str) -> bool:
voucher = int.from_bytes(base64.b64decode(voucher.encode()), "big")
message = int.to_bytes(pow(voucher, self.key.e, self.key.n), 128, "big")
return (
voucher.bit_length() <= 1024
and message.startswith(self.prefix)
and message.endswith(self.null + self.Hm)
)
class Challenge:
def __init__(self, name):
self.name = name
self.balance = 100
self.items = {
"bread": {"price": 33, "callable": self.__get_bread},
"voucher": {"price": 50, "callable": self.__get_voucher},
"flag": {"price": 420, "callable": self.__get_flag},
}
self.redeemed_voucher = set()
self.gift_shop = GiftShop(self.name)
def greet(self):
msg = ""
msg += f"\nWelcome, {self.name}!"
msg += f"\nOption:"
msg += f"\n [1] Check available items"
msg += f"\n [2] Buy item"
msg += f"\n [3] Redeem voucher"
msg += f"\n [9] Input admin code"
print(msg)
def __get_bread(self):
return self.gift_shop.key.public_key().export_key().decode().replace('-', chr(0x1F35E))
def __get_voucher(self):
return self.gift_shop.generate_voucher()
def __get_flag(self):
return FLAG
def check_available(self):
msg = ""
msg += f"\nAvailable items:"
for item_name, item_info in self.items.items():
item_price = item_info["price"]
msg += f"\n [+] {item_name} (${item_price})"
return msg
def buy_item(self, item):
if item not in self.items.keys():
return f"Item {item} is not available"
if self.balance < self.items[item]["price"]:
return f"Insufficient balance"
self.balance -= self.items[item]["price"]
return self.items[item]["callable"]()
def redeem_voucher(self, voucher):
if voucher in self.redeemed_voucher:
return "Your voucher is already used"
if not self.gift_shop.validate_voucher(voucher):
return "Your voucher is invalid"
value = random.randint(30, 60)
self.balance += value
self.redeemed_voucher.add(voucher)
return f"You got ${value} from the voucher"
def admin_code(self, code):
if code != FLAG:
return "Incorrect code"
self.balance += self.items["flag"]["price"]
return "Correct code"
def user_input(s):
inp = input(s).strip()
assert len(inp) < 1024
return inp
def main():
name = user_input("Name: ")
challenge = Challenge(name)
challenge.greet()
while True:
print(f"\nCurrent balance: ${challenge.balance}")
match int(user_input("> ")):
case 1:
print(challenge.check_available())
case 2:
item = user_input("Item: ")
print(challenge.buy_item(item))
case 3:
voucher = user_input("Voucher: ")
print(challenge.redeem_voucher(voucher))
case 9:
code = user_input("Code: ")
print(challenge.admin_code(code))
case _:
print("Invalid option")
break
if __name__ == "__main__":
signal.alarm(60)
main()