diff --git a/example_deploy/pwnshop.yml b/example_deploy/pwnshop.yml index 9e8342e..e26e95a 100644 --- a/example_deploy/pwnshop.yml +++ b/example_deploy/pwnshop.yml @@ -18,3 +18,7 @@ challenges: - id: shell-1604 challenge: Shell1604 variants: 1 +- id: python-pass + challenge: PythonPass + binary_name: pp + variants: 2 diff --git a/example_module/__init__.py b/example_module/__init__.py index 2f3bd52..0b76d43 100644 --- a/example_module/__init__.py +++ b/example_module/__init__.py @@ -3,7 +3,7 @@ import os class ShellBase(pwnshop.Challenge, register=False): # don't register this as an actual challenge - TEMPLATE_PATH = "example_shell.c" + TEMPLATE_PATH = "template_shell.c" EXEC_STACK = True CANARY = True LINK_LIBRARIES = ["capstone"] @@ -80,3 +80,18 @@ class Shell1604InVitu(Shell1604): BUILD_IMAGE = "ubuntu:16.04" VERIFY_IMAGE = "ubuntu:16.04" PIN_LIBRARIES = False + +class PythonPass(pwnshop.PythonChallenge): + """ + Simple templated python example. + """ + TEMPLATE_PATH = "template_pypass.py" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.password = self.random_word(8) + + def verify(self, **kwargs): + with self.run_challenge() as p: + p.sendline(self.password) + assert self.flag in p.readall() diff --git a/example_module/template_pypass.py b/example_module/template_pypass.py new file mode 100644 index 0000000..7d7a0e3 --- /dev/null +++ b/example_module/template_pypass.py @@ -0,0 +1,6 @@ +#!/opt/pwn.college/python + +if input("Password? ").strip() == "{{challenge.password}}": + print(open("/flag").read()) +else: + print("Nope") diff --git a/example_module/example_shell.c b/example_module/template_shell.c similarity index 100% rename from example_module/example_shell.c rename to example_module/template_shell.c diff --git a/pwnshop/__init__.py b/pwnshop/__init__.py index 3cc980e..30822ca 100644 --- a/pwnshop/__init__.py +++ b/pwnshop/__init__.py @@ -2,6 +2,6 @@ ALL_MODULES = { } MODULE_LEVELS = { } -from .challenge import Challenge, KernelChallenge, WindowsChallenge, ChallengeGroup +from .challenge import Challenge, PythonChallenge, KernelChallenge, WindowsChallenge, ChallengeGroup from .register import register_challenge, register_challenges from .util import did_segfault, did_timeout, did_abort, did_sigsys, retry diff --git a/pwnshop/__main__.py b/pwnshop/__main__.py index 0732393..be40b5a 100644 --- a/pwnshop/__main__.py +++ b/pwnshop/__main__.py @@ -231,7 +231,7 @@ def handle_apply(args): shutil.copy2(challenge.src_path, os.path.join(out_dir, os.path.basename(challenge.src_path))) print(f"... copying binary {os.path.basename(challenge.bin_path)} to {out_dir}") shutil.copy2(challenge.bin_path, os.path.join(out_dir, os.path.basename(challenge.bin_path))) - if os.path.exists(challenge.lib_path): + if hasattr(challenge, "lib_path") and os.path.exists(challenge.lib_path): print(f"... copying libraries {os.path.basename(challenge.lib_path)} to {out_dir}") shutil.copytree(challenge.lib_path, os.path.join(out_dir, os.path.basename(challenge.lib_path)), dirs_exist_ok=True) diff --git a/pwnshop/challenge.py b/pwnshop/challenge.py index cb4b6bb..bbf6cf4 100644 --- a/pwnshop/challenge.py +++ b/pwnshop/challenge.py @@ -118,6 +118,8 @@ def verify(self, **kwargs): def run_challenge(self, *, argv=None, close_stdin=False, flag_symlink=None, **kwargs): self.ensure_containers() + assert argv + if flag_symlink: self.run_sh(f"ln -s /flag {flag_symlink}") @@ -278,6 +280,22 @@ def local_context(self): if not e.startswith("_") and e == e.upper() } +class PythonChallenge(TemplatedChallenge, register=False): + @property + def bin_path(self): + return self.src_path + + def build(self): + os.chmod(self.src_path, 0o4755) + + @contextlib.contextmanager + def run_challenge(self, argv=None, **kwargs): + if not self.source: + self.render() + + argv = argv or ["python3", self.src_path] + with super().run_challenge(argv=argv, **kwargs) as y: + yield y class Challenge(TemplatedChallenge, register=False): COMPILER = "gcc" diff --git a/tests/test.sh b/tests/test.sh index 4d91788..4dd18f5 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -17,6 +17,7 @@ cat /tmp/out | grep "SUCCEEDED: ShellOptimized" cat /tmp/out | grep "FAILED: ShellBadVerifier" cat /tmp/out | grep "SUCCEEDED: Shell1604" cat /tmp/out | grep "SUCCEEDED: Shell1604InVitu" +cat /tmp/out | grep "SUCCEEDED: PythonPass" pwnshop apply ../example_deploy/pwnshop.yml SOURCES=( ../example_deploy/*/*/*.c ) @@ -25,7 +26,7 @@ FILES=( ../example_deploy/*/*/* ) LIBS=( ../example_deploy/*/*/lib/* ) [ "${#SOURCES[@]}" -eq 1 ] || exit 1 [ "${#BINS[@]}" -eq 6 ] || exit 1 -[ "${#FILES[@]}" -eq 8 ] || exit 1 +[ "${#FILES[@]}" -eq 10 ] || exit 1 [ "${#LIBS[@]}" -eq 3 ] || exit 1 rm -rf ../example_deploy/*/*/* @@ -36,7 +37,7 @@ FILES=( ../example_deploy/*/*/* ) LIBS=( ../example_deploy/*/*/lib/* ) [ "${#SOURCES[@]}" -eq 1 ] || exit 1 [ "${#BINS[@]}" -eq 6 ] || exit 1 -[ "${#FILES[@]}" -eq 8 ] || exit 1 +[ "${#FILES[@]}" -eq 10 ] || exit 1 [ "${#LIBS[@]}" -eq 3 ] || exit 1 cd /