From f553033b3b032b0f8e39f36107e14c661d6eb20d Mon Sep 17 00:00:00 2001 From: Connor Nelson Date: Wed, 1 Feb 2023 12:20:34 -0700 Subject: [PATCH] Updated challenges showing off dojo features --- example-challenges/README.md | 1 - example-challenges/_global/README.global | 1 - example-challenges/level1/0/README | 1 - example-challenges/level1/0/level1 | 3 --- example-challenges/level1/1/README.md | 1 - example-challenges/level1/1/level1 | 3 --- example-challenges/level2/0/.init | 4 ---- example-challenges/level2/0/README | 1 - hello/apple/README.md | 10 ++++++++++ hello/apple/apple | 4 ++++ hello/banana/README.md | 14 ++++++++++++++ hello/banana/_0/.config | 1 + hello/banana/_1/.config | 1 + hello/banana/_2/.config | 1 + hello/banana/banana | 10 ++++++++++ world/earth/.init | 10 ++++++++++ world/earth/README.md | 14 ++++++++++++++ world/earth/earth | 4 ++++ world/earth/planets.txt | 1 + world/mars/README.md | 17 +++++++++++++++++ world/mars/orbit | 15 +++++++++++++++ world/mars/planets.txt | 1 + world/planets.txt | 8 ++++++++ world/venus/.init | 23 +++++++++++++++++++++++ world/venus/README.md | 17 +++++++++++++++++ world/venus/_0/takeoff | 6 ++++++ world/venus/_1/takeoff | 6 ++++++ world/venus/launch.j2 | 8 ++++++++ world/venus/planets.txt | 1 + 29 files changed, 172 insertions(+), 15 deletions(-) delete mode 100644 example-challenges/README.md delete mode 100644 example-challenges/_global/README.global delete mode 100644 example-challenges/level1/0/README delete mode 100755 example-challenges/level1/0/level1 delete mode 100644 example-challenges/level1/1/README.md delete mode 100755 example-challenges/level1/1/level1 delete mode 100755 example-challenges/level2/0/.init delete mode 100644 example-challenges/level2/0/README create mode 100644 hello/apple/README.md create mode 100644 hello/apple/apple create mode 100644 hello/banana/README.md create mode 100644 hello/banana/_0/.config create mode 100644 hello/banana/_1/.config create mode 100644 hello/banana/_2/.config create mode 100644 hello/banana/banana create mode 100644 world/earth/.init create mode 100644 world/earth/README.md create mode 100644 world/earth/earth create mode 120000 world/earth/planets.txt create mode 100644 world/mars/README.md create mode 100644 world/mars/orbit create mode 120000 world/mars/planets.txt create mode 100644 world/planets.txt create mode 100644 world/venus/.init create mode 100644 world/venus/README.md create mode 100644 world/venus/_0/takeoff create mode 100644 world/venus/_1/takeoff create mode 100644 world/venus/launch.j2 create mode 120000 world/venus/planets.txt diff --git a/example-challenges/README.md b/example-challenges/README.md deleted file mode 100644 index 4b7f202..0000000 --- a/example-challenges/README.md +++ /dev/null @@ -1 +0,0 @@ -This directory is a "category" of challenges. It can hold multiple levels (with multiple variants per level) along with global files. diff --git a/example-challenges/_global/README.global b/example-challenges/_global/README.global deleted file mode 100644 index 2a02031..0000000 --- a/example-challenges/_global/README.global +++ /dev/null @@ -1 +0,0 @@ -All files from the "_global" directory are also copied into /challenge and made SUID-executable. This can help with common resources for all levels in a module. diff --git a/example-challenges/level1/0/README b/example-challenges/level1/0/README deleted file mode 100644 index 51392db..0000000 --- a/example-challenges/level1/0/README +++ /dev/null @@ -1 +0,0 @@ -The files from the level directory are copied into /challenge, set up to be owned by root, and made SUID-executable. diff --git a/example-challenges/level1/0/level1 b/example-challenges/level1/0/level1 deleted file mode 100755 index 36114f8..0000000 --- a/example-challenges/level1/0/level1 +++ /dev/null @@ -1,3 +0,0 @@ -#!/opt/pwn.college/python - -print(open("/flag").read()) \ No newline at end of file diff --git a/example-challenges/level1/1/README.md b/example-challenges/level1/1/README.md deleted file mode 100644 index 9fc1ae8..0000000 --- a/example-challenges/level1/1/README.md +++ /dev/null @@ -1 +0,0 @@ -You can have several variants of a level that will be randomly assigned to users. Just give each variant its own directory! diff --git a/example-challenges/level1/1/level1 b/example-challenges/level1/1/level1 deleted file mode 100755 index 36114f8..0000000 --- a/example-challenges/level1/1/level1 +++ /dev/null @@ -1,3 +0,0 @@ -#!/opt/pwn.college/python - -print(open("/flag").read()) \ No newline at end of file diff --git a/example-challenges/level2/0/.init b/example-challenges/level2/0/.init deleted file mode 100755 index 9395214..0000000 --- a/example-challenges/level2/0/.init +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -cp /flag /tmp/here_it_is -chmod 644 /tmp/here_it_is diff --git a/example-challenges/level2/0/README b/example-challenges/level2/0/README deleted file mode 100644 index 1530ad2..0000000 --- a/example-challenges/level2/0/README +++ /dev/null @@ -1 +0,0 @@ -This level has a `.init` file that is run by root when the challenge is started! diff --git a/hello/apple/README.md b/hello/apple/README.md new file mode 100644 index 0000000..2ac033e --- /dev/null +++ b/hello/apple/README.md @@ -0,0 +1,10 @@ +# hello +## apple + +This challenge is named `apple`, and is located within module `hello`. + +When users start this challenge, their environment will have: +- `/flag` +- `/challenge/apple` + +`/flag` is read-only by root, and `/challenge/apple` is setuid root. diff --git a/hello/apple/apple b/hello/apple/apple new file mode 100644 index 0000000..5f7d07f --- /dev/null +++ b/hello/apple/apple @@ -0,0 +1,4 @@ +#!/opt/pwn.college/python + +with open("/flag") as f: + print(f.read()) \ No newline at end of file diff --git a/hello/banana/README.md b/hello/banana/README.md new file mode 100644 index 0000000..d72737f --- /dev/null +++ b/hello/banana/README.md @@ -0,0 +1,14 @@ +# hello +## banana + +This challenge is named `banana`, and is located within module `hello`. + +When users start this challenge, their environment will have: +- `/flag` +- `/challenge/banana` +- `/chalenge/.config` + +Within a challenge's definition, directories which begin with `_` are statically instanced. +Users will randomly, but deterministically, be assigned one instance of the challenge. +Every time they start the challenge, they will be assigned the same static instance. +This allows different users to receive different versions of the same challenge. diff --git a/hello/banana/_0/.config b/hello/banana/_0/.config new file mode 100644 index 0000000..573541a --- /dev/null +++ b/hello/banana/_0/.config @@ -0,0 +1 @@ +0 diff --git a/hello/banana/_1/.config b/hello/banana/_1/.config new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/hello/banana/_1/.config @@ -0,0 +1 @@ +1 diff --git a/hello/banana/_2/.config b/hello/banana/_2/.config new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/hello/banana/_2/.config @@ -0,0 +1 @@ +2 diff --git a/hello/banana/banana b/hello/banana/banana new file mode 100644 index 0000000..b11c559 --- /dev/null +++ b/hello/banana/banana @@ -0,0 +1,10 @@ +#!/opt/pwn.college/python + +import pathlib + +config = (pathlib.Path(__file__).parent / ".config").read_text().strip() + +print(f"Instance: {config}") + +with open("/flag") as f: + print(f.read()) \ No newline at end of file diff --git a/world/earth/.init b/world/earth/.init new file mode 100644 index 0000000..3aa0fe3 --- /dev/null +++ b/world/earth/.init @@ -0,0 +1,10 @@ +#!/opt/pwn.college/python + +import pathlib + +dir = pathlib.Path(__file__).parent +planets = (dir / "planets.txt").read_text().strip().splitlines() + +for planet in planets: + planet_path = dir / planet.lower() + planet_path.write_text(planet) diff --git a/world/earth/README.md b/world/earth/README.md new file mode 100644 index 0000000..2cc32ec --- /dev/null +++ b/world/earth/README.md @@ -0,0 +1,14 @@ +# world +## earth + +This challenge is named `earth`, and is located within module `world`. + +When users start this challenge, their environment will have: +- `/flag` +- `/challenge/earth` +- `/challenge/planets.txt` +- `/chalenge/.init` + +Symbolic links which are relative to the dojo root-directory are supported. + +When a challenge starts, and before users have access to their environment, `.init` will automatically be run as the root user. diff --git a/world/earth/earth b/world/earth/earth new file mode 100644 index 0000000..5f7d07f --- /dev/null +++ b/world/earth/earth @@ -0,0 +1,4 @@ +#!/opt/pwn.college/python + +with open("/flag") as f: + print(f.read()) \ No newline at end of file diff --git a/world/earth/planets.txt b/world/earth/planets.txt new file mode 120000 index 0000000..f1e9a24 --- /dev/null +++ b/world/earth/planets.txt @@ -0,0 +1 @@ +../planets.txt \ No newline at end of file diff --git a/world/mars/README.md b/world/mars/README.md new file mode 100644 index 0000000..0d8e840 --- /dev/null +++ b/world/mars/README.md @@ -0,0 +1,17 @@ +# world +## mars + +This challenge is named `mars`, and is located within module `world`. + +When users start this challenge, their environment will have: +- `/flag` +- `/challenge/orbit` +- `/challenge/planets.txt` + +In this challenge, `orbit` reads in the flag and seeds random off of it. +While this is a challenge-specific detail, it is a broadly useful idea. +It allows for the challenge's behavior to be dynamically dependent on the flag. +This offers a similar paradigm to instanced challenge files. +However, it is dynamically instanced, rather than statically instanced. +Statically instanced values may be accessed by a student, while dynamically instanced values may not be (since they are dependent on the flag). +Which style is appropriate depends on the specifics of the challenge. diff --git a/world/mars/orbit b/world/mars/orbit new file mode 100644 index 0000000..b70344a --- /dev/null +++ b/world/mars/orbit @@ -0,0 +1,15 @@ +#!/opt/pwn.college/python + +import pathlib +import random + +with open("/flag") as f: + random.seed(f.read()) + +planets = (pathlib.Path(__file__).parent / "planets.txt").read_text().strip().splitlines() + +print("This is a flag-seeded random number: {}".format(random.randint(0, 1000))) +print(random.choice(planets)) + +with open("/flag") as f: + print(f.read()) diff --git a/world/mars/planets.txt b/world/mars/planets.txt new file mode 120000 index 0000000..f1e9a24 --- /dev/null +++ b/world/mars/planets.txt @@ -0,0 +1 @@ +../planets.txt \ No newline at end of file diff --git a/world/planets.txt b/world/planets.txt new file mode 100644 index 0000000..d2f0f52 --- /dev/null +++ b/world/planets.txt @@ -0,0 +1,8 @@ +Mercury +Venus +Earth +Mars +Jupiter +Saturn +Uranus +Neptune diff --git a/world/venus/.init b/world/venus/.init new file mode 100644 index 0000000..911975a --- /dev/null +++ b/world/venus/.init @@ -0,0 +1,23 @@ +#!/opt/pwn.college/python + +import pathlib +import random + +import jinja2 + +with open("/flag") as f: + random.seed(f.read()) + +init_path = pathlib.Path(__file__) +planets_path = (pathlib.Path(__file__).parent / "planets.txt") +launch_path = (pathlib.Path(__file__).parent / "launch") +launch_template_path = (pathlib.Path(__file__).parent / "launch.j2") + +planet = random.choice(planets_path.read_text().strip().splitlines()) + +template = jinja2.Template(launch_template_path) +launch_path.write_text(template.render(planet=planet)) + +launch_template_path.unlink() +planets_path.unlink() +init_path.unlink() \ No newline at end of file diff --git a/world/venus/README.md b/world/venus/README.md new file mode 100644 index 0000000..159de01 --- /dev/null +++ b/world/venus/README.md @@ -0,0 +1,17 @@ +# world +## venus + +This challenge is named `venus`, and is located within module `world`. + +When users start this challenge, their environment will have: +- `/flag` +- `/challenge/takeoff` +- `/challenge/launch` + +In this challenge, `takeoff` is a statically instanced file. +There is also files `.init`, `planets.txt`, and `launch.j2` which students will never see. +At run time, `.init` reads in `planets.txt` to construct `launch` from the templated file `launch.j2`. +This gives the challenge static instancing dependent upon the flag. +In general, it is best to define a pool of static instanced files prior, so that this setup does not need to be performed at runtime every challenge start. +However, for simple cases, this may be acceptable. +It is important to note, however, that the results of these static instances are still dependent upon the flag, which means running the challenge with a different flag (e.g. with a practice flag), will fundamentally change the instance. diff --git a/world/venus/_0/takeoff b/world/venus/_0/takeoff new file mode 100644 index 0000000..f6cb901 --- /dev/null +++ b/world/venus/_0/takeoff @@ -0,0 +1,6 @@ +#!/opt/pwn.college/python + +import sys + +print("3.... 2... 1...") +print(sys.argv[1]) \ No newline at end of file diff --git a/world/venus/_1/takeoff b/world/venus/_1/takeoff new file mode 100644 index 0000000..f1db5ba --- /dev/null +++ b/world/venus/_1/takeoff @@ -0,0 +1,6 @@ +#!/opt/pwn.college/python + +import sys + +print("5... 4... 3.... 2... 1...") +print(sys.argv[1]) \ No newline at end of file diff --git a/world/venus/launch.j2 b/world/venus/launch.j2 new file mode 100644 index 0000000..89962a9 --- /dev/null +++ b/world/venus/launch.j2 @@ -0,0 +1,8 @@ +#!/opt/pwn.college/python + +import subprocess + +subprocess.run(["/challenge/takeoff", "{{ planet }}"]) + +with open("/flag") as f: + print(f.read()) \ No newline at end of file diff --git a/world/venus/planets.txt b/world/venus/planets.txt new file mode 120000 index 0000000..f1e9a24 --- /dev/null +++ b/world/venus/planets.txt @@ -0,0 +1 @@ +../planets.txt \ No newline at end of file