-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: merge PR #37 from BlockheaderWeb3-Community/security
feat: add vulnerable contracts
- Loading branch information
Showing
5 changed files
with
132 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
target | ||
.snfoundry.toml | ||
.snfoundry.toml | ||
.snfoundry_cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// AttackCounter Contract | ||
// Whereas a function is considered as a read-only function if its self is a snapshot of storage as depicted thus (self: @TContractState), it is not true that such a functin cannot modify state | ||
// By leveraging syscalls like `call_contract_syscall`, such function can modify state | ||
// In this contract, we showcase this possibility of using `call_contract_syscall` in our AttackCounter contract to modify the `count` state of our simple counter contract | ||
|
||
#[starknet::interface] | ||
pub trait IAttackCounter<TContractState> { | ||
// get count - retrieve the count from storage | ||
// a read-only function | ||
fn counter_count(self: @TContractState) -> u32; | ||
|
||
// set count | ||
fn attack_count(self: @TContractState); | ||
} | ||
|
||
|
||
#[starknet::contract] | ||
pub mod AttackCounter { | ||
use crate::counter::{ ICounterDispatcher, ICounterDispatcherTrait}; | ||
use starknet::{ContractAddress, syscalls:: call_contract_syscall}; | ||
#[storage] | ||
struct Storage { | ||
counter_address: ContractAddress | ||
} | ||
|
||
#[constructor] | ||
fn constructor(ref self: ContractState, counter_addr: ContractAddress) { | ||
self.counter_address.write(counter_addr) | ||
} | ||
|
||
#[abi(embed_v0)] | ||
impl CounterImpl of super::IAttackCounter<ContractState> { | ||
fn counter_count(self: @ContractState) -> u32 { | ||
let counter_addr = self.counter_address.read(); | ||
ICounterDispatcher { contract_address: counter_addr }.get_count() | ||
} | ||
|
||
fn attack_count(self: @ContractState) { | ||
let counter_addr = self.counter_address.read(); | ||
let selector = selector!("set_count"); | ||
|
||
let mut args: Array<felt252> = array![]; | ||
let value = 100; | ||
value.serialize(ref args); | ||
call_contract_syscall(counter_addr, selector, args.span()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// VulnerableStake contract | ||
// Both deposit and withdraw functions of this contract contains flawed logic | ||
use starknet::ContractAddress; | ||
#[starknet::interface] | ||
pub trait IVulnerableStake<T> { | ||
fn deposit(ref self: T, amount: u256, stake_addr: ContractAddress); | ||
fn withdraw(ref self: T, amount: u256, reward_addr: ContractAddress); | ||
} | ||
|
||
|
||
#[derive(Debug, Drop, Serde, Copy, starknet::Store)] | ||
pub struct StakerInfo { | ||
pub stake_addr: ContractAddress, | ||
pub reward_amount: u256, | ||
pub stake_amount: u256, | ||
pub unclaimed_rewards_own: u256, | ||
} | ||
|
||
|
||
#[starknet::contract] | ||
mod VulnerableStake { | ||
use starknet::{ContractAddress, get_caller_address}; | ||
use starknet::storage::{StoragePointerWriteAccess, StoragePathEntry, Map}; | ||
use super::{StakerInfo, IVulnerableStake,}; | ||
#[storage] | ||
struct Storage { | ||
staker_info: Map<ContractAddress, StakerInfo>, | ||
} | ||
|
||
#[abi(embed_v0)] | ||
impl StakeImpl of IVulnerableStake<ContractState> { | ||
fn deposit(ref self: ContractState, amount: u256, stake_addr: ContractAddress) { | ||
let staker_info = StakerInfo { | ||
stake_addr, reward_amount: 0, stake_amount: amount, unclaimed_rewards_own: 0 | ||
}; | ||
let caller = get_caller_address(); | ||
self.staker_info.entry(caller).write(staker_info); | ||
} | ||
|
||
|
||
fn withdraw(ref self: ContractState, amount: u256, reward_addr: ContractAddress) {} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// NB | ||
// this is not an ERC-20 token contract as it doesn't implement the ERC-20 standard | ||
// This minimalistic VulnerableToken contract is a token contract whose `mint_token` method lacks the requisite access control to for the execution of critical operations like minting/burning of tokens; in our case here, we are targetting the increase total supply operation of the contract. | ||
// It is being used here to showcase the security vulnerability of exposing critical functions without access control | ||
|
||
#[starknet::interface] | ||
pub trait IVulnerableToken<T> { | ||
fn mint_token(ref self: T); | ||
fn get_token_supply(self: @T) -> u256; | ||
} | ||
|
||
#[starknet::contract] | ||
mod VulnerableToken { | ||
const MINT_AMOUNT: u256 = 1000; | ||
|
||
#[storage] | ||
struct Storage { | ||
total_supply: u256 | ||
} | ||
|
||
|
||
#[abi(embed_v0)] | ||
impl VulnerableTokenImpl of super::IVulnerableToken<ContractState> { | ||
// increase token total supply by MINT_AMOUNT | ||
fn mint_token(ref self: ContractState) { | ||
let current_supply: u256 = self.total_supply.read(); | ||
self.total_supply.write(current_supply + MINT_AMOUNT) | ||
} | ||
|
||
// get total supply of token | ||
fn get_token_supply(self: @ContractState) -> u256 { | ||
self.total_supply.read() | ||
} | ||
} | ||
} | ||
|